1 #!/usr/bin/python 2 # 3 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 7 """Unit tests for client/common_lib/cros/dev_server.py.""" 8 9 import __builtin__ 10 11 import httplib 12 import json 13 import mox 14 import os 15 import StringIO 16 import time 17 import unittest 18 import urllib2 19 20 import mock 21 22 import common 23 from autotest_lib.client.bin import utils as bin_utils 24 from autotest_lib.client.common_lib import android_utils 25 from autotest_lib.client.common_lib import error 26 from autotest_lib.client.common_lib import global_config 27 from autotest_lib.client.common_lib import utils 28 from autotest_lib.client.common_lib.cros import dev_server 29 from autotest_lib.client.common_lib.cros import retry 30 31 32 def retry_mock(ExceptionToCheck, timeout_min, exception_to_raise=None, 33 label=None): 34 """A mock retry decorator to use in place of the actual one for testing. 35 36 @param ExceptionToCheck: the exception to check. 37 @param timeout_mins: Amount of time in mins to wait before timing out. 38 @param exception_to_raise: the exception to raise in retry.retry 39 @param label: used in debug messages 40 41 """ 42 def inner_retry(func): 43 """The actual decorator. 44 45 @param func: Function to be called in decorator. 46 47 """ 48 return func 49 50 return inner_retry 51 52 53 class MockSshResponse(object): 54 """An ssh response mocked for testing.""" 55 56 def __init__(self, output, exit_status=0): 57 self.stdout = output 58 self.exit_status = exit_status 59 self.stderr = 'SSH connection error occurred.' 60 61 62 class MockSshError(error.CmdError): 63 """An ssh error response mocked for testing.""" 64 65 def __init__(self): 66 self.result_obj = MockSshResponse('error', exit_status=255) 67 68 69 E403 = urllib2.HTTPError(url='', 70 code=httplib.FORBIDDEN, 71 msg='Error 403', 72 hdrs=None, 73 fp=StringIO.StringIO('Expected.')) 74 E500 = urllib2.HTTPError(url='', 75 code=httplib.INTERNAL_SERVER_ERROR, 76 msg='Error 500', 77 hdrs=None, 78 fp=StringIO.StringIO('Expected.')) 79 CMD_ERROR = error.CmdError('error_cmd', MockSshError().result_obj) 80 81 82 class RunCallTest(mox.MoxTestBase): 83 """Unit tests for ImageServerBase.run_call or DevServer.run_call.""" 84 85 def setUp(self): 86 """Set up the test""" 87 self.test_call = 'http://nothing/test' 88 self.hostname = 'nothing' 89 self.contents = 'true' 90 self.contents_readline = ['file/one', 'file/two'] 91 self.save_ssh_config = dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER 92 super(RunCallTest, self).setUp() 93 self.mox.StubOutWithMock(urllib2, 'urlopen') 94 self.mox.StubOutWithMock(utils, 'run') 95 96 97 def tearDown(self): 98 """Tear down the test""" 99 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = self.save_ssh_config 100 super(RunCallTest, self).tearDown() 101 102 103 def testRunCallWithSingleCallHTTP(self): 104 """Test dev_server.ImageServerBase.run_call using http with arg: 105 (call).""" 106 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False 107 108 urllib2.urlopen(mox.StrContains(self.test_call)).AndReturn( 109 StringIO.StringIO(self.contents)) 110 self.mox.ReplayAll() 111 response = dev_server.ImageServerBase.run_call(self.test_call) 112 self.assertEquals(self.contents, response) 113 114 115 def testRunCallWithCallAndReadlineHTTP(self): 116 """Test dev_server.ImageServerBase.run_call using http with arg: 117 (call, readline=True).""" 118 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False 119 120 urllib2.urlopen(mox.StrContains(self.test_call)).AndReturn( 121 StringIO.StringIO('\n'.join(self.contents_readline))) 122 self.mox.ReplayAll() 123 response = dev_server.ImageServerBase.run_call( 124 self.test_call, readline=True) 125 self.assertEquals(self.contents_readline, response) 126 127 128 def testRunCallWithCallAndTimeoutHTTP(self): 129 """Test dev_server.ImageServerBase.run_call using http with args: 130 (call, timeout=xxx).""" 131 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False 132 133 urllib2.urlopen(mox.StrContains(self.test_call), data=None).AndReturn( 134 StringIO.StringIO(self.contents)) 135 self.mox.ReplayAll() 136 response = dev_server.ImageServerBase.run_call( 137 self.test_call, timeout=60) 138 self.assertEquals(self.contents, response) 139 140 141 def testRunCallWithSingleCallSSH(self): 142 """Test dev_server.ImageServerBase.run_call using ssh with arg: 143 (call).""" 144 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True 145 self.mox.StubOutWithMock(utils, 'get_restricted_subnet') 146 utils.get_restricted_subnet( 147 self.hostname, utils.RESTRICTED_SUBNETS).AndReturn( 148 self.hostname) 149 150 to_return = MockSshResponse(self.contents) 151 utils.run(mox.StrContains(self.test_call), 152 timeout=mox.IgnoreArg()).AndReturn(to_return) 153 self.mox.ReplayAll() 154 response = dev_server.ImageServerBase.run_call(self.test_call) 155 self.assertEquals(self.contents, response) 156 157 158 def testRunCallWithCallAndReadlineSSH(self): 159 """Test dev_server.ImageServerBase.run_call using ssh with args: 160 (call, readline=True).""" 161 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True 162 self.mox.StubOutWithMock(utils, 'get_restricted_subnet') 163 utils.get_restricted_subnet( 164 self.hostname, utils.RESTRICTED_SUBNETS).AndReturn( 165 self.hostname) 166 167 to_return = MockSshResponse('\n'.join(self.contents_readline)) 168 utils.run(mox.StrContains(self.test_call), 169 timeout=mox.IgnoreArg()).AndReturn(to_return) 170 self.mox.ReplayAll() 171 response = dev_server.ImageServerBase.run_call( 172 self.test_call, readline=True) 173 self.assertEquals(self.contents_readline, response) 174 175 176 def testRunCallWithCallAndTimeoutSSH(self): 177 """Test dev_server.ImageServerBase.run_call using ssh with args: 178 (call, timeout=xxx).""" 179 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True 180 self.mox.StubOutWithMock(utils, 'get_restricted_subnet') 181 utils.get_restricted_subnet( 182 self.hostname, utils.RESTRICTED_SUBNETS).AndReturn( 183 self.hostname) 184 185 to_return = MockSshResponse(self.contents) 186 utils.run(mox.StrContains(self.test_call), 187 timeout=mox.IgnoreArg()).AndReturn(to_return) 188 self.mox.ReplayAll() 189 response = dev_server.ImageServerBase.run_call( 190 self.test_call, timeout=60) 191 self.assertEquals(self.contents, response) 192 193 194 def testRunCallWithExceptionHTTP(self): 195 """Test dev_server.ImageServerBase.run_call using http with raising 196 exception.""" 197 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False 198 urllib2.urlopen(mox.StrContains(self.test_call)).AndRaise(E500) 199 self.mox.ReplayAll() 200 self.assertRaises(urllib2.HTTPError, 201 dev_server.ImageServerBase.run_call, 202 self.test_call) 203 204 205 def testRunCallWithExceptionSSH(self): 206 """Test dev_server.ImageServerBase.run_call using ssh with raising 207 exception.""" 208 dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True 209 self.mox.StubOutWithMock(utils, 'get_restricted_subnet') 210 utils.get_restricted_subnet( 211 self.hostname, utils.RESTRICTED_SUBNETS).AndReturn( 212 self.hostname) 213 214 utils.run(mox.StrContains(self.test_call), 215 timeout=mox.IgnoreArg()).AndRaise(MockSshError()) 216 self.mox.ReplayAll() 217 self.assertRaises(error.CmdError, 218 dev_server.ImageServerBase.run_call, 219 self.test_call) 220 221 222 def testRunCallByDevServerHTTP(self): 223 """Test dev_server.DevServer.run_call, which uses http, and can be 224 directly called by CrashServer.""" 225 urllib2.urlopen( 226 mox.StrContains(self.test_call), data=None).AndReturn( 227 StringIO.StringIO(self.contents)) 228 self.mox.ReplayAll() 229 response = dev_server.DevServer.run_call( 230 self.test_call, timeout=60) 231 self.assertEquals(self.contents, response) 232 233 234 class DevServerTest(mox.MoxTestBase): 235 """Unit tests for dev_server.DevServer. 236 237 @var _HOST: fake dev server host address. 238 """ 239 240 _HOST = 'http://nothing' 241 _CRASH_HOST = 'http://nothing-crashed' 242 _CONFIG = global_config.global_config 243 244 245 def setUp(self): 246 """Set up the test""" 247 super(DevServerTest, self).setUp() 248 self.crash_server = dev_server.CrashServer(DevServerTest._CRASH_HOST) 249 self.dev_server = dev_server.ImageServer(DevServerTest._HOST) 250 self.android_dev_server = dev_server.AndroidBuildServer( 251 DevServerTest._HOST) 252 self.mox.StubOutWithMock(dev_server.ImageServerBase, 'run_call') 253 self.mox.StubOutWithMock(urllib2, 'urlopen') 254 self.mox.StubOutWithMock(utils, 'run') 255 self.mox.StubOutWithMock(os.path, 'exists') 256 # Hide local restricted_subnets setting. 257 dev_server.RESTRICTED_SUBNETS = [] 258 self.mox.StubOutWithMock(dev_server.ImageServer, 259 '_read_json_response_from_devserver') 260 261 sleep = mock.patch('time.sleep', autospec=True) 262 sleep.start() 263 self.addCleanup(sleep.stop) 264 265 266 def testSimpleResolve(self): 267 """One devserver, verify we resolve to it.""" 268 self.mox.StubOutWithMock(dev_server, '_get_dev_server_list') 269 self.mox.StubOutWithMock(dev_server.ImageServer, 'devserver_healthy') 270 dev_server._get_dev_server_list().MultipleTimes().AndReturn( 271 [DevServerTest._HOST]) 272 dev_server.ImageServer.devserver_healthy(DevServerTest._HOST).AndReturn( 273 True) 274 self.mox.ReplayAll() 275 devserver = dev_server.ImageServer.resolve('my_build') 276 self.assertEquals(devserver.url(), DevServerTest._HOST) 277 278 279 def testResolveWithFailure(self): 280 """Ensure we rehash on a failed ping on a bad_host.""" 281 self.mox.StubOutWithMock(dev_server, '_get_dev_server_list') 282 bad_host, good_host = 'http://bad_host:99', 'http://good_host:8080' 283 dev_server._get_dev_server_list().MultipleTimes().AndReturn( 284 [bad_host, good_host]) 285 argument1 = mox.StrContains(bad_host) 286 argument2 = mox.StrContains(good_host) 287 288 # Mock out bad ping failure to bad_host by raising devserver exception. 289 dev_server.ImageServerBase.run_call( 290 argument1, timeout=mox.IgnoreArg()).AndRaise( 291 dev_server.DevServerException()) 292 # Good host is good. 293 dev_server.ImageServerBase.run_call( 294 argument2, timeout=mox.IgnoreArg()).AndReturn( 295 '{"free_disk": 1024}') 296 297 self.mox.ReplayAll() 298 host = dev_server.ImageServer.resolve(0) # Using 0 as it'll hash to 0. 299 self.assertEquals(host.url(), good_host) 300 self.mox.VerifyAll() 301 302 303 def testResolveWithFailureURLError(self): 304 """Ensure we rehash on a failed ping using http on a bad_host after 305 urlerror.""" 306 # Set retry.retry to retry_mock for just returning the original 307 # method for this test. This is to save waiting time for real retry, 308 # which is defined by dev_server.DEVSERVER_SSH_TIMEOUT_MINS. 309 # Will reset retry.retry to real retry at the end of this test. 310 real_retry = retry.retry 311 retry.retry = retry_mock 312 313 self.mox.StubOutWithMock(dev_server, '_get_dev_server_list') 314 bad_host, good_host = 'http://bad_host:99', 'http://good_host:8080' 315 dev_server._get_dev_server_list().MultipleTimes().AndReturn( 316 [bad_host, good_host]) 317 argument1 = mox.StrContains(bad_host) 318 argument2 = mox.StrContains(good_host) 319 320 # Mock out bad ping failure to bad_host by raising devserver exception. 321 dev_server.ImageServerBase.run_call( 322 argument1, timeout=mox.IgnoreArg()).MultipleTimes().AndRaise( 323 urllib2.URLError('urlopen connection timeout')) 324 325 # Good host is good. 326 dev_server.ImageServerBase.run_call( 327 argument2, timeout=mox.IgnoreArg()).AndReturn( 328 '{"free_disk": 1024}') 329 330 self.mox.ReplayAll() 331 host = dev_server.ImageServer.resolve(0) # Using 0 as it'll hash to 0. 332 self.assertEquals(host.url(), good_host) 333 self.mox.VerifyAll() 334 335 retry.retry = real_retry 336 337 338 def testResolveWithManyDevservers(self): 339 """Should be able to return different urls with multiple devservers.""" 340 self.mox.StubOutWithMock(dev_server.ImageServer, 'servers') 341 self.mox.StubOutWithMock(dev_server.DevServer, 'devserver_healthy') 342 343 host0_expected = 'http://host0:8080' 344 host1_expected = 'http://host1:8082' 345 346 dev_server.ImageServer.servers().MultipleTimes().AndReturn( 347 [host0_expected, host1_expected]) 348 dev_server.ImageServer.devserver_healthy(host0_expected).AndReturn(True) 349 dev_server.ImageServer.devserver_healthy(host1_expected).AndReturn(True) 350 351 self.mox.ReplayAll() 352 host0 = dev_server.ImageServer.resolve(0) 353 host1 = dev_server.ImageServer.resolve(1) 354 self.mox.VerifyAll() 355 356 self.assertEqual(host0.url(), host0_expected) 357 self.assertEqual(host1.url(), host1_expected) 358 359 360 def testCmdErrorRetryCollectAULog(self): 361 """Devserver should retry _collect_au_log() on CMDError, 362 but pass through real exception.""" 363 dev_server.ImageServerBase.run_call( 364 mox.IgnoreArg()).AndRaise(CMD_ERROR) 365 dev_server.ImageServerBase.run_call( 366 mox.IgnoreArg()).AndRaise(E500) 367 self.mox.ReplayAll() 368 self.assertFalse(self.dev_server.collect_au_log( 369 '100.0.0.0', 100, 'path/')) 370 371 372 def testURLErrorRetryCollectAULog(self): 373 """Devserver should retry _collect_au_log() on URLError, 374 but pass through real exception.""" 375 self.mox.StubOutWithMock(time, 'sleep') 376 377 refused = urllib2.URLError('[Errno 111] Connection refused') 378 dev_server.ImageServerBase.run_call( 379 mox.IgnoreArg()).AndRaise(refused) 380 time.sleep(mox.IgnoreArg()) 381 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403) 382 self.mox.ReplayAll() 383 self.assertFalse(self.dev_server.collect_au_log( 384 '100.0.0.0', 100, 'path/')) 385 386 387 def testCmdErrorRetryKillAUProcess(self): 388 """Devserver should retry _kill_au_process() on CMDError, 389 but pass through real exception.""" 390 dev_server.ImageServerBase.run_call( 391 mox.IgnoreArg()).AndRaise(CMD_ERROR) 392 dev_server.ImageServerBase.run_call( 393 mox.IgnoreArg()).AndRaise(E500) 394 self.mox.ReplayAll() 395 self.assertFalse(self.dev_server.kill_au_process_for_host( 396 '100.0.0.0', 100)) 397 398 399 def testURLErrorRetryKillAUProcess(self): 400 """Devserver should retry _kill_au_process() on URLError, 401 but pass through real exception.""" 402 self.mox.StubOutWithMock(time, 'sleep') 403 404 refused = urllib2.URLError('[Errno 111] Connection refused') 405 dev_server.ImageServerBase.run_call( 406 mox.IgnoreArg()).AndRaise(refused) 407 time.sleep(mox.IgnoreArg()) 408 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403) 409 self.mox.ReplayAll() 410 self.assertFalse(self.dev_server.kill_au_process_for_host( 411 '100.0.0.0', 100)) 412 413 414 def testCmdErrorRetryCleanTrackLog(self): 415 """Devserver should retry _clean_track_log() on CMDError, 416 but pass through real exception.""" 417 dev_server.ImageServerBase.run_call( 418 mox.IgnoreArg()).AndRaise(CMD_ERROR) 419 dev_server.ImageServerBase.run_call( 420 mox.IgnoreArg()).AndRaise(E500) 421 self.mox.ReplayAll() 422 self.assertFalse(self.dev_server.clean_track_log('100.0.0.0', 100)) 423 424 425 def testURLErrorRetryCleanTrackLog(self): 426 """Devserver should retry _clean_track_log() on URLError, 427 but pass through real exception.""" 428 self.mox.StubOutWithMock(time, 'sleep') 429 430 refused = urllib2.URLError('[Errno 111] Connection refused') 431 dev_server.ImageServerBase.run_call( 432 mox.IgnoreArg()).AndRaise(refused) 433 time.sleep(mox.IgnoreArg()) 434 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403) 435 self.mox.ReplayAll() 436 self.assertFalse(self.dev_server.clean_track_log('100.0.0.0', 100)) 437 438 439 def _mockWriteFile(self): 440 """Mock write content to a file.""" 441 mock_file = self.mox.CreateMockAnything() 442 open(mox.IgnoreArg(), 'w').AndReturn(mock_file) 443 mock_file.__enter__().AndReturn(mock_file) 444 mock_file.write(mox.IgnoreArg()) 445 mock_file.__exit__(None, None, None) 446 447 448 def _preSetupForAutoUpdate(self, **kwargs): 449 """Pre-setup for testing auto_update logics and error handling in 450 devserver.""" 451 response1 = (True, 100) 452 response2 = (True, 'Completed') 453 response3 = {'host_logs': {'a': 'log'}, 'cros_au_log': 'logs'} 454 455 argument1 = mox.And(mox.StrContains(self._HOST), 456 mox.StrContains('cros_au')) 457 argument2 = mox.And(mox.StrContains(self._HOST), 458 mox.StrContains('get_au_status')) 459 argument3 = mox.And(mox.StrContains(self._HOST), 460 mox.StrContains('collect_cros_au_log')) 461 argument4 = mox.And(mox.StrContains(self._HOST), 462 mox.StrContains('handler_cleanup')) 463 argument5 = mox.And(mox.StrContains(self._HOST), 464 mox.StrContains('kill_au_proc')) 465 466 retry_error = None 467 if 'retry_error' in kwargs: 468 retry_error = kwargs['retry_error'] 469 470 raised_error = E403 471 if 'raised_error' in kwargs: 472 raised_error = kwargs['raised_error'] 473 474 if 'cros_au_error' in kwargs: 475 if retry_error: 476 dev_server.ImageServerBase.run_call(argument1).AndRaise( 477 retry_error) 478 time.sleep(mox.IgnoreArg()) 479 480 if kwargs['cros_au_error']: 481 dev_server.ImageServerBase.run_call(argument1).AndRaise( 482 raised_error) 483 else: 484 dev_server.ImageServerBase.run_call(argument1).AndReturn( 485 json.dumps(response1)) 486 487 if 'get_au_status_error' in kwargs: 488 if retry_error: 489 dev_server.ImageServerBase.run_call(argument2).AndRaise( 490 retry_error) 491 time.sleep(mox.IgnoreArg()) 492 493 if kwargs['get_au_status_error']: 494 dev_server.ImageServerBase.run_call(argument2).AndRaise( 495 raised_error) 496 else: 497 dev_server.ImageServerBase.run_call(argument2).AndReturn( 498 json.dumps(response2)) 499 500 if 'collect_au_log_error' in kwargs: 501 if kwargs['collect_au_log_error']: 502 dev_server.ImageServerBase.run_call(argument3).AndRaise( 503 raised_error) 504 else: 505 dev_server.ImageServer._read_json_response_from_devserver( 506 mox.IgnoreArg()).AndReturn(response3) 507 dev_server.ImageServerBase.run_call(argument3).AndReturn('log') 508 os.path.exists(mox.IgnoreArg()).AndReturn(True) 509 510 # We write two log files: host_log and cros_au_log 511 self._mockWriteFile() 512 self._mockWriteFile() 513 514 if 'handler_cleanup_error' in kwargs: 515 if kwargs['handler_cleanup_error']: 516 dev_server.ImageServerBase.run_call(argument4).AndRaise( 517 raised_error) 518 else: 519 dev_server.ImageServerBase.run_call(argument4).AndReturn('True') 520 521 if 'kill_au_proc_error' in kwargs: 522 if kwargs['kill_au_proc_error']: 523 dev_server.ImageServerBase.run_call(argument5).AndRaise( 524 raised_error) 525 else: 526 dev_server.ImageServerBase.run_call(argument5).AndReturn('True') 527 528 529 def testSuccessfulTriggerAutoUpdate(self): 530 """Verify the dev server's auto_update() succeeds.""" 531 kwargs={'cros_au_error': False, 'get_au_status_error': False, 532 'handler_cleanup_error': False} 533 self._preSetupForAutoUpdate(**kwargs) 534 535 self.mox.ReplayAll() 536 self.dev_server.auto_update('100.0.0.0', '') 537 self.mox.VerifyAll() 538 539 540 def testSuccessfulTriggerAutoUpdateWithCollectingLog(self): 541 """Verify the dev server's auto_update() with collecting logs 542 succeeds.""" 543 kwargs={'cros_au_error': False, 'get_au_status_error': False, 544 'handler_cleanup_error': False, 'collect_au_log_error': False} 545 self.mox.StubOutWithMock(__builtin__, 'open') 546 self._preSetupForAutoUpdate(**kwargs) 547 548 self.mox.ReplayAll() 549 self.dev_server.auto_update('100.0.0.0', '', log_dir='path/') 550 self.mox.VerifyAll() 551 552 553 def testCrOSAUURLErrorRetryTriggerAutoUpdateSucceed(self): 554 """Devserver should retry cros_au() on URLError.""" 555 self.mox.StubOutWithMock(time, 'sleep') 556 refused = urllib2.URLError('[Errno 111] Connection refused') 557 kwargs={'retry_error': refused, 'cros_au_error': False, 558 'get_au_status_error': False, 'handler_cleanup_error': False, 559 'collect_au_log_error': False} 560 self.mox.StubOutWithMock(__builtin__, 'open') 561 self._preSetupForAutoUpdate(**kwargs) 562 563 self.mox.ReplayAll() 564 self.dev_server.auto_update('100.0.0.0', '', log_dir='path/') 565 self.mox.VerifyAll() 566 567 568 def testCrOSAUCmdErrorRetryTriggerAutoUpdateSucceed(self): 569 """Devserver should retry cros_au() on CMDError.""" 570 self.mox.StubOutWithMock(time, 'sleep') 571 self.mox.StubOutWithMock(__builtin__, 'open') 572 kwargs={'retry_error': CMD_ERROR, 'cros_au_error': False, 573 'get_au_status_error': False, 'handler_cleanup_error': False, 574 'collect_au_log_error': False} 575 self._preSetupForAutoUpdate(**kwargs) 576 577 self.mox.ReplayAll() 578 self.dev_server.auto_update('100.0.0.0', '', log_dir='path/') 579 self.mox.VerifyAll() 580 581 582 def testCrOSAUURLErrorRetryTriggerAutoUpdateFail(self): 583 """Devserver should retry cros_au() on URLError, but pass through 584 real exception.""" 585 self.mox.StubOutWithMock(time, 'sleep') 586 refused = urllib2.URLError('[Errno 111] Connection refused') 587 kwargs={'retry_error': refused, 'cros_au_error': True, 588 'raised_error': E500} 589 590 for i in range(dev_server.AU_RETRY_LIMIT): 591 self._preSetupForAutoUpdate(**kwargs) 592 if i < dev_server.AU_RETRY_LIMIT - 1: 593 time.sleep(mox.IgnoreArg()) 594 595 self.mox.ReplayAll() 596 self.assertRaises(dev_server.DevServerException, 597 self.dev_server.auto_update, 598 '', '') 599 600 601 def testCrOSAUCmdErrorRetryTriggerAutoUpdateFail(self): 602 """Devserver should retry cros_au() on CMDError, but pass through 603 real exception.""" 604 self.mox.StubOutWithMock(time, 'sleep') 605 kwargs={'retry_error': CMD_ERROR, 'cros_au_error': True} 606 607 for i in range(dev_server.AU_RETRY_LIMIT): 608 self._preSetupForAutoUpdate(**kwargs) 609 if i < dev_server.AU_RETRY_LIMIT - 1: 610 time.sleep(mox.IgnoreArg()) 611 612 self.mox.ReplayAll() 613 self.assertRaises(dev_server.DevServerException, 614 self.dev_server.auto_update, 615 '', '') 616 617 618 def testGetAUStatusErrorInAutoUpdate(self): 619 """Verify devserver's auto_update() logics for handling get_au_status 620 errors. 621 622 Func auto_update() should call 'handler_cleanup' and 'collect_au_log' 623 even if '_trigger_auto_update()' failed. 624 """ 625 self.mox.StubOutWithMock(time, 'sleep') 626 self.mox.StubOutWithMock(__builtin__, 'open') 627 kwargs={'cros_au_error': False, 'get_au_status_error': True, 628 'handler_cleanup_error': False, 'collect_au_log_error': False, 629 'kill_au_proc_error': False} 630 631 for i in range(dev_server.AU_RETRY_LIMIT): 632 self._preSetupForAutoUpdate(**kwargs) 633 if i < dev_server.AU_RETRY_LIMIT - 1: 634 time.sleep(mox.IgnoreArg()) 635 636 self.mox.ReplayAll() 637 self.assertRaises(dev_server.DevServerException, 638 self.dev_server.auto_update, 639 '100.0.0.0', 'build', log_dir='path/') 640 641 642 def testCleanUpErrorInAutoUpdate(self): 643 """Verify devserver's auto_update() logics for handling handler_cleanup 644 errors. 645 646 Func auto_update() should call 'handler_cleanup' and 'collect_au_log' 647 no matter '_trigger_auto_update()' succeeds or fails. 648 """ 649 self.mox.StubOutWithMock(time, 'sleep') 650 self.mox.StubOutWithMock(__builtin__, 'open') 651 kwargs={'cros_au_error': False, 'get_au_status_error': False, 652 'handler_cleanup_error': True, 'collect_au_log_error': False, 653 'kill_au_proc_error': False} 654 655 656 for i in range(dev_server.AU_RETRY_LIMIT): 657 self._preSetupForAutoUpdate(**kwargs) 658 if i < dev_server.AU_RETRY_LIMIT - 1: 659 time.sleep(mox.IgnoreArg()) 660 661 self.mox.ReplayAll() 662 self.assertRaises(dev_server.DevServerException, 663 self.dev_server.auto_update, 664 '100.0.0.0', 'build', log_dir='path/') 665 666 667 def testCollectLogErrorInAutoUpdate(self): 668 """Verify devserver's auto_update() logics for handling collect_au_log 669 errors.""" 670 self.mox.StubOutWithMock(time, 'sleep') 671 kwargs={'cros_au_error': False, 'get_au_status_error': False, 672 'handler_cleanup_error': False, 'collect_au_log_error': True, 673 'kill_au_proc_error': False} 674 675 676 for i in range(dev_server.AU_RETRY_LIMIT): 677 self._preSetupForAutoUpdate(**kwargs) 678 if i < dev_server.AU_RETRY_LIMIT - 1: 679 time.sleep(mox.IgnoreArg()) 680 681 self.mox.ReplayAll() 682 self.assertRaises(dev_server.DevServerException, 683 self.dev_server.auto_update, 684 '100.0.0.0', 'build', log_dir='path/') 685 686 687 def testGetAUStatusErrorAndCleanUpErrorInAutoUpdate(self): 688 """Verify devserver's auto_update() logics for handling get_au_status 689 and handler_cleanup errors. 690 691 Func auto_update() should call 'handler_cleanup' and 'collect_au_log' 692 even if '_trigger_auto_update()' fails. 693 """ 694 self.mox.StubOutWithMock(time, 'sleep') 695 self.mox.StubOutWithMock(__builtin__, 'open') 696 kwargs={'cros_au_error': False, 'get_au_status_error': True, 697 'handler_cleanup_error': True, 'collect_au_log_error': False, 698 'kill_au_proc_error': False} 699 700 701 for i in range(dev_server.AU_RETRY_LIMIT): 702 self._preSetupForAutoUpdate(**kwargs) 703 if i < dev_server.AU_RETRY_LIMIT - 1: 704 time.sleep(mox.IgnoreArg()) 705 706 self.mox.ReplayAll() 707 self.assertRaises(dev_server.DevServerException, 708 self.dev_server.auto_update, 709 '100.0.0.0', 'build', log_dir='path/') 710 711 712 def testGetAUStatusErrorAndCleanUpErrorAndCollectLogErrorInAutoUpdate(self): 713 """Verify devserver's auto_update() logics for handling get_au_status, 714 handler_cleanup, and collect_au_log errors. 715 716 Func auto_update() should call 'handler_cleanup' and 'collect_au_log' 717 even if '_trigger_auto_update()' fails. 718 """ 719 self.mox.StubOutWithMock(time, 'sleep') 720 kwargs={'cros_au_error': False, 'get_au_status_error': True, 721 'handler_cleanup_error': True, 'collect_au_log_error': True, 722 'kill_au_proc_error': False} 723 724 for i in range(dev_server.AU_RETRY_LIMIT): 725 self._preSetupForAutoUpdate(**kwargs) 726 if i < dev_server.AU_RETRY_LIMIT - 1: 727 time.sleep(mox.IgnoreArg()) 728 729 self.mox.ReplayAll() 730 self.assertRaises(dev_server.DevServerException, 731 self.dev_server.auto_update, 732 '100.0.0.0', 'build', log_dir='path/') 733 734 735 def testGetAUStatusErrorAndCleanUpErrorAndCollectLogErrorAndKillErrorInAutoUpdate(self): 736 """Verify devserver's auto_update() logics for handling get_au_status, 737 handler_cleanup, collect_au_log, and kill_au_proc errors. 738 739 Func auto_update() should call 'handler_cleanup' and 'collect_au_log' 740 even if '_trigger_auto_update()' fails. 741 """ 742 self.mox.StubOutWithMock(time, 'sleep') 743 744 kwargs={'cros_au_error': False, 'get_au_status_error': True, 745 'handler_cleanup_error': True, 'collect_au_log_error': True, 746 'kill_au_proc_error': True} 747 748 for i in range(dev_server.AU_RETRY_LIMIT): 749 self._preSetupForAutoUpdate(**kwargs) 750 if i < dev_server.AU_RETRY_LIMIT - 1: 751 time.sleep(mox.IgnoreArg()) 752 753 self.mox.ReplayAll() 754 self.assertRaises(dev_server.DevServerException, 755 self.dev_server.auto_update, 756 '100.0.0.0', 'build', log_dir='path/') 757 758 759 def testSuccessfulTriggerDownloadSync(self): 760 """Call the dev server's download method with synchronous=True.""" 761 name = 'fake/image' 762 self.mox.StubOutWithMock(dev_server.ImageServer, '_finish_download') 763 argument1 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name), 764 mox.StrContains('stage?')) 765 argument2 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name), 766 mox.StrContains('is_staged')) 767 dev_server.ImageServerBase.run_call(argument1).AndReturn('Success') 768 dev_server.ImageServerBase.run_call(argument2).AndReturn('True') 769 self.dev_server._finish_download(name, mox.IgnoreArg(), mox.IgnoreArg()) 770 771 # Synchronous case requires a call to finish download. 772 self.mox.ReplayAll() 773 self.dev_server.trigger_download(name, synchronous=True) 774 self.mox.VerifyAll() 775 776 777 def testSuccessfulTriggerDownloadASync(self): 778 """Call the dev server's download method with synchronous=False.""" 779 name = 'fake/image' 780 argument1 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name), 781 mox.StrContains('stage?')) 782 argument2 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name), 783 mox.StrContains('is_staged')) 784 dev_server.ImageServerBase.run_call(argument1).AndReturn('Success') 785 dev_server.ImageServerBase.run_call(argument2).AndReturn('True') 786 787 self.mox.ReplayAll() 788 self.dev_server.trigger_download(name, synchronous=False) 789 self.mox.VerifyAll() 790 791 792 def testURLErrorRetryTriggerDownload(self): 793 """Should retry on URLError, but pass through real exception.""" 794 self.mox.StubOutWithMock(time, 'sleep') 795 796 refused = urllib2.URLError('[Errno 111] Connection refused') 797 dev_server.ImageServerBase.run_call( 798 mox.IgnoreArg()).AndRaise(refused) 799 time.sleep(mox.IgnoreArg()) 800 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403) 801 self.mox.ReplayAll() 802 self.assertRaises(dev_server.DevServerException, 803 self.dev_server.trigger_download, 804 '') 805 806 807 def testErrorTriggerDownload(self): 808 """Should call the dev server's download method using http, fail 809 gracefully.""" 810 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E500) 811 self.mox.ReplayAll() 812 self.assertRaises(dev_server.DevServerException, 813 self.dev_server.trigger_download, 814 '') 815 816 817 def testForbiddenTriggerDownload(self): 818 """Should call the dev server's download method using http, 819 get exception.""" 820 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403) 821 self.mox.ReplayAll() 822 self.assertRaises(dev_server.DevServerException, 823 self.dev_server.trigger_download, 824 '') 825 826 827 def testCmdErrorTriggerDownload(self): 828 """Should call the dev server's download method using ssh, retry 829 trigger_download when getting error.CmdError, raise exception for 830 urllib2.HTTPError.""" 831 dev_server.ImageServerBase.run_call( 832 mox.IgnoreArg()).AndRaise(CMD_ERROR) 833 dev_server.ImageServerBase.run_call( 834 mox.IgnoreArg()).AndRaise(E500) 835 self.mox.ReplayAll() 836 self.assertRaises(dev_server.DevServerException, 837 self.dev_server.trigger_download, 838 '') 839 840 841 def testSuccessfulFinishDownload(self): 842 """Should successfully call the dev server's finish download method.""" 843 name = 'fake/image' 844 argument1 = mox.And(mox.StrContains(self._HOST), 845 mox.StrContains(name), 846 mox.StrContains('stage?')) 847 argument2 = mox.And(mox.StrContains(self._HOST), 848 mox.StrContains(name), 849 mox.StrContains('is_staged')) 850 dev_server.ImageServerBase.run_call(argument1).AndReturn('Success') 851 dev_server.ImageServerBase.run_call(argument2).AndReturn('True') 852 853 # Synchronous case requires a call to finish download. 854 self.mox.ReplayAll() 855 self.dev_server.finish_download(name) # Raises on failure. 856 self.mox.VerifyAll() 857 858 859 def testErrorFinishDownload(self): 860 """Should call the dev server's finish download method using http, fail 861 gracefully.""" 862 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E500) 863 self.mox.ReplayAll() 864 self.assertRaises(dev_server.DevServerException, 865 self.dev_server.finish_download, 866 '') 867 868 869 def testCmdErrorFinishDownload(self): 870 """Should call the dev server's finish download method using ssh, 871 retry finish_download when getting error.CmdError, raise exception 872 for urllib2.HTTPError.""" 873 dev_server.ImageServerBase.run_call( 874 mox.IgnoreArg()).AndRaise(CMD_ERROR) 875 dev_server.ImageServerBase.run_call( 876 mox.IgnoreArg()).AndRaise(E500) 877 self.mox.ReplayAll() 878 self.assertRaises(dev_server.DevServerException, 879 self.dev_server.finish_download, 880 '') 881 882 883 def testListControlFiles(self): 884 """Should successfully list control files from the dev server.""" 885 name = 'fake/build' 886 control_files = ['file/one', 'file/two'] 887 argument = mox.And(mox.StrContains(self._HOST), 888 mox.StrContains(name)) 889 dev_server.ImageServerBase.run_call( 890 argument, readline=True).AndReturn(control_files) 891 892 self.mox.ReplayAll() 893 paths = self.dev_server.list_control_files(name) 894 self.assertEquals(len(paths), 2) 895 for f in control_files: 896 self.assertTrue(f in paths) 897 898 899 def testFailedListControlFiles(self): 900 """Should call the dev server's list-files method using http, get 901 exception.""" 902 dev_server.ImageServerBase.run_call( 903 mox.IgnoreArg(), readline=True).AndRaise(E500) 904 self.mox.ReplayAll() 905 self.assertRaises(dev_server.DevServerException, 906 self.dev_server.list_control_files, 907 '') 908 909 910 def testExplodingListControlFiles(self): 911 """Should call the dev server's list-files method using http, get 912 exception.""" 913 dev_server.ImageServerBase.run_call( 914 mox.IgnoreArg(), readline=True).AndRaise(E403) 915 self.mox.ReplayAll() 916 self.assertRaises(dev_server.DevServerException, 917 self.dev_server.list_control_files, 918 '') 919 920 921 def testCmdErrorListControlFiles(self): 922 """Should call the dev server's list-files method using ssh, retry 923 list_control_files when getting error.CmdError, raise exception for 924 urllib2.HTTPError.""" 925 dev_server.ImageServerBase.run_call( 926 mox.IgnoreArg(), readline=True).AndRaise(CMD_ERROR) 927 dev_server.ImageServerBase.run_call( 928 mox.IgnoreArg(), readline=True).AndRaise(E500) 929 self.mox.ReplayAll() 930 self.assertRaises(dev_server.DevServerException, 931 self.dev_server.list_control_files, 932 '') 933 934 def testListSuiteControls(self): 935 """Should successfully list all contents of control files from the dev 936 server.""" 937 name = 'fake/build' 938 control_contents = ['control file one', 'control file two'] 939 argument = mox.And(mox.StrContains(self._HOST), 940 mox.StrContains(name)) 941 dev_server.ImageServerBase.run_call( 942 argument).AndReturn(json.dumps(control_contents)) 943 944 self.mox.ReplayAll() 945 file_contents = self.dev_server.list_suite_controls(name) 946 self.assertEquals(len(file_contents), 2) 947 for f in control_contents: 948 self.assertTrue(f in file_contents) 949 950 951 def testFailedListSuiteControls(self): 952 """Should call the dev server's list_suite_controls method using http, 953 get exception.""" 954 dev_server.ImageServerBase.run_call( 955 mox.IgnoreArg()).AndRaise(E500) 956 self.mox.ReplayAll() 957 self.assertRaises(dev_server.DevServerException, 958 self.dev_server.list_suite_controls, 959 '') 960 961 962 def testExplodingListSuiteControls(self): 963 """Should call the dev server's list_suite_controls method using http, 964 get exception.""" 965 dev_server.ImageServerBase.run_call( 966 mox.IgnoreArg()).AndRaise(E403) 967 self.mox.ReplayAll() 968 self.assertRaises(dev_server.DevServerException, 969 self.dev_server.list_suite_controls, 970 '') 971 972 973 def testCmdErrorListSuiteControls(self): 974 """Should call the dev server's list_suite_controls method using ssh, 975 retry list_suite_controls when getting error.CmdError, raise exception 976 for urllib2.HTTPError.""" 977 dev_server.ImageServerBase.run_call( 978 mox.IgnoreArg()).AndRaise(CMD_ERROR) 979 dev_server.ImageServerBase.run_call( 980 mox.IgnoreArg()).AndRaise(E500) 981 self.mox.ReplayAll() 982 self.assertRaises(dev_server.DevServerException, 983 self.dev_server.list_suite_controls, 984 '') 985 986 987 def testGetControlFile(self): 988 """Should successfully get a control file from the dev server.""" 989 name = 'fake/build' 990 file = 'file/one' 991 contents = 'Multi-line\nControl File Contents\n' 992 argument = mox.And(mox.StrContains(self._HOST), 993 mox.StrContains(name), 994 mox.StrContains(file)) 995 dev_server.ImageServerBase.run_call(argument).AndReturn(contents) 996 997 self.mox.ReplayAll() 998 self.assertEquals(self.dev_server.get_control_file(name, file), 999 contents) 1000 1001 1002 def testErrorGetControlFile(self): 1003 """Should try to get the contents of a control file using http, get 1004 exception.""" 1005 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E500) 1006 self.mox.ReplayAll() 1007 self.assertRaises(dev_server.DevServerException, 1008 self.dev_server.get_control_file, 1009 '', '') 1010 1011 1012 def testForbiddenGetControlFile(self): 1013 """Should try to get the contents of a control file using http, get 1014 exception.""" 1015 dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403) 1016 self.mox.ReplayAll() 1017 self.assertRaises(dev_server.DevServerException, 1018 self.dev_server.get_control_file, 1019 '', '') 1020 1021 1022 def testCmdErrorGetControlFile(self): 1023 """Should try to get the contents of a control file using ssh, retry 1024 get_control_file when getting error.CmdError, raise exception for 1025 urllib2.HTTPError.""" 1026 dev_server.ImageServerBase.run_call( 1027 mox.IgnoreArg()).AndRaise(CMD_ERROR) 1028 dev_server.ImageServerBase.run_call( 1029 mox.IgnoreArg()).AndRaise(E500) 1030 self.mox.ReplayAll() 1031 self.assertRaises(dev_server.DevServerException, 1032 self.dev_server.get_control_file, 1033 '', '') 1034 1035 1036 def testGetLatestBuild(self): 1037 """Should successfully return a build for a given target.""" 1038 self.mox.StubOutWithMock(dev_server.ImageServer, 'servers') 1039 self.mox.StubOutWithMock(dev_server.DevServer, 'devserver_healthy') 1040 1041 dev_server.ImageServer.servers().AndReturn([self._HOST]) 1042 dev_server.ImageServer.devserver_healthy(self._HOST).AndReturn(True) 1043 1044 target = 'x86-generic-release' 1045 build_string = 'R18-1586.0.0-a1-b1514' 1046 argument = mox.And(mox.StrContains(self._HOST), 1047 mox.StrContains(target)) 1048 dev_server.ImageServerBase.run_call(argument).AndReturn(build_string) 1049 1050 self.mox.ReplayAll() 1051 build = dev_server.ImageServer.get_latest_build(target) 1052 self.assertEquals(build_string, build) 1053 1054 1055 def testGetLatestBuildWithManyDevservers(self): 1056 """Should successfully return newest build with multiple devservers.""" 1057 self.mox.StubOutWithMock(dev_server.ImageServer, 'servers') 1058 self.mox.StubOutWithMock(dev_server.DevServer, 'devserver_healthy') 1059 1060 host0_expected = 'http://host0:8080' 1061 host1_expected = 'http://host1:8082' 1062 1063 dev_server.ImageServer.servers().MultipleTimes().AndReturn( 1064 [host0_expected, host1_expected]) 1065 1066 dev_server.ImageServer.devserver_healthy(host0_expected).AndReturn(True) 1067 dev_server.ImageServer.devserver_healthy(host1_expected).AndReturn(True) 1068 1069 target = 'x86-generic-release' 1070 build_string1 = 'R9-1586.0.0-a1-b1514' 1071 build_string2 = 'R19-1586.0.0-a1-b3514' 1072 argument1 = mox.And(mox.StrContains(host0_expected), 1073 mox.StrContains(target)) 1074 argument2 = mox.And(mox.StrContains(host1_expected), 1075 mox.StrContains(target)) 1076 dev_server.ImageServerBase.run_call(argument1).AndReturn(build_string1) 1077 dev_server.ImageServerBase.run_call(argument2).AndReturn(build_string2) 1078 1079 self.mox.ReplayAll() 1080 build = dev_server.ImageServer.get_latest_build(target) 1081 self.assertEquals(build_string2, build) 1082 1083 1084 def testCrashesAreSetToTheCrashServer(self): 1085 """Should send symbolicate dump rpc calls to crash_server.""" 1086 self.mox.ReplayAll() 1087 call = self.crash_server.build_call('symbolicate_dump') 1088 self.assertTrue(call.startswith(self._CRASH_HOST)) 1089 1090 1091 def _stageTestHelper(self, artifacts=[], files=[], archive_url=None): 1092 """Helper to test combos of files/artifacts/urls with stage call.""" 1093 expected_archive_url = archive_url 1094 if not archive_url: 1095 expected_archive_url = 'gs://my_default_url' 1096 self.mox.StubOutWithMock(dev_server, '_get_image_storage_server') 1097 dev_server._get_image_storage_server().AndReturn( 1098 'gs://my_default_url') 1099 name = 'fake/image' 1100 else: 1101 # This is embedded in the archive_url. Not needed. 1102 name = '' 1103 1104 argument1 = mox.And(mox.StrContains(expected_archive_url), 1105 mox.StrContains(name), 1106 mox.StrContains('artifacts=%s' % 1107 ','.join(artifacts)), 1108 mox.StrContains('files=%s' % ','.join(files)), 1109 mox.StrContains('stage?')) 1110 argument2 = mox.And(mox.StrContains(expected_archive_url), 1111 mox.StrContains(name), 1112 mox.StrContains('artifacts=%s' % 1113 ','.join(artifacts)), 1114 mox.StrContains('files=%s' % ','.join(files)), 1115 mox.StrContains('is_staged')) 1116 dev_server.ImageServerBase.run_call(argument1).AndReturn('Success') 1117 dev_server.ImageServerBase.run_call(argument2).AndReturn('True') 1118 1119 self.mox.ReplayAll() 1120 self.dev_server.stage_artifacts(name, artifacts, files, archive_url) 1121 self.mox.VerifyAll() 1122 1123 1124 def testStageArtifactsBasic(self): 1125 """Basic functionality to stage artifacts (similar to 1126 trigger_download).""" 1127 self._stageTestHelper(artifacts=['full_payload', 'stateful']) 1128 1129 1130 def testStageArtifactsBasicWithFiles(self): 1131 """Basic functionality to stage artifacts (similar to 1132 trigger_download).""" 1133 self._stageTestHelper(artifacts=['full_payload', 'stateful'], 1134 files=['taco_bell.coupon']) 1135 1136 1137 def testStageArtifactsOnlyFiles(self): 1138 """Test staging of only file artifacts.""" 1139 self._stageTestHelper(files=['tasty_taco_bell.coupon']) 1140 1141 1142 def testStageWithArchiveURL(self): 1143 """Basic functionality to stage artifacts (similar to 1144 trigger_download).""" 1145 self._stageTestHelper(files=['tasty_taco_bell.coupon'], 1146 archive_url='gs://tacos_galore/my/dir') 1147 1148 1149 def testStagedFileUrl(self): 1150 """Sanity tests that the staged file url looks right.""" 1151 devserver_label = 'x86-mario-release/R30-1234.0.0' 1152 url = self.dev_server.get_staged_file_url('stateful.tgz', 1153 devserver_label) 1154 expected_url = '/'.join([self._HOST, 'static', devserver_label, 1155 'stateful.tgz']) 1156 self.assertEquals(url, expected_url) 1157 1158 devserver_label = 'something_crazy/that/you_MIGHT/hate' 1159 url = self.dev_server.get_staged_file_url('chromiumos_image.bin', 1160 devserver_label) 1161 expected_url = '/'.join([self._HOST, 'static', devserver_label, 1162 'chromiumos_image.bin']) 1163 self.assertEquals(url, expected_url) 1164 1165 1166 def _StageTimeoutHelper(self): 1167 """Helper class for testing staging timeout.""" 1168 self.mox.StubOutWithMock(dev_server.ImageServer, 'call_and_wait') 1169 dev_server.ImageServer.call_and_wait( 1170 call_name='stage', 1171 artifacts=mox.IgnoreArg(), 1172 files=mox.IgnoreArg(), 1173 archive_url=mox.IgnoreArg(), 1174 error_message=mox.IgnoreArg()).AndRaise(bin_utils.TimeoutError()) 1175 1176 1177 def test_StageArtifactsTimeout(self): 1178 """Test DevServerException is raised when stage_artifacts timed out.""" 1179 self._StageTimeoutHelper() 1180 self.mox.ReplayAll() 1181 self.assertRaises(dev_server.DevServerException, 1182 self.dev_server.stage_artifacts, 1183 image='fake/image', artifacts=['full_payload']) 1184 self.mox.VerifyAll() 1185 1186 1187 def test_TriggerDownloadTimeout(self): 1188 """Test DevServerException is raised when trigger_download timed out.""" 1189 self._StageTimeoutHelper() 1190 self.mox.ReplayAll() 1191 self.assertRaises(dev_server.DevServerException, 1192 self.dev_server.trigger_download, 1193 image='fake/image') 1194 self.mox.VerifyAll() 1195 1196 1197 def test_FinishDownloadTimeout(self): 1198 """Test DevServerException is raised when finish_download timed out.""" 1199 self._StageTimeoutHelper() 1200 self.mox.ReplayAll() 1201 self.assertRaises(dev_server.DevServerException, 1202 self.dev_server.finish_download, 1203 image='fake/image') 1204 self.mox.VerifyAll() 1205 1206 1207 def test_compare_load(self): 1208 """Test load comparison logic. 1209 """ 1210 load_high_cpu = {'devserver': 'http://devserver_1:8082', 1211 dev_server.DevServer.CPU_LOAD: 100.0, 1212 dev_server.DevServer.NETWORK_IO: 1024*1024*1.0, 1213 dev_server.DevServer.DISK_IO: 1024*1024.0} 1214 load_high_network = {'devserver': 'http://devserver_1:8082', 1215 dev_server.DevServer.CPU_LOAD: 1.0, 1216 dev_server.DevServer.NETWORK_IO: 1024*1024*100.0, 1217 dev_server.DevServer.DISK_IO: 1024*1024*1.0} 1218 load_1 = {'devserver': 'http://devserver_1:8082', 1219 dev_server.DevServer.CPU_LOAD: 1.0, 1220 dev_server.DevServer.NETWORK_IO: 1024*1024*1.0, 1221 dev_server.DevServer.DISK_IO: 1024*1024*2.0} 1222 load_2 = {'devserver': 'http://devserver_1:8082', 1223 dev_server.DevServer.CPU_LOAD: 1.0, 1224 dev_server.DevServer.NETWORK_IO: 1024*1024*1.0, 1225 dev_server.DevServer.DISK_IO: 1024*1024*1.0} 1226 self.assertFalse(dev_server._is_load_healthy(load_high_cpu)) 1227 self.assertFalse(dev_server._is_load_healthy(load_high_network)) 1228 self.assertTrue(dev_server._compare_load(load_1, load_2) > 0) 1229 1230 1231 def _testSuccessfulTriggerDownloadAndroid(self, synchronous=True): 1232 """Call the dev server's download method with given synchronous 1233 setting. 1234 1235 @param synchronous: True to call the download method synchronously. 1236 """ 1237 target = 'test_target' 1238 branch = 'test_branch' 1239 build_id = '123456' 1240 artifacts = android_utils.AndroidArtifacts.get_artifacts_for_reimage( 1241 None) 1242 self.mox.StubOutWithMock(dev_server.AndroidBuildServer, 1243 '_finish_download') 1244 argument1 = mox.And(mox.StrContains(self._HOST), 1245 mox.StrContains(target), 1246 mox.StrContains(branch), 1247 mox.StrContains(build_id), 1248 mox.StrContains('stage?')) 1249 argument2 = mox.And(mox.StrContains(self._HOST), 1250 mox.StrContains(target), 1251 mox.StrContains(branch), 1252 mox.StrContains(build_id), 1253 mox.StrContains('is_staged')) 1254 dev_server.ImageServerBase.run_call(argument1).AndReturn('Success') 1255 dev_server.ImageServerBase.run_call(argument2).AndReturn('True') 1256 1257 if synchronous: 1258 android_build_info = {'target': target, 1259 'build_id': build_id, 1260 'branch': branch} 1261 build = dev_server.ANDROID_BUILD_NAME_PATTERN % android_build_info 1262 self.android_dev_server._finish_download( 1263 build, artifacts, '', target=target, build_id=build_id, 1264 branch=branch) 1265 1266 # Synchronous case requires a call to finish download. 1267 self.mox.ReplayAll() 1268 self.android_dev_server.trigger_download( 1269 synchronous=synchronous, target=target, build_id=build_id, 1270 branch=branch) 1271 self.mox.VerifyAll() 1272 1273 1274 def testSuccessfulTriggerDownloadAndroidSync(self): 1275 """Call the dev server's download method with synchronous=True.""" 1276 self._testSuccessfulTriggerDownloadAndroid(synchronous=True) 1277 1278 1279 def testSuccessfulTriggerDownloadAndroidAsync(self): 1280 """Call the dev server's download method with synchronous=False.""" 1281 self._testSuccessfulTriggerDownloadAndroid(synchronous=False) 1282 1283 1284 def testGetUnrestrictedDevservers(self): 1285 """Test method get_unrestricted_devservers works as expected.""" 1286 restricted_devserver = 'http://192.168.0.100:8080' 1287 unrestricted_devserver = 'http://172.1.1.3:8080' 1288 self.mox.StubOutWithMock(dev_server.ImageServer, 'servers') 1289 dev_server.ImageServer.servers().AndReturn([restricted_devserver, 1290 unrestricted_devserver]) 1291 self.mox.ReplayAll() 1292 self.assertEqual(dev_server.ImageServer.get_unrestricted_devservers( 1293 [('192.168.0.0', 24)]), 1294 [unrestricted_devserver]) 1295 1296 1297 def testDevserverHealthy(self): 1298 """Test which types of connections that method devserver_healthy uses 1299 for different types of DevServer. 1300 1301 CrashServer always adopts DevServer.run_call. 1302 ImageServer and AndroidBuildServer use ImageServerBase.run_call. 1303 """ 1304 argument = mox.StrContains(self._HOST) 1305 1306 # for testing CrashServer 1307 self.mox.StubOutWithMock(dev_server.DevServer, 'run_call') 1308 dev_server.DevServer.run_call( 1309 argument, timeout=mox.IgnoreArg()).AndReturn( 1310 '{"free_disk": 1024}') 1311 # for testing ImageServer 1312 dev_server.ImageServerBase.run_call( 1313 argument, timeout=mox.IgnoreArg()).AndReturn( 1314 '{"free_disk": 1024}') 1315 # for testing AndroidBuildServer 1316 dev_server.ImageServerBase.run_call( 1317 argument, timeout=mox.IgnoreArg()).AndReturn( 1318 '{"free_disk": 1024}') 1319 1320 self.mox.ReplayAll() 1321 self.assertTrue(dev_server.CrashServer.devserver_healthy(self._HOST)) 1322 self.assertTrue(dev_server.ImageServer.devserver_healthy(self._HOST)) 1323 self.assertTrue( 1324 dev_server.AndroidBuildServer.devserver_healthy(self._HOST)) 1325 1326 1327 def testLocateFile(self): 1328 """Test locating files for AndriodBuildServer.""" 1329 file_name = 'fake_file' 1330 artifacts=['full_payload', 'stateful'] 1331 build = 'fake_build' 1332 argument = mox.And(mox.StrContains(file_name), 1333 mox.StrContains(build), 1334 mox.StrContains('locate_file')) 1335 dev_server.ImageServerBase.run_call(argument).AndReturn('file_path') 1336 1337 self.mox.ReplayAll() 1338 file_location = 'http://nothing/static/fake_build/file_path' 1339 self.assertEqual(self.android_dev_server.locate_file( 1340 file_name, artifacts, build, None), file_location) 1341 1342 def testCmdErrorLocateFile(self): 1343 """Test locating files for AndriodBuildServer for retry 1344 error.CmdError, and raise urllib2.URLError.""" 1345 dev_server.ImageServerBase.run_call( 1346 mox.IgnoreArg()).AndRaise(CMD_ERROR) 1347 dev_server.ImageServerBase.run_call( 1348 mox.IgnoreArg()).AndRaise(E500) 1349 self.mox.ReplayAll() 1350 self.assertRaises(dev_server.DevServerException, 1351 self.dev_server.trigger_download, 1352 '') 1353 1354 1355 def testGetAvailableDevserversForCrashServer(self): 1356 """Test method get_available_devservers for CrashServer.""" 1357 crash_servers = ['http://crash_servers1:8080'] 1358 host = '127.0.0.1' 1359 self.mox.StubOutWithMock(dev_server.CrashServer, 'servers') 1360 dev_server.CrashServer.servers().AndReturn(crash_servers) 1361 self.mox.ReplayAll() 1362 self.assertEqual(dev_server.CrashServer.get_available_devservers(host), 1363 (crash_servers, False)) 1364 1365 1366 def testGetAvailableDevserversForImageServer(self): 1367 """Test method get_available_devservers for ImageServer.""" 1368 unrestricted_host = '100.0.0.99' 1369 unrestricted_servers = ['http://100.0.0.10:8080', 1370 'http://128.0.0.10:8080'] 1371 same_subnet_unrestricted_servers = ['http://100.0.0.10:8080'] 1372 restricted_host = '127.0.0.99' 1373 restricted_servers = ['http://127.0.0.10:8080'] 1374 all_servers = unrestricted_servers + restricted_servers 1375 # Set restricted subnets 1376 restricted_subnets = [('127.0.0.0', 24)] 1377 self.mox.StubOutWithMock(dev_server.ImageServerBase, 'servers') 1378 dev_server.ImageServerBase.servers().MultipleTimes().AndReturn( 1379 all_servers) 1380 self.mox.ReplayAll() 1381 # dut in unrestricted subnet shall be offered devserver in the same 1382 # subnet first, and allow retry. 1383 self.assertEqual( 1384 dev_server.ImageServer.get_available_devservers( 1385 unrestricted_host, True, restricted_subnets), 1386 (same_subnet_unrestricted_servers, True)) 1387 1388 # If prefer_local_devserver is set to False, allow any devserver in 1389 # unrestricted subet to be available, and retry is not allowed. 1390 self.assertEqual( 1391 dev_server.ImageServer.get_available_devservers( 1392 unrestricted_host, False, restricted_subnets), 1393 (unrestricted_servers, False)) 1394 1395 # When no hostname is specified, all devservers in unrestricted subnets 1396 # should be considered, and retry is not allowed. 1397 self.assertEqual( 1398 dev_server.ImageServer.get_available_devservers( 1399 None, True, restricted_subnets), 1400 (unrestricted_servers, False)) 1401 1402 # dut in restricted subnet should only be offered devserver in the 1403 # same restricted subnet, and retry is not allowed. 1404 self.assertEqual( 1405 dev_server.ImageServer.get_available_devservers( 1406 restricted_host, True, restricted_subnets), 1407 (restricted_servers, False)) 1408 1409 1410 if __name__ == "__main__": 1411 unittest.main() 1412