blob: 3014e8cda4a1b3f6feafb76c32bfb4b6e630556d [file] [log] [blame] [edit]
#!/usr/bin/python
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for client/common_lib/cros/dev_server.py."""
import __builtin__
import httplib
import json
import mox
import StringIO
import time
import unittest
import urllib2
from autotest_lib.client.bin import utils as site_utils
from autotest_lib.client.common_lib import android_utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import global_config
from autotest_lib.client.common_lib import utils
from autotest_lib.client.common_lib.cros import dev_server
from autotest_lib.client.common_lib.cros import retry
def retry_mock(ExceptionToCheck, timeout_min, exception_to_raise=None):
"""A mock retry decorator to use in place of the actual one for testing.
@param ExceptionToCheck: the exception to check.
@param timeout_mins: Amount of time in mins to wait before timing out.
@param exception_to_raise: the exception to raise in retry.retry
"""
def inner_retry(func):
"""The actual decorator.
@param func: Function to be called in decorator.
"""
return func
return inner_retry
class MockSshResponse(object):
"""An ssh response mocked for testing."""
def __init__(self, output, exit_status=0):
self.stdout = output
self.exit_status = exit_status
self.stderr = 'SSH connection error occurred.'
class MockSshError(error.CmdError):
"""An ssh error response mocked for testing."""
def __init__(self):
self.result_obj = MockSshResponse('error', exit_status=255)
E403 = urllib2.HTTPError(url='',
code=httplib.FORBIDDEN,
msg='Error 403',
hdrs=None,
fp=StringIO.StringIO('Expected.'))
E500 = urllib2.HTTPError(url='',
code=httplib.INTERNAL_SERVER_ERROR,
msg='Error 500',
hdrs=None,
fp=StringIO.StringIO('Expected.'))
CMD_ERROR = error.CmdError('error_cmd', MockSshError().result_obj)
class RunCallTest(mox.MoxTestBase):
"""Unit tests for ImageServerBase.run_call or DevServer.run_call."""
def setUp(self):
self.test_call = 'http://nothing/test'
self.contents = 'true'
self.contents_readline = ['file/one', 'file/two']
self.save_ssh_config = dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER
super(RunCallTest, self).setUp()
self.mox.StubOutWithMock(urllib2, 'urlopen')
self.mox.StubOutWithMock(utils, 'run')
def tearDown(self):
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = self.save_ssh_config
super(RunCallTest, self).tearDown()
def testRunCallWithSingleCallHTTP(self):
"""Test dev_server.ImageServerBase.run_call using http with arg:
(call)."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False
urllib2.urlopen(mox.StrContains(self.test_call)).AndReturn(
StringIO.StringIO(self.contents))
self.mox.ReplayAll()
response = dev_server.ImageServerBase.run_call(self.test_call)
self.assertEquals(self.contents, response)
def testRunCallWithCallAndReadlineHTTP(self):
"""Test dev_server.ImageServerBase.run_call using http with arg:
(call, readline=True)."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False
urllib2.urlopen(mox.StrContains(self.test_call)).AndReturn(
StringIO.StringIO('\n'.join(self.contents_readline)))
self.mox.ReplayAll()
response = dev_server.ImageServerBase.run_call(
self.test_call, readline=True)
self.assertEquals(self.contents_readline, response)
def testRunCallWithCallAndTimeoutHTTP(self):
"""Test dev_server.ImageServerBase.run_call using http with args:
(call, timeout=xxx)."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False
urllib2.urlopen(mox.StrContains(self.test_call), data=None).AndReturn(
StringIO.StringIO(self.contents))
self.mox.ReplayAll()
response = dev_server.ImageServerBase.run_call(
self.test_call, timeout=60)
self.assertEquals(self.contents, response)
def testRunCallWithSingleCallSSH(self):
"""Test dev_server.ImageServerBase.run_call using ssh with arg:
(call)."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True
to_return = MockSshResponse(self.contents)
utils.run(mox.StrContains(self.test_call),
timeout=mox.IgnoreArg()).AndReturn(to_return)
self.mox.ReplayAll()
response = dev_server.ImageServerBase.run_call(self.test_call)
self.assertEquals(self.contents, response)
def testRunCallWithCallAndReadlineSSH(self):
"""Test dev_server.ImageServerBase.run_call using ssh with args:
(call, readline=True)."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True
to_return = MockSshResponse('\n'.join(self.contents_readline))
utils.run(mox.StrContains(self.test_call),
timeout=mox.IgnoreArg()).AndReturn(to_return)
self.mox.ReplayAll()
response = dev_server.ImageServerBase.run_call(
self.test_call, readline=True)
self.assertEquals(self.contents_readline, response)
def testRunCallWithCallAndTimeoutSSH(self):
"""Test dev_server.ImageServerBase.run_call using ssh with args:
(call, timeout=xxx)."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True
to_return = MockSshResponse(self.contents)
utils.run(mox.StrContains(self.test_call),
timeout=mox.IgnoreArg()).AndReturn(to_return)
self.mox.ReplayAll()
response = dev_server.ImageServerBase.run_call(
self.test_call, timeout=60)
self.assertEquals(self.contents, response)
def testRunCallWithExceptionHTTP(self):
"""Test dev_server.ImageServerBase.run_call using http with raising
exception."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = False
urllib2.urlopen(mox.StrContains(self.test_call)).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(urllib2.HTTPError,
dev_server.ImageServerBase.run_call,
self.test_call)
def testRunCallWithExceptionSSH(self):
"""Test dev_server.ImageServerBase.run_call using ssh with raising
exception."""
dev_server.ENABLE_SSH_CONNECTION_FOR_DEVSERVER = True
utils.run(mox.StrContains(self.test_call),
timeout=mox.IgnoreArg()).AndRaise(MockSshError())
self.mox.ReplayAll()
self.assertRaises(error.CmdError,
dev_server.ImageServerBase.run_call,
self.test_call)
def testRunCallByDevServerHTTP(self):
"""Test dev_server.DevServer.run_call, which uses http, and can be
directly called by CrashServer."""
urllib2.urlopen(
mox.StrContains(self.test_call), data=None).AndReturn(
StringIO.StringIO(self.contents))
self.mox.ReplayAll()
response = dev_server.DevServer.run_call(
self.test_call, timeout=60)
self.assertEquals(self.contents, response)
class DevServerTest(mox.MoxTestBase):
"""Unit tests for dev_server.DevServer.
@var _HOST: fake dev server host address.
"""
_HOST = 'http://nothing'
_CRASH_HOST = 'http://nothing-crashed'
_CONFIG = global_config.global_config
def setUp(self):
super(DevServerTest, self).setUp()
self.crash_server = dev_server.CrashServer(DevServerTest._CRASH_HOST)
self.dev_server = dev_server.ImageServer(DevServerTest._HOST)
self.android_dev_server = dev_server.AndroidBuildServer(
DevServerTest._HOST)
self.mox.StubOutWithMock(dev_server.ImageServerBase, 'run_call')
self.mox.StubOutWithMock(urllib2, 'urlopen')
self.mox.StubOutWithMock(utils, 'run')
# Hide local restricted_subnets setting.
dev_server.RESTRICTED_SUBNETS = []
def testSimpleResolve(self):
"""One devserver, verify we resolve to it."""
self.mox.StubOutWithMock(dev_server, '_get_dev_server_list')
self.mox.StubOutWithMock(dev_server.ImageServer, 'devserver_healthy')
dev_server._get_dev_server_list().MultipleTimes().AndReturn(
[DevServerTest._HOST])
dev_server.ImageServer.devserver_healthy(DevServerTest._HOST).AndReturn(
True)
self.mox.ReplayAll()
devserver = dev_server.ImageServer.resolve('my_build')
self.assertEquals(devserver.url(), DevServerTest._HOST)
def testResolveWithFailure(self):
"""Ensure we rehash on a failed ping on a bad_host."""
self.mox.StubOutWithMock(dev_server, '_get_dev_server_list')
bad_host, good_host = 'http://bad_host:99', 'http://good_host:8080'
dev_server._get_dev_server_list().MultipleTimes().AndReturn(
[bad_host, good_host])
argument1 = mox.StrContains(bad_host)
argument2 = mox.StrContains(good_host)
# Mock out bad ping failure to bad_host by raising devserver exception.
dev_server.ImageServerBase.run_call(
argument1, timeout=mox.IgnoreArg()).AndRaise(
dev_server.DevServerException())
# Good host is good.
dev_server.ImageServerBase.run_call(
argument2, timeout=mox.IgnoreArg()).AndReturn(
'{"free_disk": 1024}')
self.mox.ReplayAll()
host = dev_server.ImageServer.resolve(0) # Using 0 as it'll hash to 0.
self.assertEquals(host.url(), good_host)
self.mox.VerifyAll()
def testResolveWithFailureURLError(self):
"""Ensure we rehash on a failed ping using http on a bad_host after
urlerror."""
# Retry mock just return the original method.
retry.retry = retry_mock
self.mox.StubOutWithMock(dev_server, '_get_dev_server_list')
bad_host, good_host = 'http://bad_host:99', 'http://good_host:8080'
dev_server._get_dev_server_list().MultipleTimes().AndReturn(
[bad_host, good_host])
argument1 = mox.StrContains(bad_host)
argument2 = mox.StrContains(good_host)
# Mock out bad ping failure to bad_host by raising devserver exception.
dev_server.ImageServerBase.run_call(
argument1, timeout=mox.IgnoreArg()).MultipleTimes().AndRaise(
urllib2.URLError('urlopen connection timeout'))
# Good host is good.
dev_server.ImageServerBase.run_call(
argument2, timeout=mox.IgnoreArg()).AndReturn(
'{"free_disk": 1024}')
self.mox.ReplayAll()
host = dev_server.ImageServer.resolve(0) # Using 0 as it'll hash to 0.
self.assertEquals(host.url(), good_host)
self.mox.VerifyAll()
def testResolveWithManyDevservers(self):
"""Should be able to return different urls with multiple devservers."""
self.mox.StubOutWithMock(dev_server.ImageServer, 'servers')
self.mox.StubOutWithMock(dev_server.DevServer, 'devserver_healthy')
host0_expected = 'http://host0:8080'
host1_expected = 'http://host1:8082'
dev_server.ImageServer.servers().MultipleTimes().AndReturn(
[host0_expected, host1_expected])
dev_server.ImageServer.devserver_healthy(host0_expected).AndReturn(True)
dev_server.ImageServer.devserver_healthy(host1_expected).AndReturn(True)
self.mox.ReplayAll()
host0 = dev_server.ImageServer.resolve(0)
host1 = dev_server.ImageServer.resolve(1)
self.mox.VerifyAll()
self.assertEqual(host0.url(), host0_expected)
self.assertEqual(host1.url(), host1_expected)
def testCmdErrorRetryCollectAULog(self):
"""Devserver should retry _collect_au_log() on CMDError,
but pass through real exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertFalse(self.dev_server.collect_au_log(
'100.0.0.0', 100, 'path/'))
def testURLErrorRetryCollectAULog(self):
"""Devserver should retry _collect_au_log() on URLError,
but pass through real exception."""
self.mox.StubOutWithMock(time, 'sleep')
refused = urllib2.URLError('[Errno 111] Connection refused')
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(refused)
time.sleep(mox.IgnoreArg())
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertFalse(self.dev_server.collect_au_log(
'100.0.0.0', 100, 'path/'))
def testCmdErrorRetryKillAUProcess(self):
"""Devserver should retry _kill_au_process() on CMDError,
but pass through real exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertFalse(self.dev_server.kill_au_process_for_host(
'100.0.0.0'))
def testURLErrorRetryKillAUProcess(self):
"""Devserver should retry _kill_au_process() on URLError,
but pass through real exception."""
self.mox.StubOutWithMock(time, 'sleep')
refused = urllib2.URLError('[Errno 111] Connection refused')
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(refused)
time.sleep(mox.IgnoreArg())
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertFalse(self.dev_server.kill_au_process_for_host('100.0.0.0'))
def testCmdErrorRetryCleanTrackLog(self):
"""Devserver should retry _clean_track_log() on CMDError,
but pass through real exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertFalse(self.dev_server.clean_track_log('100.0.0.0', 100))
def testURLErrorRetryCleanTrackLog(self):
"""Devserver should retry _clean_track_log() on URLError,
but pass through real exception."""
self.mox.StubOutWithMock(time, 'sleep')
refused = urllib2.URLError('[Errno 111] Connection refused')
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(refused)
time.sleep(mox.IgnoreArg())
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertFalse(self.dev_server.clean_track_log('100.0.0.0', 100))
def _mockWriteFile(self):
"""Mock write content to a file."""
mock_file = self.mox.CreateMockAnything()
open(mox.IgnoreArg(), 'w').AndReturn(mock_file)
mock_file.__enter__().AndReturn(mock_file)
mock_file.write(mox.IgnoreArg())
mock_file.__exit__(None, None, None)
def _preSetupForAutoUpdate(self, **kwargs):
"""Pre-setup for testing auto_update logics and error handling in
devserver."""
response1 = (True, 100)
response2 = (True, 'Completed')
argument1 = mox.And(mox.StrContains(self._HOST),
mox.StrContains('cros_au'))
argument2 = mox.And(mox.StrContains(self._HOST),
mox.StrContains('get_au_status'))
argument3 = mox.And(mox.StrContains(self._HOST),
mox.StrContains('handler_cleanup'))
argument4 = mox.And(mox.StrContains(self._HOST),
mox.StrContains('collect_cros_au_log'))
argument5 = mox.And(mox.StrContains(self._HOST),
mox.StrContains('kill_au_proc'))
retry_error = None
if 'retry_error' in kwargs:
retry_error = kwargs['retry_error']
raised_error = E403
if 'raised_error' in kwargs:
raised_error = kwargs['raised_error']
if 'cros_au_error' in kwargs:
if retry_error:
dev_server.ImageServerBase.run_call(argument1).AndRaise(
retry_error)
time.sleep(mox.IgnoreArg())
if kwargs['cros_au_error']:
dev_server.ImageServerBase.run_call(argument1).AndRaise(
raised_error)
else:
dev_server.ImageServerBase.run_call(argument1).AndReturn(
json.dumps(response1))
if 'get_au_status_error' in kwargs:
if retry_error:
dev_server.ImageServerBase.run_call(argument2).AndRaise(
retry_error)
time.sleep(mox.IgnoreArg())
if kwargs['get_au_status_error']:
dev_server.ImageServerBase.run_call(argument2).AndRaise(
raised_error)
else:
dev_server.ImageServerBase.run_call(argument2).AndReturn(
json.dumps(response2))
if 'handler_cleanup_error' in kwargs:
if kwargs['handler_cleanup_error']:
dev_server.ImageServerBase.run_call(argument3).AndRaise(
raised_error)
else:
dev_server.ImageServerBase.run_call(argument3).AndReturn('True')
if 'collect_au_log_error' in kwargs:
if kwargs['collect_au_log_error']:
dev_server.ImageServerBase.run_call(argument4).AndRaise(
raised_error)
else:
dev_server.ImageServerBase.run_call(argument4).AndReturn('log')
self._mockWriteFile()
if 'kill_au_proc_error' in kwargs:
if kwargs['kill_au_proc_error']:
dev_server.ImageServerBase.run_call(argument5).AndRaise(
raised_error)
else:
dev_server.ImageServerBase.run_call(argument5).AndReturn('True')
def testSuccessfulTriggerAutoUpdate(self):
"""Verify the dev server's auto_update() succeeds."""
kwargs={'cros_au_error': False, 'get_au_status_error': False,
'handler_cleanup_error': False}
self._preSetupForAutoUpdate(**kwargs)
self.mox.ReplayAll()
self.dev_server.auto_update('100.0.0.0', '')
self.mox.VerifyAll()
def testSuccessfulTriggerAutoUpdateWithCollectingLog(self):
"""Verify the dev server's auto_update() with collecting logs
succeeds."""
kwargs={'cros_au_error': False, 'get_au_status_error': False,
'handler_cleanup_error': False, 'collect_au_log_error': False}
self.mox.StubOutWithMock(__builtin__, 'open')
self._preSetupForAutoUpdate(**kwargs)
self.mox.ReplayAll()
self.dev_server.auto_update('100.0.0.0', '', log_dir='path/')
self.mox.VerifyAll()
def testCrOSAUURLErrorRetryTriggerAutoUpdateSucceed(self):
"""Devserver should retry cros_au() on URLError."""
self.mox.StubOutWithMock(time, 'sleep')
refused = urllib2.URLError('[Errno 111] Connection refused')
kwargs={'retry_error': refused, 'cros_au_error': False,
'get_au_status_error': False, 'handler_cleanup_error': False,
'collect_au_log_error': False}
self.mox.StubOutWithMock(__builtin__, 'open')
self._preSetupForAutoUpdate(**kwargs)
self.mox.ReplayAll()
self.dev_server.auto_update('100.0.0.0', '', log_dir='path/')
self.mox.VerifyAll()
def testCrOSAUCmdErrorRetryTriggerAutoUpdateSucceed(self):
"""Devserver should retry cros_au() on CMDError."""
self.mox.StubOutWithMock(time, 'sleep')
self.mox.StubOutWithMock(__builtin__, 'open')
kwargs={'retry_error': CMD_ERROR, 'cros_au_error': False,
'get_au_status_error': False, 'handler_cleanup_error': False,
'collect_au_log_error': False}
self._preSetupForAutoUpdate(**kwargs)
self.mox.ReplayAll()
self.dev_server.auto_update('100.0.0.0', '', log_dir='path/')
self.mox.VerifyAll()
def testCrOSAUURLErrorRetryTriggerAutoUpdateFail(self):
"""Devserver should retry cros_au() on URLError, but pass through
real exception."""
self.mox.StubOutWithMock(time, 'sleep')
refused = urllib2.URLError('[Errno 111] Connection refused')
kwargs={'retry_error': refused, 'cros_au_error': True,
'raised_error': E500}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'', '')
def testCrOSAUCmdErrorRetryTriggerAutoUpdateFail(self):
"""Devserver should retry cros_au() on CMDError, but pass through
real exception."""
self.mox.StubOutWithMock(time, 'sleep')
kwargs={'retry_error': CMD_ERROR, 'cros_au_error': True}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'', '')
def testGetAUStatusErrorInAutoUpdate(self):
"""Verify devserver's auto_update() logics for handling get_au_status
errors.
Func auto_update() should call 'handler_cleanup' and 'collect_au_log'
even if '_start_auto_update()' failed.
"""
self.mox.StubOutWithMock(time, 'sleep')
self.mox.StubOutWithMock(__builtin__, 'open')
kwargs={'cros_au_error': False, 'get_au_status_error': True,
'handler_cleanup_error': False, 'collect_au_log_error': False,
'kill_au_proc_error': False}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'100.0.0.0', 'build', 'path/')
def testCleanUpErrorInAutoUpdate(self):
"""Verify devserver's auto_update() logics for handling handler_cleanup
errors.
Func auto_update() should call 'handler_cleanup' and 'collect_au_log'
no matter '_start_auto_update()' succeeds or fails.
"""
self.mox.StubOutWithMock(time, 'sleep')
self.mox.StubOutWithMock(__builtin__, 'open')
kwargs={'cros_au_error': False, 'get_au_status_error': False,
'handler_cleanup_error': True, 'collect_au_log_error': False,
'kill_au_proc_error': False}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'100.0.0.0', 'build', 'path/')
def testCollectLogErrorInAutoUpdate(self):
"""Verify devserver's auto_update() logics for handling collect_au_log
errors."""
self.mox.StubOutWithMock(time, 'sleep')
kwargs={'cros_au_error': False, 'get_au_status_error': False,
'handler_cleanup_error': False, 'collect_au_log_error': True,
'kill_au_proc_error': False}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'100.0.0.0', 'build', 'path/')
def testGetAUStatusErrorAndCleanUpErrorInAutoUpdate(self):
"""Verify devserver's auto_update() logics for handling get_au_status
and handler_cleanup errors.
Func auto_update() should call 'handler_cleanup' and 'collect_au_log'
even if '_start_auto_update()' fails.
"""
self.mox.StubOutWithMock(time, 'sleep')
self.mox.StubOutWithMock(__builtin__, 'open')
kwargs={'cros_au_error': False, 'get_au_status_error': True,
'handler_cleanup_error': True, 'collect_au_log_error': False,
'kill_au_proc_error': False}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'100.0.0.0', 'build', 'path/')
def testGetAUStatusErrorAndCleanUpErrorAndCollectLogErrorInAutoUpdate(self):
"""Verify devserver's auto_update() logics for handling get_au_status,
handler_cleanup, and collect_au_log errors.
Func auto_update() should call 'handler_cleanup' and 'collect_au_log'
even if '_start_auto_update()' fails.
"""
self.mox.StubOutWithMock(time, 'sleep')
kwargs={'cros_au_error': False, 'get_au_status_error': True,
'handler_cleanup_error': True, 'collect_au_log_error': True,
'kill_au_proc_error': False}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'100.0.0.0', 'build', 'path/')
def testGetAUStatusErrorAndCleanUpErrorAndCollectLogErrorAndKillErrorInAutoUpdate(self):
"""Verify devserver's auto_update() logics for handling get_au_status,
handler_cleanup, collect_au_log, and kill_au_proc errors.
Func auto_update() should call 'handler_cleanup' and 'collect_au_log'
even if '_start_auto_update()' fails.
"""
self.mox.StubOutWithMock(time, 'sleep')
kwargs={'cros_au_error': False, 'get_au_status_error': True,
'handler_cleanup_error': True, 'collect_au_log_error': True,
'kill_au_proc_error': True}
for i in range(dev_server.AU_RETRY_LIMIT):
self._preSetupForAutoUpdate(**kwargs)
if i < dev_server.AU_RETRY_LIMIT - 1:
time.sleep(mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.auto_update,
'100.0.0.0', 'build', 'path/')
def testSuccessfulTriggerDownloadSync(self):
"""Call the dev server's download method with synchronous=True."""
name = 'fake/image'
self.mox.StubOutWithMock(dev_server.ImageServer, '_finish_download')
argument1 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name),
mox.StrContains('stage?'))
argument2 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name),
mox.StrContains('is_staged'))
dev_server.ImageServerBase.run_call(argument1).AndReturn('Success')
dev_server.ImageServerBase.run_call(argument2).AndReturn('True')
self.dev_server._finish_download(name, mox.IgnoreArg(), mox.IgnoreArg())
# Synchronous case requires a call to finish download.
self.mox.ReplayAll()
self.dev_server.trigger_download(name, synchronous=True)
self.mox.VerifyAll()
def testSuccessfulTriggerDownloadASync(self):
"""Call the dev server's download method with synchronous=False."""
name = 'fake/image'
argument1 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name),
mox.StrContains('stage?'))
argument2 = mox.And(mox.StrContains(self._HOST), mox.StrContains(name),
mox.StrContains('is_staged'))
dev_server.ImageServerBase.run_call(argument1).AndReturn('Success')
dev_server.ImageServerBase.run_call(argument2).AndReturn('True')
self.mox.ReplayAll()
self.dev_server.trigger_download(name, synchronous=False)
self.mox.VerifyAll()
def testURLErrorRetryTriggerDownload(self):
"""Should retry on URLError, but pass through real exception."""
self.mox.StubOutWithMock(time, 'sleep')
refused = urllib2.URLError('[Errno 111] Connection refused')
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(refused)
time.sleep(mox.IgnoreArg())
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.trigger_download,
'')
def testErrorTriggerDownload(self):
"""Should call the dev server's download method using http, fail
gracefully."""
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.trigger_download,
'')
def testForbiddenTriggerDownload(self):
"""Should call the dev server's download method using http,
get exception."""
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.trigger_download,
'')
def testCmdErrorTriggerDownload(self):
"""Should call the dev server's download method using ssh, retry
trigger_download when getting error.CmdError, raise exception for
urllib2.HTTPError."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.trigger_download,
'')
def testSuccessfulFinishDownload(self):
"""Should successfully call the dev server's finish download method."""
name = 'fake/image'
argument1 = mox.And(mox.StrContains(self._HOST),
mox.StrContains(name),
mox.StrContains('stage?'))
argument2 = mox.And(mox.StrContains(self._HOST),
mox.StrContains(name),
mox.StrContains('is_staged'))
dev_server.ImageServerBase.run_call(argument1).AndReturn('Success')
dev_server.ImageServerBase.run_call(argument2).AndReturn('True')
# Synchronous case requires a call to finish download.
self.mox.ReplayAll()
self.dev_server.finish_download(name) # Raises on failure.
self.mox.VerifyAll()
def testErrorFinishDownload(self):
"""Should call the dev server's finish download method using http, fail
gracefully."""
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.finish_download,
'')
def testCmdErrorFinishDownload(self):
"""Should call the dev server's finish download method using ssh,
retry finish_download when getting error.CmdError, raise exception
for urllib2.HTTPError."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.finish_download,
'')
def testListControlFiles(self):
"""Should successfully list control files from the dev server."""
name = 'fake/build'
control_files = ['file/one', 'file/two']
argument = mox.And(mox.StrContains(self._HOST),
mox.StrContains(name))
dev_server.ImageServerBase.run_call(
argument, readline=True).AndReturn(control_files)
self.mox.ReplayAll()
paths = self.dev_server.list_control_files(name)
self.assertEquals(len(paths), 2)
for f in control_files:
self.assertTrue(f in paths)
def testFailedListControlFiles(self):
"""Should call the dev server's list-files method using http, get
exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg(), readline=True).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.list_control_files,
'')
def testExplodingListControlFiles(self):
"""Should call the dev server's list-files method using http, get
exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg(), readline=True).AndRaise(E403)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.list_control_files,
'')
def testCmdErrorListControlFiles(self):
"""Should call the dev server's list-files method using ssh, retry
list_control_files when getting error.CmdError, raise exception for
urllib2.HTTPError."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg(), readline=True).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg(), readline=True).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.list_control_files,
'')
def testListSuiteControls(self):
"""Should successfully list all contents of control files from the dev
server."""
name = 'fake/build'
control_contents = ['control file one', 'control file two']
argument = mox.And(mox.StrContains(self._HOST),
mox.StrContains(name))
dev_server.ImageServerBase.run_call(
argument).AndReturn(json.dumps(control_contents))
self.mox.ReplayAll()
file_contents = self.dev_server.list_suite_controls(name)
self.assertEquals(len(file_contents), 2)
for f in control_contents:
self.assertTrue(f in file_contents)
def testFailedListSuiteControls(self):
"""Should call the dev server's list_suite_controls method using http,
get exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.list_suite_controls,
'')
def testExplodingListSuiteControls(self):
"""Should call the dev server's list_suite_controls method using http,
get exception."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.list_suite_controls,
'')
def testCmdErrorListSuiteControls(self):
"""Should call the dev server's list_suite_controls method using ssh,
retry list_suite_controls when getting error.CmdError, raise exception
for urllib2.HTTPError."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.list_suite_controls,
'')
def testGetControlFile(self):
"""Should successfully get a control file from the dev server."""
name = 'fake/build'
file = 'file/one'
contents = 'Multi-line\nControl File Contents\n'
argument = mox.And(mox.StrContains(self._HOST),
mox.StrContains(name),
mox.StrContains(file))
dev_server.ImageServerBase.run_call(argument).AndReturn(contents)
self.mox.ReplayAll()
self.assertEquals(self.dev_server.get_control_file(name, file),
contents)
def testErrorGetControlFile(self):
"""Should try to get the contents of a control file using http, get
exception."""
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.get_control_file,
'', '')
def testForbiddenGetControlFile(self):
"""Should try to get the contents of a control file using http, get
exception."""
dev_server.ImageServerBase.run_call(mox.IgnoreArg()).AndRaise(E403)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.get_control_file,
'', '')
def testCmdErrorGetControlFile(self):
"""Should try to get the contents of a control file using ssh, retry
get_control_file when getting error.CmdError, raise exception for
urllib2.HTTPError."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.get_control_file,
'', '')
def testGetLatestBuild(self):
"""Should successfully return a build for a given target."""
self.mox.StubOutWithMock(dev_server.ImageServer, 'servers')
self.mox.StubOutWithMock(dev_server.DevServer, 'devserver_healthy')
dev_server.ImageServer.servers().AndReturn([self._HOST])
dev_server.ImageServer.devserver_healthy(self._HOST).AndReturn(True)
target = 'x86-generic-release'
build_string = 'R18-1586.0.0-a1-b1514'
argument = mox.And(mox.StrContains(self._HOST),
mox.StrContains(target))
dev_server.ImageServerBase.run_call(argument).AndReturn(build_string)
self.mox.ReplayAll()
build = dev_server.ImageServer.get_latest_build(target)
self.assertEquals(build_string, build)
def testGetLatestBuildWithManyDevservers(self):
"""Should successfully return newest build with multiple devservers."""
self.mox.StubOutWithMock(dev_server.ImageServer, 'servers')
self.mox.StubOutWithMock(dev_server.DevServer, 'devserver_healthy')
host0_expected = 'http://host0:8080'
host1_expected = 'http://host1:8082'
dev_server.ImageServer.servers().MultipleTimes().AndReturn(
[host0_expected, host1_expected])
dev_server.ImageServer.devserver_healthy(host0_expected).AndReturn(True)
dev_server.ImageServer.devserver_healthy(host1_expected).AndReturn(True)
target = 'x86-generic-release'
build_string1 = 'R9-1586.0.0-a1-b1514'
build_string2 = 'R19-1586.0.0-a1-b3514'
argument1 = mox.And(mox.StrContains(host0_expected),
mox.StrContains(target))
argument2 = mox.And(mox.StrContains(host1_expected),
mox.StrContains(target))
dev_server.ImageServerBase.run_call(argument1).AndReturn(build_string1)
dev_server.ImageServerBase.run_call(argument2).AndReturn(build_string2)
self.mox.ReplayAll()
build = dev_server.ImageServer.get_latest_build(target)
self.assertEquals(build_string2, build)
def testCrashesAreSetToTheCrashServer(self):
"""Should send symbolicate dump rpc calls to crash_server."""
self.mox.ReplayAll()
call = self.crash_server.build_call('symbolicate_dump')
self.assertTrue(call.startswith(self._CRASH_HOST))
def _stageTestHelper(self, artifacts=[], files=[], archive_url=None):
"""Helper to test combos of files/artifacts/urls with stage call."""
expected_archive_url = archive_url
if not archive_url:
expected_archive_url = 'gs://my_default_url'
self.mox.StubOutWithMock(dev_server, '_get_image_storage_server')
dev_server._get_image_storage_server().AndReturn(
'gs://my_default_url')
name = 'fake/image'
else:
# This is embedded in the archive_url. Not needed.
name = ''
argument1 = mox.And(mox.StrContains(expected_archive_url),
mox.StrContains(name),
mox.StrContains('artifacts=%s' %
','.join(artifacts)),
mox.StrContains('files=%s' % ','.join(files)),
mox.StrContains('stage?'))
argument2 = mox.And(mox.StrContains(expected_archive_url),
mox.StrContains(name),
mox.StrContains('artifacts=%s' %
','.join(artifacts)),
mox.StrContains('files=%s' % ','.join(files)),
mox.StrContains('is_staged'))
dev_server.ImageServerBase.run_call(argument1).AndReturn('Success')
dev_server.ImageServerBase.run_call(argument2).AndReturn('True')
self.mox.ReplayAll()
self.dev_server.stage_artifacts(name, artifacts, files, archive_url)
self.mox.VerifyAll()
def testStageArtifactsBasic(self):
"""Basic functionality to stage artifacts (similar to
trigger_download)."""
self._stageTestHelper(artifacts=['full_payload', 'stateful'])
def testStageArtifactsBasicWithFiles(self):
"""Basic functionality to stage artifacts (similar to
trigger_download)."""
self._stageTestHelper(artifacts=['full_payload', 'stateful'],
files=['taco_bell.coupon'])
def testStageArtifactsOnlyFiles(self):
"""Test staging of only file artifacts."""
self._stageTestHelper(files=['tasty_taco_bell.coupon'])
def testStageWithArchiveURL(self):
"""Basic functionality to stage artifacts (similar to
trigger_download)."""
self._stageTestHelper(files=['tasty_taco_bell.coupon'],
archive_url='gs://tacos_galore/my/dir')
def testStagedFileUrl(self):
"""Sanity tests that the staged file url looks right."""
devserver_label = 'x86-mario-release/R30-1234.0.0'
url = self.dev_server.get_staged_file_url('stateful.tgz',
devserver_label)
expected_url = '/'.join([self._HOST, 'static', devserver_label,
'stateful.tgz'])
self.assertEquals(url, expected_url)
devserver_label = 'something_crazy/that/you_MIGHT/hate'
url = self.dev_server.get_staged_file_url('chromiumos_image.bin',
devserver_label)
expected_url = '/'.join([self._HOST, 'static', devserver_label,
'chromiumos_image.bin'])
self.assertEquals(url, expected_url)
def _StageTimeoutHelper(self):
"""Helper class for testing staging timeout."""
self.mox.StubOutWithMock(dev_server.ImageServer, 'call_and_wait')
dev_server.ImageServer.call_and_wait(
call_name='stage',
artifacts=mox.IgnoreArg(),
files=mox.IgnoreArg(),
archive_url=mox.IgnoreArg(),
error_message=mox.IgnoreArg()).AndRaise(site_utils.TimeoutError())
def test_StageArtifactsTimeout(self):
"""Test DevServerException is raised when stage_artifacts timed out."""
self._StageTimeoutHelper()
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.stage_artifacts,
image='fake/image', artifacts=['full_payload'])
self.mox.VerifyAll()
def test_TriggerDownloadTimeout(self):
"""Test DevServerException is raised when trigger_download timed out."""
self._StageTimeoutHelper()
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.trigger_download,
image='fake/image')
self.mox.VerifyAll()
def test_FinishDownloadTimeout(self):
"""Test DevServerException is raised when finish_download timed out."""
self._StageTimeoutHelper()
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.finish_download,
image='fake/image')
self.mox.VerifyAll()
def test_compare_load(self):
"""Test load comparison logic.
"""
load_high_cpu = {'devserver': 'http://devserver_1:8082',
dev_server.DevServer.CPU_LOAD: 100.0,
dev_server.DevServer.NETWORK_IO: 1024*1024*1.0,
dev_server.DevServer.DISK_IO: 1024*1024.0}
load_high_network = {'devserver': 'http://devserver_1:8082',
dev_server.DevServer.CPU_LOAD: 1.0,
dev_server.DevServer.NETWORK_IO: 1024*1024*100.0,
dev_server.DevServer.DISK_IO: 1024*1024*1.0}
load_1 = {'devserver': 'http://devserver_1:8082',
dev_server.DevServer.CPU_LOAD: 1.0,
dev_server.DevServer.NETWORK_IO: 1024*1024*1.0,
dev_server.DevServer.DISK_IO: 1024*1024*2.0}
load_2 = {'devserver': 'http://devserver_1:8082',
dev_server.DevServer.CPU_LOAD: 1.0,
dev_server.DevServer.NETWORK_IO: 1024*1024*1.0,
dev_server.DevServer.DISK_IO: 1024*1024*1.0}
self.assertFalse(dev_server._is_load_healthy(load_high_cpu))
self.assertFalse(dev_server._is_load_healthy(load_high_network))
self.assertTrue(dev_server._compare_load(load_1, load_2) > 0)
def _testSuccessfulTriggerDownloadAndroid(self, synchronous=True):
"""Call the dev server's download method with given synchronous
setting.
@param synchronous: True to call the download method synchronously.
"""
target = 'test_target'
branch = 'test_branch'
build_id = '123456'
artifacts = android_utils.AndroidArtifacts.get_artifacts_for_reimage(
None)
self.mox.StubOutWithMock(dev_server.AndroidBuildServer,
'_finish_download')
argument1 = mox.And(mox.StrContains(self._HOST),
mox.StrContains(target),
mox.StrContains(branch),
mox.StrContains(build_id),
mox.StrContains('stage?'))
argument2 = mox.And(mox.StrContains(self._HOST),
mox.StrContains(target),
mox.StrContains(branch),
mox.StrContains(build_id),
mox.StrContains('is_staged'))
dev_server.ImageServerBase.run_call(argument1).AndReturn('Success')
dev_server.ImageServerBase.run_call(argument2).AndReturn('True')
if synchronous:
android_build_info = {'target': target,
'build_id': build_id,
'branch': branch}
build = dev_server.ANDROID_BUILD_NAME_PATTERN % android_build_info
self.android_dev_server._finish_download(
build, artifacts, '', target=target, build_id=build_id,
branch=branch)
# Synchronous case requires a call to finish download.
self.mox.ReplayAll()
self.android_dev_server.trigger_download(
synchronous=synchronous, target=target, build_id=build_id,
branch=branch)
self.mox.VerifyAll()
def testSuccessfulTriggerDownloadAndroidSync(self):
"""Call the dev server's download method with synchronous=True."""
self._testSuccessfulTriggerDownloadAndroid(synchronous=True)
def testSuccessfulTriggerDownloadAndroidAsync(self):
"""Call the dev server's download method with synchronous=False."""
self._testSuccessfulTriggerDownloadAndroid(synchronous=False)
def testGetUnrestrictedDevservers(self):
"""Test method get_unrestricted_devservers works as expected."""
restricted_devserver = 'http://192.168.0.100:8080'
unrestricted_devserver = 'http://172.1.1.3:8080'
self.mox.StubOutWithMock(dev_server.ImageServer, 'servers')
dev_server.ImageServer.servers().AndReturn([restricted_devserver,
unrestricted_devserver])
self.mox.ReplayAll()
self.assertEqual(dev_server.ImageServer.get_unrestricted_devservers(
[('192.168.0.0', 24)]),
[unrestricted_devserver])
def testDevserverHealthy(self):
"""Test which types of connections that method devserver_healthy uses
for different types of DevServer.
CrashServer always adopts DevServer.run_call.
ImageServer and AndroidBuildServer use ImageServerBase.run_call.
"""
argument = mox.StrContains(self._HOST)
# for testing CrashServer
self.mox.StubOutWithMock(dev_server.DevServer, 'run_call')
dev_server.DevServer.run_call(
argument, timeout=mox.IgnoreArg()).AndReturn(
'{"free_disk": 1024}')
# for testing ImageServer
dev_server.ImageServerBase.run_call(
argument, timeout=mox.IgnoreArg()).AndReturn(
'{"free_disk": 1024}')
# for testing AndroidBuildServer
dev_server.ImageServerBase.run_call(
argument, timeout=mox.IgnoreArg()).AndReturn(
'{"free_disk": 1024}')
self.mox.ReplayAll()
self.assertTrue(dev_server.CrashServer.devserver_healthy(self._HOST))
self.assertTrue(dev_server.ImageServer.devserver_healthy(self._HOST))
self.assertTrue(
dev_server.AndroidBuildServer.devserver_healthy(self._HOST))
def testLocateFile(self):
"""Test locating files for AndriodBuildServer."""
file_name = 'fake_file'
artifacts=['full_payload', 'stateful']
build = 'fake_build'
argument = mox.And(mox.StrContains(file_name),
mox.StrContains(build),
mox.StrContains('locate_file'))
dev_server.ImageServerBase.run_call(argument).AndReturn('file_path')
self.mox.ReplayAll()
file_location = 'http://nothing/static/fake_build/file_path'
self.assertEqual(self.android_dev_server.locate_file(
file_name, artifacts, build, None), file_location)
def testCmdErrorLocateFile(self):
"""Test locating files for AndriodBuildServer for retry
error.CmdError, and raise urllib2.URLError."""
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(CMD_ERROR)
dev_server.ImageServerBase.run_call(
mox.IgnoreArg()).AndRaise(E500)
self.mox.ReplayAll()
self.assertRaises(dev_server.DevServerException,
self.dev_server.trigger_download,
'')
def testGetAvailableDevserversForCrashServer(self):
"""Test method get_available_devservers for CrashServer."""
crash_servers = ['http://crash_servers1:8080']
host = '127.0.0.1'
self.mox.StubOutWithMock(dev_server.CrashServer, 'servers')
dev_server.CrashServer.servers().AndReturn(crash_servers)
self.mox.ReplayAll()
self.assertEqual(dev_server.CrashServer.get_available_devservers(host),
(crash_servers, False))
def testGetAvailableDevserversForImageServer(self):
"""Test method get_available_devservers for ImageServer."""
unrestricted_host = '100.0.0.99'
unrestricted_servers = ['http://100.0.0.10:8080',
'http://128.0.0.10:8080']
same_subnet_unrestricted_servers = ['http://100.0.0.10:8080']
restricted_host = '127.0.0.99'
restricted_servers = ['http://127.0.0.10:8080']
all_servers = unrestricted_servers + restricted_servers
# Set restricted subnets
restricted_subnets = [('127.0.0.0', 24)]
self.mox.StubOutWithMock(dev_server.ImageServerBase, 'servers')
dev_server.ImageServerBase.servers().MultipleTimes().AndReturn(
all_servers)
self.mox.ReplayAll()
# dut in unrestricted subnet shall be offered devserver in the same
# subnet first, and allow retry.
self.assertEqual(
dev_server.ImageServer.get_available_devservers(
unrestricted_host, True, restricted_subnets),
(same_subnet_unrestricted_servers, True))
# If prefer_local_devserver is set to False, allow any devserver in
# unrestricted subet to be available, and retry is not allowed.
self.assertEqual(
dev_server.ImageServer.get_available_devservers(
unrestricted_host, False, restricted_subnets),
(unrestricted_servers, False))
# When no hostname is specified, all devservers in unrestricted subnets
# should be considered, and retry is not allowed.
self.assertEqual(
dev_server.ImageServer.get_available_devservers(
None, True, restricted_subnets),
(unrestricted_servers, False))
# dut in restricted subnet should only be offered devserver in the
# same restricted subnet, and retry is not allowed.
self.assertEqual(
dev_server.ImageServer.get_available_devservers(
restricted_host, True, restricted_subnets),
(restricted_servers, False))
if __name__ == "__main__":
unittest.main()