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