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