Mike Frysinger | d03e6b5 | 2019-08-03 12:49:01 -0400 | [diff] [blame] | 1 | #!/usr/bin/python2 |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 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 | |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 6 | import mock |
Dan Shi | b95bb86 | 2013-03-22 16:29:28 -0700 | [diff] [blame] | 7 | import mox |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 8 | import unittest |
| 9 | |
| 10 | import common |
David Haddock | 77b75c3 | 2020-05-14 01:56:32 -0700 | [diff] [blame] | 11 | from autotest_lib.client.common_lib.cros import kernel_utils |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 12 | from autotest_lib.server.cros import provisioner |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 13 | |
| 14 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 15 | class _StubUpdateError(provisioner._AttributedUpdateError): |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 16 | STUB_MESSAGE = 'Stub message' |
| 17 | STUB_PATTERN = 'Stub pattern matched' |
| 18 | _SUMMARY = 'Stub summary' |
| 19 | _CLASSIFIERS = [ |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 20 | (STUB_MESSAGE, STUB_MESSAGE), |
| 21 | ('Stub .*', STUB_PATTERN), |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 22 | ] |
| 23 | |
| 24 | def __init__(self, info, msg): |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 25 | super(_StubUpdateError, self).__init__('Stub %s' % info, msg) |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 26 | |
| 27 | |
| 28 | class 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): |
Derek Beckett | 4de221e | 2021-06-03 10:50:58 -0700 | [diff] [blame^] | 63 | """Test the `HostUpdateError` classifier.""" |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 64 | exception = provisioner.HostUpdateError('chromeos6-row3-rack3-host19', |
| 65 | 'Fake message') |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 66 | self.assertTrue(isinstance(exception.failure_summary, str)) |
| 67 | |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 68 | def test_image_install_error(self): |
Derek Beckett | 4de221e | 2021-06-03 10:50:58 -0700 | [diff] [blame^] | 69 | """Test the `ImageInstallError` classifier.""" |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 70 | exception = provisioner.ImageInstallError( |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 71 | 'chromeos6-row3-rack3-host19', 'chromeos4-devserver7.cros', |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 72 | 'Fake message') |
| 73 | self.assertTrue(isinstance(exception.failure_summary, str)) |
| 74 | |
| 75 | def test_new_build_update_error(self): |
Derek Beckett | 4de221e | 2021-06-03 10:50:58 -0700 | [diff] [blame^] | 76 | """Test the `NewBuildUpdateError` classifier.""" |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 77 | exception = provisioner.NewBuildUpdateError('R68-10621.0.0', |
| 78 | 'Fake message') |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 79 | self.assertTrue(isinstance(exception.failure_summary, str)) |
| 80 | |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 81 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 82 | class TestProvisioner(mox.MoxTestBase): |
| 83 | """Test provisioner module.""" |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 84 | |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 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' |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 90 | self.assertEqual(provisioner.url_to_image_name(update_url), |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 91 | expected_value) |
| 92 | |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 93 | def testGetRemoteScript(self): |
| 94 | """Test _get_remote_script() behaviors.""" |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 95 | update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/' |
| 96 | 'R28-4444.0.0-b2996') |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 97 | script_name = 'fubar' |
| 98 | local_script = '/usr/local/bin/%s' % script_name |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 99 | host = self.mox.CreateMockAnything() |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 100 | cros_provisioner = provisioner.ChromiumOSProvisioner(update_url, |
| 101 | host=host) |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 102 | host.path_exists(local_script).AndReturn(True) |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 103 | |
| 104 | self.mox.ReplayAll() |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 105 | # Simple case: file exists on DUT |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 106 | self.assertEqual(cros_provisioner._get_remote_script(script_name), |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 107 | local_script) |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 108 | self.mox.VerifyAll() |
| 109 | |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 110 | self.mox.ResetAll() |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 111 | fake_shell = '/bin/ash' |
Laurence Goodby | 06fb42c | 2020-02-29 17:14:42 -0800 | [diff] [blame] | 112 | tmp_script = '/usr/local/tmp/%s' % script_name |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 113 | fake_result = self.mox.CreateMockAnything() |
Dana Goyette | 353d1d9 | 2019-06-27 10:43:59 -0700 | [diff] [blame] | 114 | fake_result.stdout = '#!%s\n' % fake_shell |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 115 | host.path_exists(local_script).AndReturn(False) |
Laurence Goodby | 06fb42c | 2020-02-29 17:14:42 -0800 | [diff] [blame] | 116 | host.run(mox.IgnoreArg()) |
Dana Goyette | 353d1d9 | 2019-06-27 10:43:59 -0700 | [diff] [blame] | 117 | host.run(mox.IgnoreArg()).AndReturn(fake_result) |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 118 | |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 119 | self.mox.ReplayAll() |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 120 | # Complicated case: script not on DUT, so try to download it. |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 121 | self.assertEqual(cros_provisioner._get_remote_script(script_name), |
| 122 | '%s %s' % (fake_shell, tmp_script)) |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 123 | self.mox.VerifyAll() |
| 124 | |
Chris Sosa | c861752 | 2014-06-09 23:22:26 +0000 | [diff] [blame] | 125 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 126 | class TestProvisioner2(unittest.TestCase): |
| 127 | """Another test for provisioner module that using mock.""" |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 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' |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 133 | provisioner.dev_server = mock.MagicMock() |
| 134 | provisioner.metrics = mock.MagicMock() |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 135 | host = mock.MagicMock() |
| 136 | update_url = '%s/update/%s' % (devserver, image) |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 137 | cros_provisioner = provisioner.ChromiumOSProvisioner(update_url, host) |
| 138 | cros_provisioner.check_update_status = mock.MagicMock() |
David Haddock | 77b75c3 | 2020-05-14 01:56:32 -0700 | [diff] [blame] | 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() |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 142 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame] | 143 | cros_provisioner.run_provision() |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 144 | host.run.assert_any_call( |
Jae Hoon Kim | 3f00499 | 2020-09-10 17:48:33 -0700 | [diff] [blame] | 145 | '/usr/local/bin/quick-provision --noreboot %s ' |
| 146 | '%s/download/chromeos-image-archive' % (image, devserver)) |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 147 | |
| 148 | |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 149 | if __name__ == '__main__': |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 150 | unittest.main() |