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