blob: d5e0f8c0225a1026bb61445b36c27b9da0ad3a29 [file] [log] [blame]
#!/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 server/cros/dynamic_suite/tools.py."""
import mox
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.dynamic_suite.comparitors import AllInHostList
from autotest_lib.server.cros.dynamic_suite.fakes import FakeHost
from autotest_lib.server.cros.dynamic_suite.host_spec import HostSpec
from autotest_lib.server.cros.dynamic_suite import host_spec
from autotest_lib.server.cros.dynamic_suite import tools
from autotest_lib.server.cros.dynamic_suite.reimager import OsReimager
from autotest_lib.server import frontend
class DynamicSuiteToolsTest(mox.MoxTestBase):
"""Unit tests for dynamic_suite tools module methods.
@var _BOARD: fake board to reimage
"""
_BOARD = 'board'
_DEPENDENCIES = {'test1': ['label1'], 'test2': ['label2']}
_POOL = 'bvt'
def setUp(self):
super(DynamicSuiteToolsTest, self).setUp()
self.afe = self.mox.CreateMock(frontend.AFE)
self.tko = self.mox.CreateMock(frontend.TKO)
self.reimager = OsReimager('', self._BOARD, afe=self.afe, tko=self.tko)
# Having these ordered by complexity is important!
host_spec_list = [HostSpec([self._BOARD, self._POOL])]
for dep_list in self._DEPENDENCIES.itervalues():
host_spec_list.append(
HostSpec([self._BOARD, self._POOL], dep_list))
self.specs = host_spec.order_by_complexity(host_spec_list)
def testInjectVars(self):
"""Should inject dict of varibles into provided strings."""
def find_all_in(d, s):
"""Returns true if all key-value pairs in |d| are printed in |s|."""
for k, v in d.iteritems():
if isinstance(v, str):
if "%s='%s'\n" % (k, v) not in s:
return False
else:
if "%s=%r\n" % (k, v) not in s:
return False
return True
v = {'v1': 'one', 'v2': 'two', 'v3': None, 'v4': False, 'v5': 5}
self.assertTrue(find_all_in(v, tools.inject_vars(v, '')))
self.assertTrue(find_all_in(v, tools.inject_vars(v, 'ctrl')))
def testIncorrectlyLocked(self):
"""Should detect hosts locked by random users."""
host = FakeHost(locked=True, locked_by='some guy')
self.assertTrue(tools.incorrectly_locked(host))
def testNotIncorrectlyLocked(self):
"""Should accept hosts locked by the infrastructure."""
infra_user = 'an infra user'
self.mox.StubOutWithMock(tools, 'infrastructure_user')
tools.infrastructure_user().AndReturn(infra_user)
self.mox.ReplayAll()
host = FakeHost(locked=True, locked_by=infra_user)
self.assertFalse(tools.incorrectly_locked(host))
def testEnsureEnoughHosts(self):
"""At least one living host for each list; enough total."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
host_lists = [[FakeHost('h1')], [FakeHost('h2')], [FakeHost('h3')]]
for hosts in host_lists:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
self.mox.ReplayAll()
hosts_per_spec = dict(zip(self.specs, host_lists))
self.reimager._choose_hosts(hosts_per_spec, len(self.specs))
def testNoticeZeroHosts(self):
"""Should notice zero hosts for some unique spec, but continue."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
host_lists = [[], [FakeHost('h1')], [FakeHost('h2')]]
for hosts in host_lists[1:]:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
# Expect call for the spec with no hosts.
tools.get_random_best_host(
self.reimager._afe, [], True).InAnyOrder('random').AndReturn(None)
# Now, expect an attempt to fill out the list with 'simplest' hosts.
tools.get_random_best_host(
self.reimager._afe, [], True).MultipleTimes().AndReturn(None)
self.mox.ReplayAll()
hosts_per_spec = dict(zip(self.specs, host_lists))
explicit_group = self.reimager._choose_hosts(hosts_per_spec,
len(self.specs))
self.assertTrue(self.specs[0] in explicit_group.unsatisfied_specs,
'%r seems to have been satisfied?' % self.specs[0])
def testTolerateZeroHostsForSpecThatIsASubset(self):
"""Should tolerate zero hosts for some subsumed spec, but continue."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
host_lists = [[FakeHost('h1')], [FakeHost('h2')], []]
for hosts in host_lists[:-1]:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
# Expect call for the spec with no hosts.
tools.get_random_best_host(
self.reimager._afe, [], True).InAnyOrder('random').AndReturn(None)
# Now, expect an attempt to fill out the list with 'simplest' hosts.
tools.get_random_best_host(
self.reimager._afe, [], True).MultipleTimes().AndReturn(None)
self.mox.ReplayAll()
hosts_per_spec = dict(zip(self.specs, host_lists))
explicit_group = self.reimager._choose_hosts(hosts_per_spec,
len(self.specs))
self.assertFalse(
explicit_group.unsatisfied_specs,
'%r should be empty!' % explicit_group.unsatisfied_specs)
def testFailZeroHostsTotal(self):
"""Should fail on zero hosts for all specs."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
tools.get_random_best_host(
self.reimager._afe,
mox.IgnoreArg(),
True).MultipleTimes().AndReturn(None)
self.mox.ReplayAll()
hosts_per_spec = dict([(spec, []) for spec in self.specs])
self.assertRaises(error.NoHostsException,
self.reimager._choose_hosts,
hosts_per_spec, len(self.specs))
def testTolerateTooFewHosts(self):
"""Should tolerate having < num hosts, but one per given specs."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
host_lists = [[FakeHost('h1')], [FakeHost('h2')], [FakeHost('h3')]]
for hosts in host_lists:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
tools.get_random_best_host(self.reimager._afe, [], True).AndReturn(None)
self.mox.ReplayAll()
hosts_per_spec = dict(zip(self.specs, host_lists))
self.reimager._choose_hosts(hosts_per_spec, len(self.specs) + 1)
def testSubsumeTrivialHostSpec(self):
"""Should tolerate num hosts < host specs, if we have a trivial spec."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
num = len(self.specs) - 1
host_lists = [[FakeHost('h1')], [FakeHost('h2')], [FakeHost('h3')]]
hosts_per_spec = dict(zip(self.specs, host_lists))
for spec, hosts in hosts_per_spec.iteritems():
if spec.is_trivial:
continue
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
self.mox.ReplayAll()
hosts = self.reimager._choose_hosts(hosts_per_spec, num)
self.assertEquals(num, hosts.size())
def testNumOneStillGetDownToTrivialHostSpec(self):
"""Still run tests, even if we can only satisfy trivial spec."""
self.mox.StubOutWithMock(tools, 'get_random_best_host')
num = 1
host_lists = [[FakeHost('h1')], [FakeHost('h2')], [FakeHost('h3')]]
hosts_per_spec = dict(zip(self.specs, host_lists))
for spec, hosts in hosts_per_spec.iteritems():
if spec.is_trivial:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
else:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn([])
self.mox.ReplayAll()
hosts = self.reimager._choose_hosts(hosts_per_spec, num)
self.assertEquals(num, hosts.size())
def testRandomBestHostReadyAvailable(self):
"""Should return one of the 'Ready' hosts."""
ready = [FakeHost('h3'), FakeHost('h4')]
hosts = [FakeHost('h1', status='Running'),
FakeHost('h2', locked=True, locked_by='some_guy')]
hosts.extend(ready)
hostnames = [host.hostname for host in hosts]
self.afe.get_hosts(
hostnames=mox.SameElementsAs(hostnames)).AndReturn(hosts)
self.mox.ReplayAll()
self.assertTrue(tools.get_random_best_host(self.reimager._afe,
hosts) in ready)
def testRandomBestHostNoneUsable(self):
"""Should fail on zero usable hosts."""
hosts = [FakeHost(status='Repairing'),
FakeHost(locked=True, locked_by='some_guy')]
hostnames = [host.hostname for host in hosts]
self.afe.get_hosts(
hostnames=mox.SameElementsAs(hostnames)).AndReturn(hosts)
self.mox.ReplayAll()
self.assertEquals(None, tools.get_random_best_host(self.reimager._afe,
hosts))
def testRandomBestHostAllowUnusable(self):
"""Should find zero usable hosts, but use them anyhow."""
hosts = [FakeHost(status='Repairing'),
FakeHost(locked=True, locked_by='some_guy')]
hostnames = [host.hostname for host in hosts]
self.afe.get_hosts(
hostnames=mox.SameElementsAs(hostnames)).AndReturn(hosts)
self.mox.ReplayAll()
self.assertTrue(
tools.get_random_best_host(self.reimager._afe, hosts, False)
in hosts)
def testRandomBestHostRunningAvailable(self):
"""Should return the correctly locked 'Running' host."""
user = 'an infra user'
self.mox.StubOutWithMock(tools, 'infrastructure_user')
tools.infrastructure_user().MultipleTimes().AndReturn(user)
running = FakeHost('h1', status='Running', locked=True, locked_by=user)
hosts = [FakeHost('h2', status='Running', locked=True, locked_by='foo'),
FakeHost('h3', status='Repair Failed')]
hosts.append(running)
hostnames = [host.hostname for host in hosts]
self.afe.get_hosts(
hostnames=mox.SameElementsAs(hostnames)).AndReturn(hosts)
self.mox.ReplayAll()
self.assertEquals(running, tools.get_random_best_host(
self.reimager._afe, hosts))
def testRandomBestHostCleaningAvailable(self):
"""Should return the 'Cleaning' host."""
cleaning = FakeHost('h1', status='Cleaning')
hosts = [FakeHost('h2', status='Ready', locked=True, locked_by='foo'),
FakeHost('h3', status='Repair Failed')]
hosts.append(cleaning)
hostnames = [host.hostname for host in hosts]
self.afe.get_hosts(
hostnames=mox.SameElementsAs(hostnames)).AndReturn(hosts)
self.mox.ReplayAll()
self.assertEquals(cleaning, tools.get_random_best_host(
self.reimager._afe, hosts))
def testChooseHostsFromSpecsAndHosts(self):
"""Should choose N hosts from per-spec host lists."""
expected = [FakeHost('h1'), FakeHost('h3'), FakeHost('h4')]
host_lists = [[FakeHost('h6'), expected[0]],
[FakeHost('h2'), expected[1]],
[expected[0], FakeHost('h2'), expected[2]]]
hosts_per_spec = dict(zip(self.specs, host_lists))
self.mox.StubOutWithMock(tools, 'get_random_best_host')
for hosts in host_lists:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
self.mox.ReplayAll()
to_use = self.reimager._choose_hosts(hosts_per_spec, len(self.specs))
self.assertEquals(to_use.size(), len(self.specs))
for expected_host in expected:
self.assertTrue(to_use.contains_host(expected_host))
def testChooseExtraHostsFromSpecsAndHosts(self):
"""Should choose N hosts from per-spec host lists, plus one extra."""
expected = [FakeHost('h1'), FakeHost('h3'), FakeHost('h4')]
extra_expected = FakeHost('h5')
host_lists = [[FakeHost('h6'), expected[0]],
[FakeHost('h2'), expected[1]],
[extra_expected, FakeHost('h2'), expected[2]]]
hosts_per_spec = dict(zip(self.specs, host_lists))
self.mox.StubOutWithMock(tools, 'get_random_best_host')
for hosts in host_lists:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
# self.specs ordered by complexity, so -1st entry is least complex.
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts_per_spec[self.specs[-1]]),
True).InAnyOrder('random').AndReturn(extra_expected)
self.mox.ReplayAll()
to_use = self.reimager._choose_hosts(hosts_per_spec,
len(self.specs) + 1)
self.assertEquals(to_use.size(), len(self.specs) + 1)
for expected_host in expected:
self.assertTrue(to_use.contains_host(expected_host))
self.assertTrue(to_use.contains_host(extra_expected))
def testChooseHostsFromSpecsAndHostsFallShort(self):
"""Should choose N hosts from per-spec host lists, plus none extra."""
expected = [FakeHost('h1'), FakeHost('h3'), FakeHost('h4')]
host_lists = [[FakeHost('h6'), expected[0]],
[FakeHost('h2'), expected[1]],
[expected[0], FakeHost('h2'), expected[2]]]
hosts_per_spec = dict(zip(self.specs, host_lists))
self.mox.StubOutWithMock(tools, 'get_random_best_host')
for hosts in host_lists:
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts),
True).InAnyOrder('random').AndReturn(hosts[-1])
# self.specs ordered by complexity, so -1st entry is least complex.
tools.get_random_best_host(
self.reimager._afe,
AllInHostList(hosts_per_spec[self.specs[-1]]),
True).InAnyOrder('random').AndReturn(None)
self.mox.ReplayAll()
to_use = self.reimager._choose_hosts(hosts_per_spec,
len(self.specs) + 1)
self.assertEquals(to_use.size(), len(self.specs))
for expected_host in expected:
self.assertTrue(to_use.contains_host(expected_host))
def testChooseHostsFromSpecsAndHostsCannotSatisfy(self):
"""Should try to choose N hosts from per-spec host lists, but fail."""
hosts_per_spec = dict([(spec, []) for spec in self.specs])
self.mox.StubOutWithMock(tools, 'get_random_best_host')
tools.get_random_best_host(
self.reimager._afe,
mox.IgnoreArg(), True).MultipleTimes().AndReturn(None)
self.mox.ReplayAll()
self.assertRaises(error.NoHostsException,
self.reimager._choose_hosts,
hosts_per_spec, len(self.specs))