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