xref: /aosp_15_r20/external/autotest/server/cros/dynamic_suite/host_spec_unittest.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1#!/usr/bin/python3
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 server/cros/dynamic_suite/host_spec.py."""
8
9import unittest
10
11import common
12
13from autotest_lib.server.cros.dynamic_suite import host_spec
14from autotest_lib.server.cros.dynamic_suite.fakes import FakeHost
15
16
17class HostSpecTest(unittest.TestCase):
18    """Unit tests for dynamic_suite.host_spec module.
19
20    @var _BOARD: fake board to reimage
21    """
22
23
24    _BOARD = 'board'
25    _SPECS = [host_spec.HostSpec([_BOARD]),
26              host_spec.HostSpec([_BOARD, 'pool:bvt']),
27              host_spec.HostSpec([_BOARD], ['label1'])]
28
29
30    def testOrderSpecsByComplexity(self):
31        """Should return new host spec list with simpler entries later."""
32        reordered = host_spec.order_by_complexity(self._SPECS)
33
34        for spec in self._SPECS[1:]:
35            self.assertTrue(spec in reordered[:-1])
36        self.assertEquals(self._SPECS[0], reordered[-1])
37
38
39    def testSpecSubsets(self):
40        """Validate HostSpec subset checks."""
41        self.assertTrue(self._SPECS[0].is_subset(self._SPECS[1]))
42        self.assertTrue(self._SPECS[0].is_subset(self._SPECS[2]))
43        self.assertFalse(self._SPECS[1].is_subset(self._SPECS[2]))
44        self.assertFalse(self._SPECS[2].is_subset(self._SPECS[1]))
45        self.assertFalse(self._SPECS[1].is_subset(self._SPECS[0]))
46        self.assertFalse(self._SPECS[2].is_subset(self._SPECS[0]))
47
48
49    def testTrivialSpec(self):
50        """Validate that HostSpecs are correctly marked as trivial."""
51        self.assertTrue(self._SPECS[0].is_trivial)
52        self.assertTrue(self._SPECS[1].is_trivial)
53        self.assertFalse(self._SPECS[2].is_trivial)
54
55
56class HostGroupTest(unittest.TestCase):
57    """Unit tests for dynamic_suite.host_spec.HostGroup derived classes.
58    """
59
60
61    def testCanConstructExplicit(self):
62        """Should be able to make an ExplicitHostGroup."""
63        host_list = [FakeHost('h1'), FakeHost('h2'), FakeHost('h3')]
64        hosts_per_spec = {host_spec.HostSpec(['l1']): host_list[:1],
65                          host_spec.HostSpec(['l2']): host_list[1:]}
66        group = host_spec.ExplicitHostGroup(hosts_per_spec)
67        for host in host_list:
68            self.assertTrue(host.hostname in group.as_args()['hosts'])
69
70
71    def testExplicitEnforcesHostUniqueness(self):
72        """Should fail to make ExplicitHostGroup with duplicate hosts."""
73        host_list = [FakeHost('h1'), FakeHost('h2'), FakeHost('h3')]
74        hosts_per_spec = {host_spec.HostSpec(['l1']): host_list[:1],
75                          host_spec.HostSpec(['l2']): host_list}
76        self.assertRaises(ValueError,
77                          host_spec.ExplicitHostGroup, hosts_per_spec)
78
79
80    def testCanConstructByMetahostsWithDependencies(self):
81        """Should be able to make a HostGroup from labels."""
82        labels = ['meta_host', 'dep1', 'dep2']
83        num = 3
84        group = host_spec.MetaHostGroup(labels, num)
85        args = group.as_args()
86        self.assertEquals(labels[:1] * num, args['meta_hosts'])
87        self.assertEquals(labels[1:], args['dependencies'])
88
89
90    def testExplicitCanTrackSuccess(self):
91        """Track success/failure in an ExplicitHostGroup."""
92        host_list = [FakeHost('h1'), FakeHost('h2'), FakeHost('h3')]
93        specs = [host_spec.HostSpec(['l1']), host_spec.HostSpec(['l2'])]
94        hosts_per_spec = {specs[0]: host_list[:1], specs[1]: host_list[1:]}
95        group = host_spec.ExplicitHostGroup(hosts_per_spec)
96
97        # Reimage just the one host that satisfies specs[0].
98        group.mark_host_success(host_list[0].hostname)
99        self.assertTrue(group.enough_hosts_succeeded())
100        self.assertTrue(specs[1] in group.doomed_specs)
101
102        # Reimage some host that satisfies specs[1].
103        group.mark_host_success(host_list[2].hostname)
104        self.assertTrue(group.enough_hosts_succeeded())
105        self.assertFalse(group.doomed_specs)
106
107
108    def testExplicitCanTrackSuccessWithSupersets(self):
109        """Track success/failure in an ExplicitHostGroup with supersets."""
110        host_list = [FakeHost('h1'), FakeHost('h2'), FakeHost('h3')]
111        specs = [host_spec.HostSpec(['l1']),
112                 host_spec.HostSpec(['l2']),
113                 host_spec.HostSpec(['l2', 'l1'])]
114        hosts_per_spec = {specs[0]: host_list[:1],
115                          specs[1]: host_list[1:2],
116                          specs[2]: host_list[2:]}
117        group = host_spec.ExplicitHostGroup(hosts_per_spec)
118
119        # Reimage just the one host that satisfies specs[2].
120        # Because satisfying specs[2] statisfies all the specs, we should have
121        # no doomed specs.
122        group.mark_host_success(host_list[2].hostname)
123        self.assertTrue(group.enough_hosts_succeeded())
124        self.assertFalse(group.doomed_specs)
125
126
127    def testExplicitCanTrackUnsatisfiedSpecs(self):
128        """Track unsatisfiable HostSpecs in ExplicitHostGroup."""
129        group = host_spec.ExplicitHostGroup()
130        satisfiable_spec = host_spec.HostSpec(['l2'])
131        unsatisfiable_spec = host_spec.HostSpec(['l1'], ['e1'])
132        group.add_host_for_spec(unsatisfiable_spec, None)
133        group.add_host_for_spec(satisfiable_spec, FakeHost('h1'))
134        self.assertTrue(unsatisfiable_spec in group.unsatisfied_specs)
135        self.assertTrue(satisfiable_spec not in group.unsatisfied_specs)
136
137
138    def testExplicitOneHostEnoughToSatisfySpecs(self):
139        """One host is enough to satisfy a HostSpec in ExplicitHostGroup."""
140        satisfiable_spec = host_spec.HostSpec(['l1'])
141        group = host_spec.ExplicitHostGroup()
142        group.add_host_for_spec(satisfiable_spec, FakeHost('h1'))
143        group.add_host_for_spec(satisfiable_spec, None)
144        self.assertTrue(satisfiable_spec not in group.unsatisfied_specs)
145
146        group = host_spec.ExplicitHostGroup()
147        group.add_host_for_spec(satisfiable_spec, None)
148        group.add_host_for_spec(satisfiable_spec, FakeHost('h1'))
149        self.assertTrue(satisfiable_spec not in group.unsatisfied_specs)
150
151
152    def testExplicitSubsetSpecSatisfiedIfAnyAre(self):
153        """Ensures that any satisfied spec also satisfies a subset HostSpec."""
154        specs = [host_spec.HostSpec(['l1'], ['l3']),
155                 host_spec.HostSpec(['l1'], ['l3', 'l4']),
156                 host_spec.HostSpec(['l1'], ['l5', 'l4']),
157                 host_spec.HostSpec(['l1'], ['l2', 'l3', 'l4'])]
158        group = host_spec.ExplicitHostGroup()
159        group.add_host_for_spec(specs[0], None)
160        group.add_host_for_spec(specs[1], FakeHost('h1'))
161        group.add_host_for_spec(specs[2], FakeHost('h2'))
162        group.add_host_for_spec(specs[3], None)
163
164        self.assertTrue(specs[0] not in group.unsatisfied_specs)
165        self.assertTrue(specs[1] not in group.unsatisfied_specs)
166        self.assertTrue(specs[2] not in group.unsatisfied_specs)
167        self.assertTrue(specs[3] in group.unsatisfied_specs)
168
169
170    def testMetaCanTrackSuccess(self):
171        """Track success/failure in a MetaHostGroup."""
172        labels = ['meta_host', 'dep1', 'dep2']
173        num = 3
174        group = host_spec.MetaHostGroup(labels, num)
175
176        self.assertFalse(group.enough_hosts_succeeded())
177
178        group.mark_host_success('h1')
179        self.assertTrue(group.enough_hosts_succeeded())
180
181
182if __name__ == '__main__':
183    unittest.main()
184