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