xref: /aosp_15_r20/external/autotest/server/cros/provisioner_unittest.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li#!/usr/bin/python3
2*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Liimport unittest
7*9c5db199SXin Lifrom unittest import mock
8*9c5db199SXin Li
9*9c5db199SXin Liimport common
10*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import kernel_utils
11*9c5db199SXin Lifrom autotest_lib.server.cros import provisioner
12*9c5db199SXin Li
13*9c5db199SXin Li
14*9c5db199SXin Liclass _StubUpdateError(provisioner._AttributedUpdateError):
15*9c5db199SXin Li    STUB_MESSAGE = 'Stub message'
16*9c5db199SXin Li    STUB_PATTERN = 'Stub pattern matched'
17*9c5db199SXin Li    _SUMMARY = 'Stub summary'
18*9c5db199SXin Li    _CLASSIFIERS = [
19*9c5db199SXin Li            (STUB_MESSAGE, STUB_MESSAGE),
20*9c5db199SXin Li            ('Stub .*', STUB_PATTERN),
21*9c5db199SXin Li    ]
22*9c5db199SXin Li
23*9c5db199SXin Li    def __init__(self, info, msg):
24*9c5db199SXin Li        super(_StubUpdateError, self).__init__('Stub %s' % info, msg)
25*9c5db199SXin Li
26*9c5db199SXin Li
27*9c5db199SXin Liclass TestErrorClassifications(unittest.TestCase):
28*9c5db199SXin Li    """Test error message handling in `_AttributedUpdateError`."""
29*9c5db199SXin Li
30*9c5db199SXin Li    def test_exception_message(self):
31*9c5db199SXin Li        """Test that the exception string includes its arguments."""
32*9c5db199SXin Li        info = 'info marker'
33*9c5db199SXin Li        msg = 'an error message'
34*9c5db199SXin Li        stub = _StubUpdateError(info, msg)
35*9c5db199SXin Li        self.assertIn(info, str(stub))
36*9c5db199SXin Li        self.assertIn(msg, str(stub))
37*9c5db199SXin Li
38*9c5db199SXin Li    def test_classifier_message(self):
39*9c5db199SXin Li        """Test that the exception classifier can match a simple string."""
40*9c5db199SXin Li        info = 'info marker'
41*9c5db199SXin Li        stub = _StubUpdateError(info, _StubUpdateError.STUB_MESSAGE)
42*9c5db199SXin Li        self.assertNotIn(info, stub.failure_summary)
43*9c5db199SXin Li        self.assertIn(_StubUpdateError._SUMMARY, stub.failure_summary)
44*9c5db199SXin Li        self.assertIn(_StubUpdateError.STUB_MESSAGE, stub.failure_summary)
45*9c5db199SXin Li
46*9c5db199SXin Li    def test_classifier_pattern(self):
47*9c5db199SXin Li        """Test that the exception classifier can match a regex."""
48*9c5db199SXin Li        info = 'info marker'
49*9c5db199SXin Li        stub = _StubUpdateError(info, 'Stub this is a test')
50*9c5db199SXin Li        self.assertNotIn(info, stub.failure_summary)
51*9c5db199SXin Li        self.assertIn(_StubUpdateError._SUMMARY, stub.failure_summary)
52*9c5db199SXin Li        self.assertIn(_StubUpdateError.STUB_PATTERN, stub.failure_summary)
53*9c5db199SXin Li
54*9c5db199SXin Li    def test_classifier_unmatched(self):
55*9c5db199SXin Li        """Test exception summary when no classifier matches."""
56*9c5db199SXin Li        info = 'info marker'
57*9c5db199SXin Li        stub = _StubUpdateError(info, 'This matches no pattern')
58*9c5db199SXin Li        self.assertNotIn(info, stub.failure_summary)
59*9c5db199SXin Li        self.assertIn(_StubUpdateError._SUMMARY, stub.failure_summary)
60*9c5db199SXin Li
61*9c5db199SXin Li    def test_host_update_error(self):
62*9c5db199SXin Li        """Test the `HostUpdateError` classifier."""
63*9c5db199SXin Li        exception = provisioner.HostUpdateError('chromeos6-row3-rack3-host19',
64*9c5db199SXin Li                                                'Fake message')
65*9c5db199SXin Li        self.assertTrue(isinstance(exception.failure_summary, str))
66*9c5db199SXin Li
67*9c5db199SXin Li    def test_image_install_error(self):
68*9c5db199SXin Li        """Test the `ImageInstallError` classifier."""
69*9c5db199SXin Li        exception = provisioner.ImageInstallError(
70*9c5db199SXin Li                'chromeos6-row3-rack3-host19', 'chromeos4-devserver7.cros',
71*9c5db199SXin Li                'Fake message')
72*9c5db199SXin Li        self.assertTrue(isinstance(exception.failure_summary, str))
73*9c5db199SXin Li
74*9c5db199SXin Li    def test_new_build_update_error(self):
75*9c5db199SXin Li        """Test the `NewBuildUpdateError` classifier."""
76*9c5db199SXin Li        exception = provisioner.NewBuildUpdateError('R68-10621.0.0',
77*9c5db199SXin Li                                                    'Fake message')
78*9c5db199SXin Li        self.assertTrue(isinstance(exception.failure_summary, str))
79*9c5db199SXin Li
80*9c5db199SXin Li
81*9c5db199SXin Liclass TestProvisioner(unittest.TestCase):
82*9c5db199SXin Li    """Test provisioner module."""
83*9c5db199SXin Li
84*9c5db199SXin Li    def testParseBuildFromUpdateUrlwithUpdate(self):
85*9c5db199SXin Li        """Test that we properly parse the build from an update_url."""
86*9c5db199SXin Li        update_url = ('http://172.22.50.205:8082/update/lumpy-release/'
87*9c5db199SXin Li                      'R27-3837.0.0')
88*9c5db199SXin Li        expected_value = 'lumpy-release/R27-3837.0.0'
89*9c5db199SXin Li        self.assertEqual(provisioner.url_to_image_name(update_url),
90*9c5db199SXin Li                         expected_value)
91*9c5db199SXin Li
92*9c5db199SXin Li    def testGetRemoteScript(self):
93*9c5db199SXin Li        """Test _get_remote_script() behaviors."""
94*9c5db199SXin Li        update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/'
95*9c5db199SXin Li                      'R28-4444.0.0-b2996')
96*9c5db199SXin Li        script_name = 'fubar'
97*9c5db199SXin Li        local_script = '/usr/local/bin/%s' % script_name
98*9c5db199SXin Li
99*9c5db199SXin Li        host = mock.MagicMock()
100*9c5db199SXin Li        cros_provisioner = provisioner.ChromiumOSProvisioner(update_url,
101*9c5db199SXin Li                                                             host=host)
102*9c5db199SXin Li        host.path_exists.return_value = True
103*9c5db199SXin Li
104*9c5db199SXin Li        # Simple case:  file exists on DUT
105*9c5db199SXin Li        self.assertEqual(cros_provisioner._get_remote_script(script_name),
106*9c5db199SXin Li                         local_script)
107*9c5db199SXin Li        host.path_exists.assert_called_with(local_script)
108*9c5db199SXin Li
109*9c5db199SXin Li        fake_shell = '/bin/ash'
110*9c5db199SXin Li        tmp_script = '/usr/local/tmp/%s' % script_name
111*9c5db199SXin Li        fake_res = fake_result('#!%s\n' % fake_shell)
112*9c5db199SXin Li
113*9c5db199SXin Li        host.path_exists.return_value = False
114*9c5db199SXin Li        host.run.return_value = fake_res
115*9c5db199SXin Li
116*9c5db199SXin Li        # Complicated case:  script not on DUT, so try to download it.
117*9c5db199SXin Li        self.assertEqual(cros_provisioner._get_remote_script(script_name),
118*9c5db199SXin Li                         '%s %s' % (fake_shell, tmp_script))
119*9c5db199SXin Li        host.path_exists.assert_called_with(local_script)
120*9c5db199SXin Li
121*9c5db199SXin Li
122*9c5db199SXin Liclass fake_result(object):
123*9c5db199SXin Li    """A fake result with stdout attribute."""
124*9c5db199SXin Li    def __init__(self, result):
125*9c5db199SXin Li        self.stdout = result
126*9c5db199SXin Li
127*9c5db199SXin Li
128*9c5db199SXin Liclass TestProvisioner2(unittest.TestCase):
129*9c5db199SXin Li    """Another test for provisioner module that using mock."""
130*9c5db199SXin Li
131*9c5db199SXin Li    def testAlwaysRunQuickProvision(self):
132*9c5db199SXin Li        """Tests that we call quick provsion for all kinds of builds."""
133*9c5db199SXin Li        image = 'foo-whatever/R65-1234.5.6'
134*9c5db199SXin Li        devserver = 'http://mock_devserver'
135*9c5db199SXin Li        provisioner.dev_server = mock.MagicMock()
136*9c5db199SXin Li        provisioner.metrics = mock.MagicMock()
137*9c5db199SXin Li        host = mock.MagicMock()
138*9c5db199SXin Li        update_url = '%s/update/%s' % (devserver, image)
139*9c5db199SXin Li        cros_provisioner = provisioner.ChromiumOSProvisioner(update_url, host)
140*9c5db199SXin Li        cros_provisioner.check_update_status = mock.MagicMock()
141*9c5db199SXin Li        kernel_utils.verify_kernel_state_after_update = mock.MagicMock()
142*9c5db199SXin Li        kernel_utils.verify_kernel_state_after_update.return_value = 3
143*9c5db199SXin Li        kernel_utils.verify_boot_expectations = mock.MagicMock()
144*9c5db199SXin Li
145*9c5db199SXin Li        cros_provisioner.run_provision()
146*9c5db199SXin Li        host.run.assert_any_call(
147*9c5db199SXin Li                '/usr/local/bin/quick-provision --noreboot %s '
148*9c5db199SXin Li                '%s/download/chromeos-image-archive' % (image, devserver))
149*9c5db199SXin Li
150*9c5db199SXin Li
151*9c5db199SXin Liif __name__ == '__main__':
152*9c5db199SXin Li    unittest.main()
153