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