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 9import __builtin__ 10 11import httplib 12import json 13import mox 14import os 15import StringIO 16import time 17import unittest 18import urllib2 19 20import common 21from autotest_lib.client.bin import utils as site_utils 22from autotest_lib.client.common_lib import android_utils 23from autotest_lib.client.common_lib import error 24from autotest_lib.client.common_lib import global_config 25from autotest_lib.client.common_lib import utils 26from autotest_lib.client.common_lib.cros import dev_server 27from autotest_lib.client.common_lib.cros import retry 28 29 30def 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 51class 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 60class 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 67E403 = urllib2.HTTPError(url='', 68 code=httplib.FORBIDDEN, 69 msg='Error 403', 70 hdrs=None, 71 fp=StringIO.StringIO('Expected.')) 72E500 = urllib2.HTTPError(url='', 73 code=httplib.INTERNAL_SERVER_ERROR, 74 msg='Error 500', 75 hdrs=None, 76 fp=StringIO.StringIO('Expected.')) 77CMD_ERROR = error.CmdError('error_cmd', MockSshError().result_obj) 78 79 80class 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 214class 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 1377if __name__ == "__main__": 1378 unittest.main() 1379