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 = [ |
| 20 | (STUB_MESSAGE, STUB_MESSAGE), |
| 21 | ('Stub .*', STUB_PATTERN), |
| 22 | ] |
| 23 | |
| 24 | def __init__(self, info, msg): |
| 25 | super(_StubUpdateError, self).__init__( |
| 26 | 'Stub %s' % info, msg) |
| 27 | |
| 28 | |
| 29 | class TestErrorClassifications(unittest.TestCase): |
| 30 | """Test error message handling in `_AttributedUpdateError`.""" |
| 31 | |
| 32 | def test_exception_message(self): |
| 33 | """Test that the exception string includes its arguments.""" |
| 34 | info = 'info marker' |
| 35 | msg = 'an error message' |
| 36 | stub = _StubUpdateError(info, msg) |
| 37 | self.assertIn(info, str(stub)) |
| 38 | self.assertIn(msg, str(stub)) |
| 39 | |
| 40 | def test_classifier_message(self): |
| 41 | """Test that the exception classifier can match a simple string.""" |
| 42 | info = 'info marker' |
| 43 | stub = _StubUpdateError(info, _StubUpdateError.STUB_MESSAGE) |
| 44 | self.assertNotIn(info, stub.failure_summary) |
| 45 | self.assertIn(_StubUpdateError._SUMMARY, stub.failure_summary) |
| 46 | self.assertIn(_StubUpdateError.STUB_MESSAGE, stub.failure_summary) |
| 47 | |
| 48 | def test_classifier_pattern(self): |
| 49 | """Test that the exception classifier can match a regex.""" |
| 50 | info = 'info marker' |
| 51 | stub = _StubUpdateError(info, 'Stub this is a test') |
| 52 | self.assertNotIn(info, stub.failure_summary) |
| 53 | self.assertIn(_StubUpdateError._SUMMARY, stub.failure_summary) |
| 54 | self.assertIn(_StubUpdateError.STUB_PATTERN, stub.failure_summary) |
| 55 | |
| 56 | def test_classifier_unmatched(self): |
| 57 | """Test exception summary when no classifier matches.""" |
| 58 | info = 'info marker' |
| 59 | stub = _StubUpdateError(info, 'This matches no pattern') |
| 60 | self.assertNotIn(info, stub.failure_summary) |
| 61 | self.assertIn(_StubUpdateError._SUMMARY, stub.failure_summary) |
| 62 | |
| 63 | def test_host_update_error(self): |
| 64 | """Sanity test the `HostUpdateError` classifier.""" |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 65 | exception = provisioner.HostUpdateError( |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 66 | 'chromeos6-row3-rack3-host19', 'Fake message') |
| 67 | self.assertTrue(isinstance(exception.failure_summary, str)) |
| 68 | |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 69 | def test_image_install_error(self): |
| 70 | """Sanity test the `ImageInstallError` classifier.""" |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 71 | exception = provisioner.ImageInstallError( |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 72 | 'chromeos6-row3-rack3-host19', |
| 73 | 'chromeos4-devserver7.cros', |
| 74 | 'Fake message') |
| 75 | self.assertTrue(isinstance(exception.failure_summary, str)) |
| 76 | |
| 77 | def test_new_build_update_error(self): |
| 78 | """Sanity test the `NewBuildUpdateError` classifier.""" |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 79 | exception = provisioner.NewBuildUpdateError( |
Richard Barnette | 5adb6d4 | 2018-06-28 15:52:32 -0700 | [diff] [blame] | 80 | 'R68-10621.0.0', 'Fake message') |
| 81 | self.assertTrue(isinstance(exception.failure_summary, str)) |
| 82 | |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 83 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 84 | class TestProvisioner(mox.MoxTestBase): |
| 85 | """Test provisioner module.""" |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 86 | |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 87 | def testParseBuildFromUpdateUrlwithUpdate(self): |
| 88 | """Test that we properly parse the build from an update_url.""" |
| 89 | update_url = ('http://172.22.50.205:8082/update/lumpy-release/' |
| 90 | 'R27-3837.0.0') |
| 91 | expected_value = 'lumpy-release/R27-3837.0.0' |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 92 | self.assertEqual(provisioner.url_to_image_name(update_url), |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 93 | expected_value) |
| 94 | |
Chris Sosa | 7231260 | 2013-04-16 15:01:56 -0700 | [diff] [blame] | 95 | |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 96 | def testGetRemoteScript(self): |
| 97 | """Test _get_remote_script() behaviors.""" |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 98 | update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/' |
| 99 | 'R28-4444.0.0-b2996') |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 100 | script_name = 'fubar' |
| 101 | local_script = '/usr/local/bin/%s' % script_name |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 102 | host = self.mox.CreateMockAnything() |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 103 | cros_provisioner = provisioner.ChromiumOSProvisioner(update_url, host=host) |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 104 | host.path_exists(local_script).AndReturn(True) |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 105 | |
| 106 | self.mox.ReplayAll() |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 107 | # Simple case: file exists on DUT |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 108 | self.assertEqual(cros_provisioner._get_remote_script(script_name), |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 109 | local_script) |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 110 | self.mox.VerifyAll() |
| 111 | |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 112 | self.mox.ResetAll() |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 113 | fake_shell = '/bin/ash' |
Laurence Goodby | 06fb42c | 2020-02-29 17:14:42 -0800 | [diff] [blame] | 114 | tmp_script = '/usr/local/tmp/%s' % script_name |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 115 | fake_result = self.mox.CreateMockAnything() |
Dana Goyette | 353d1d9 | 2019-06-27 10:43:59 -0700 | [diff] [blame] | 116 | fake_result.stdout = '#!%s\n' % fake_shell |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 117 | host.path_exists(local_script).AndReturn(False) |
Laurence Goodby | 06fb42c | 2020-02-29 17:14:42 -0800 | [diff] [blame] | 118 | host.run(mox.IgnoreArg()) |
Dana Goyette | 353d1d9 | 2019-06-27 10:43:59 -0700 | [diff] [blame] | 119 | host.run(mox.IgnoreArg()).AndReturn(fake_result) |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 120 | |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 121 | self.mox.ReplayAll() |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 122 | # Complicated case: script not on DUT, so try to download it. |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 123 | self.assertEqual( |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 124 | cros_provisioner._get_remote_script(script_name), |
Richard Barnette | f00a2ee | 2018-06-08 11:51:38 -0700 | [diff] [blame] | 125 | '%s %s' % (fake_shell, tmp_script)) |
Gwendal Grignou | 3e96cc2 | 2017-06-07 16:22:51 -0700 | [diff] [blame] | 126 | self.mox.VerifyAll() |
| 127 | |
Chris Sosa | c861752 | 2014-06-09 23:22:26 +0000 | [diff] [blame] | 128 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 129 | class TestProvisioner2(unittest.TestCase): |
| 130 | """Another test for provisioner module that using mock.""" |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 131 | |
| 132 | def testAlwaysRunQuickProvision(self): |
| 133 | """Tests that we call quick provsion for all kinds of builds.""" |
| 134 | image = 'foo-whatever/R65-1234.5.6' |
| 135 | devserver = 'http://mock_devserver' |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 136 | provisioner.dev_server = mock.MagicMock() |
| 137 | provisioner.metrics = mock.MagicMock() |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 138 | host = mock.MagicMock() |
| 139 | update_url = '%s/update/%s' % (devserver, image) |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 140 | cros_provisioner = provisioner.ChromiumOSProvisioner(update_url, host) |
| 141 | cros_provisioner.check_update_status = mock.MagicMock() |
David Haddock | 77b75c3 | 2020-05-14 01:56:32 -0700 | [diff] [blame] | 142 | kernel_utils.verify_kernel_state_after_update = mock.MagicMock() |
| 143 | kernel_utils.verify_kernel_state_after_update.return_value = 3 |
| 144 | kernel_utils.verify_boot_expectations = mock.MagicMock() |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 145 | |
Jae Hoon Kim | 5f6ca6e | 2020-09-10 16:11:23 -0700 | [diff] [blame^] | 146 | cros_provisioner.run_provision() |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 147 | host.run.assert_any_call( |
Congbin Guo | 4a2a664 | 2019-08-12 15:03:01 -0700 | [diff] [blame] | 148 | '/usr/local/bin/quick-provision --noreboot %s ' |
| 149 | '%s/download/chromeos-image-archive' % (image, devserver)) |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 150 | |
| 151 | |
Scott Zawalski | eadbf70 | 2013-03-14 09:23:06 -0400 | [diff] [blame] | 152 | if __name__ == '__main__': |
Congbin Guo | 20ef0ce | 2019-05-15 12:08:13 -0700 | [diff] [blame] | 153 | unittest.main() |