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