blob: 592da403730989bc9def740fc80d73da67cafb40 [file] [log] [blame]
Don Garrettd0321722014-11-18 16:03:33 -08001#!/usr/bin/python
2# Copyright (c) 2014 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
Shuqian Zhao8754a1a2016-08-24 12:54:11 -07006"""Unittests for deploy_server_local.py."""
Don Garrettd0321722014-11-18 16:03:33 -08007
8from __future__ import print_function
9
10import mock
Don Garrettfa2c1c42014-12-11 12:11:49 -080011import subprocess
Don Garrettd0321722014-11-18 16:03:33 -080012import unittest
13
Richard Barnette2e0a4232018-03-07 17:13:16 -080014import common
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070015import deploy_server_local as dsl
Don Garrettd0321722014-11-18 16:03:33 -080016
17
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070018class TestDeployServerLocal(unittest.TestCase):
19 """Test deploy_server_local with commands mocked out."""
Don Garrettd0321722014-11-18 16:03:33 -080020
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070021 orig_timer = dsl.SERVICE_STABILITY_TIMER
Don Garrettd0321722014-11-18 16:03:33 -080022
Don Garrett35711212014-12-18 14:33:41 -080023 PROD_STATUS = ('\x1b[1mproject autotest/ '
24 ' \x1b[m\x1b[1mbranch prod\x1b[m\n')
25
26 PROD_VERSIONS = '''\x1b[1mproject autotest/\x1b[m
27/usr/local/autotest
28ebb2182
29
30\x1b[1mproject autotest/site_utils/autotest_private/\x1b[m
31/usr/local/autotest/site_utils/autotest_private
3278b9626
33
34\x1b[1mproject autotest/site_utils/autotest_tools/\x1b[m
35/usr/local/autotest/site_utils/autotest_tools
36a1598f7
37'''
38
39
Don Garrettd0321722014-11-18 16:03:33 -080040 def setUp(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070041 dsl.SERVICE_STABILITY_TIMER = 0.01
Don Garrettd0321722014-11-18 16:03:33 -080042
43 def tearDown(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070044 dsl.SERVICE_STABILITY_TIMER = self.orig_timer
Don Garrettd0321722014-11-18 16:03:33 -080045
Don Garrett35711212014-12-18 14:33:41 -080046 def test_strip_terminal_codes(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070047 """Test deploy_server_local.strip_terminal_codes."""
Don Garrett35711212014-12-18 14:33:41 -080048 # Leave format free lines alone.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070049 result = dsl.strip_terminal_codes('')
Don Garrett35711212014-12-18 14:33:41 -080050 self.assertEqual(result, '')
51
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070052 result = dsl.strip_terminal_codes('This is normal text.')
Don Garrett35711212014-12-18 14:33:41 -080053 self.assertEqual(result, 'This is normal text.')
54
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070055 result = dsl.strip_terminal_codes('Line1\nLine2\n')
Don Garrett35711212014-12-18 14:33:41 -080056 self.assertEqual(result, 'Line1\nLine2\n')
57
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070058 result = dsl.strip_terminal_codes('Line1\nLine2\n')
Don Garrett35711212014-12-18 14:33:41 -080059 self.assertEqual(result, 'Line1\nLine2\n')
60
61 # Test cleaning lines with formatting.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070062 result = dsl.strip_terminal_codes('\x1b[1m')
Don Garrett35711212014-12-18 14:33:41 -080063 self.assertEqual(result, '')
64
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070065 result = dsl.strip_terminal_codes('\x1b[m')
Don Garrett35711212014-12-18 14:33:41 -080066 self.assertEqual(result, '')
67
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070068 result = dsl.strip_terminal_codes('\x1b[1mm')
Don Garrett35711212014-12-18 14:33:41 -080069 self.assertEqual(result, 'm')
70
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070071 result = dsl.strip_terminal_codes(self.PROD_STATUS)
Don Garrett35711212014-12-18 14:33:41 -080072 self.assertEqual(result,
73 'project autotest/ branch prod\n')
74
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070075 result = dsl.strip_terminal_codes(self.PROD_VERSIONS)
Don Garrett35711212014-12-18 14:33:41 -080076 self.assertEqual(result, '''project autotest/
77/usr/local/autotest
78ebb2182
79
80project autotest/site_utils/autotest_private/
81/usr/local/autotest/site_utils/autotest_private
8278b9626
83
84project autotest/site_utils/autotest_tools/
85/usr/local/autotest/site_utils/autotest_tools
86a1598f7
87''')
Don Garrettd0321722014-11-18 16:03:33 -080088
89 @mock.patch('subprocess.check_output', autospec=True)
90 def test_verify_repo_clean(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070091 """Test deploy_server_local.verify_repo_clean.
Don Garrettd0321722014-11-18 16:03:33 -080092
93 @param run_cmd: Mock of subprocess call used.
94 """
95 # If repo returns what we expect, exit cleanly.
Don Garrett699b4b32014-12-11 13:10:15 -080096 run_cmd.return_value = 'nothing to commit (working directory clean)\n'
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070097 dsl.verify_repo_clean()
Don Garrett699b4b32014-12-11 13:10:15 -080098
Prathmesh Prabhuda286992015-04-07 13:20:08 -070099 # If repo contains any branches (even clean ones), raise.
Don Garrett35711212014-12-18 14:33:41 -0800100 run_cmd.return_value = self.PROD_STATUS
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700101 with self.assertRaises(dsl.DirtyTreeException):
102 dsl.verify_repo_clean()
Don Garrettd0321722014-11-18 16:03:33 -0800103
Prathmesh Prabhuda286992015-04-07 13:20:08 -0700104 # If repo doesn't return what we expect, raise.
105 run_cmd.return_value = "That's a very dirty repo you've got."
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700106 with self.assertRaises(dsl.DirtyTreeException):
107 dsl.verify_repo_clean()
Don Garrett699b4b32014-12-11 13:10:15 -0800108
Don Garrettd0321722014-11-18 16:03:33 -0800109 @mock.patch('subprocess.check_output', autospec=True)
110 def test_repo_versions(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700111 """Test deploy_server_local.repo_versions.
Don Garrettd0321722014-11-18 16:03:33 -0800112
113 @param run_cmd: Mock of subprocess call used.
114 """
Don Garrettfa2c1c42014-12-11 12:11:49 -0800115 expected = {
116 'autotest':
Don Garrett35711212014-12-18 14:33:41 -0800117 ('/usr/local/autotest', 'ebb2182'),
Don Garrettfa2c1c42014-12-11 12:11:49 -0800118 'autotest/site_utils/autotest_private':
119 ('/usr/local/autotest/site_utils/autotest_private', '78b9626'),
120 'autotest/site_utils/autotest_tools':
121 ('/usr/local/autotest/site_utils/autotest_tools', 'a1598f7'),
122 }
123
Don Garrett35711212014-12-18 14:33:41 -0800124 run_cmd.return_value = self.PROD_VERSIONS
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700125 result = dsl.repo_versions()
Don Garrettd0321722014-11-18 16:03:33 -0800126 self.assertEquals(result, expected)
127
128 run_cmd.assert_called_with(
Don Garrettfa2c1c42014-12-11 12:11:49 -0800129 ['repo', 'forall', '-p', '-c',
130 'pwd && git log -1 --format=%h'])
Don Garrettd0321722014-11-18 16:03:33 -0800131
132 @mock.patch('subprocess.check_output', autospec=True)
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700133 def test_repo_sync_not_for_push_servers(self, run_cmd):
134 """Test deploy_server_local.repo_sync.
Don Garrettd0321722014-11-18 16:03:33 -0800135
136 @param run_cmd: Mock of subprocess call used.
137 """
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700138 dsl.repo_sync()
Richard Barnette488ac8b2017-09-01 09:28:55 -0700139 expect_cmds = [mock.call(['git', 'checkout', 'cros/prod'], stderr=-2)]
Shuqian Zhaoec26bd72017-01-31 10:17:25 -0800140 run_cmd.assert_has_calls(expect_cmds)
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700141
142 @mock.patch('subprocess.check_output', autospec=True)
143 def test_repo_sync_for_push_servers(self, run_cmd):
144 """Test deploy_server_local.repo_sync.
145
146 @param run_cmd: Mock of subprocess call used.
147 """
148 dsl.repo_sync(update_push_servers=True)
Richard Barnette488ac8b2017-09-01 09:28:55 -0700149 expect_cmds = [mock.call(['git', 'checkout', 'cros/master'], stderr=-2)]
Shuqian Zhaoec26bd72017-01-31 10:17:25 -0800150 run_cmd.assert_has_calls(expect_cmds)
Don Garrettd0321722014-11-18 16:03:33 -0800151
Allen Lia2749cd2017-10-31 18:03:19 -0700152 def test_discover_commands(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700153 """Test deploy_server_local.discover_update_commands and
Don Garrettd0321722014-11-18 16:03:33 -0800154 discover_restart_services."""
155 # It should always be a list, and should always be callable in
156 # any local environment, though the result will vary.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700157 result = dsl.discover_update_commands()
Don Garrettd0321722014-11-18 16:03:33 -0800158 self.assertIsInstance(result, list)
159
Don Garrett4769c902015-01-05 15:58:56 -0800160 @mock.patch('subprocess.check_output', autospec=True)
Don Garrettd0321722014-11-18 16:03:33 -0800161 def test_update_command(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700162 """Test deploy_server_local.update_command.
Don Garrettd0321722014-11-18 16:03:33 -0800163
164 @param run_cmd: Mock of subprocess call used.
165 """
166 # Call with a bad command name.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700167 with self.assertRaises(dsl.UnknownCommandException):
168 dsl.update_command('Unknown Command')
Don Garrettd0321722014-11-18 16:03:33 -0800169 self.assertFalse(run_cmd.called)
170
Richard Barnette2e0a4232018-03-07 17:13:16 -0800171 # Call with a couple valid command names.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700172 dsl.update_command('apache')
Don Garrett4769c902015-01-05 15:58:56 -0800173 run_cmd.assert_called_with('sudo service apache2 reload', shell=True,
Richard Barnette2e0a4232018-03-07 17:13:16 -0800174 cwd=common.autotest_dir,
Don Garrett4769c902015-01-05 15:58:56 -0800175 stderr=subprocess.STDOUT)
Don Garrettd0321722014-11-18 16:03:33 -0800176
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700177 dsl.update_command('build_externals')
Richard Barnette2e0a4232018-03-07 17:13:16 -0800178 expected_cmd = './utils/build_externals.py'
179 run_cmd.assert_called_with(expected_cmd, shell=True,
180 cwd=common.autotest_dir,
Don Garrett4769c902015-01-05 15:58:56 -0800181 stderr=subprocess.STDOUT)
182
183 # Test a failed command.
Richard Barnette2e0a4232018-03-07 17:13:16 -0800184 failure = subprocess.CalledProcessError(10, expected_cmd, 'output')
Don Garrett4769c902015-01-05 15:58:56 -0800185
186 run_cmd.side_effect = failure
187 with self.assertRaises(subprocess.CalledProcessError) as unstable:
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700188 dsl.update_command('build_externals')
Don Garrettd0321722014-11-18 16:03:33 -0800189
190 @mock.patch('subprocess.check_call', autospec=True)
191 def test_restart_service(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700192 """Test deploy_server_local.restart_service.
Don Garrettd0321722014-11-18 16:03:33 -0800193
194 @param run_cmd: Mock of subprocess call used.
195 """
196 # Standard call.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700197 dsl.restart_service('foobar')
Shuqian Zhao9febd452017-01-31 15:36:40 -0800198 run_cmd.assert_called_with(['sudo', 'service', 'foobar', 'restart'],
199 stderr=-2)
Don Garrettd0321722014-11-18 16:03:33 -0800200
201 @mock.patch('subprocess.check_output', autospec=True)
202 def test_restart_status(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700203 """Test deploy_server_local.service_status.
Don Garrettd0321722014-11-18 16:03:33 -0800204
205 @param run_cmd: Mock of subprocess call used.
206 """
207 # Standard call.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700208 dsl.service_status('foobar')
Shuqian Zhaodcaa6162017-11-09 10:58:45 -0800209 run_cmd.assert_called_with(['sudo', 'service', 'foobar', 'status'])
Don Garrettd0321722014-11-18 16:03:33 -0800210
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700211 @mock.patch.object(dsl, 'restart_service', autospec=True)
Don Garrettd0321722014-11-18 16:03:33 -0800212 def _test_restart_services(self, service_results, _restart):
213 """Helper for testing restart_services.
214
215 @param service_results: {'service_name': ['status_1', 'status_2']}
216 """
217 # each call to service_status should return the next status value for
218 # that service.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700219 with mock.patch.object(dsl, 'service_status', autospec=True,
Don Garrettd0321722014-11-18 16:03:33 -0800220 side_effect=lambda n: service_results[n].pop(0)):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700221 dsl.restart_services(service_results.keys())
Don Garrettd0321722014-11-18 16:03:33 -0800222
223 def test_restart_services(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700224 """Test deploy_server_local.restart_services."""
Don Garrettd0321722014-11-18 16:03:33 -0800225 single_stable = {'foo': ['status_ok', 'status_ok']}
226 double_stable = {'foo': ['status_a', 'status_a'],
227 'bar': ['status_b', 'status_b']}
228
229 # Verify we can handle stable services.
230 self._test_restart_services(single_stable)
231 self._test_restart_services(double_stable)
232
233 single_unstable = {'foo': ['status_ok', 'status_not_ok']}
234 triple_unstable = {'foo': ['status_a', 'status_a'],
235 'bar': ['status_b', 'status_b_not_ok'],
236 'joe': ['status_c', 'status_c_not_ok']}
237
238 # Verify we can handle unstable services and report the right failures.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700239 with self.assertRaises(dsl.UnstableServices) as unstable:
Don Garrettd0321722014-11-18 16:03:33 -0800240 self._test_restart_services(single_unstable)
241 self.assertEqual(unstable.exception.args[0], ['foo'])
242
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700243 with self.assertRaises(dsl.UnstableServices) as unstable:
Don Garrettd0321722014-11-18 16:03:33 -0800244 self._test_restart_services(triple_unstable)
245 self.assertEqual(unstable.exception.args[0], ['bar', 'joe'])
246
Don Garrettfa2c1c42014-12-11 12:11:49 -0800247 @mock.patch('subprocess.check_output', autospec=True)
Don Garrett35711212014-12-18 14:33:41 -0800248 def test_report_changes_no_update(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700249 """Test deploy_server_local.report_changes.
Don Garrett35711212014-12-18 14:33:41 -0800250
251 @param run_cmd: Mock of subprocess call used.
252 """
253
254 before = {
255 'autotest': ('/usr/local/autotest', 'auto_before'),
256 'autotest_private': ('/dir/autotest_private', '78b9626'),
257 'other': ('/fake/unchanged', 'constant_hash'),
258 }
259
260 run_cmd.return_value = 'hash1 Fix change.\nhash2 Bad change.\n'
261
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700262 result = dsl.report_changes(before, None)
Don Garrett35711212014-12-18 14:33:41 -0800263
264 self.assertEqual(result, """autotest: auto_before
265autotest_private: 78b9626
266other: constant_hash
267""")
268
269 self.assertFalse(run_cmd.called)
270
271 @mock.patch('subprocess.check_output', autospec=True)
272 def test_report_changes_diff(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700273 """Test deploy_server_local.report_changes.
Don Garrettfa2c1c42014-12-11 12:11:49 -0800274
275 @param run_cmd: Mock of subprocess call used.
276 """
277
278 before = {
279 'autotest': ('/usr/local/autotest', 'auto_before'),
280 'autotest_private': ('/dir/autotest_private', '78b9626'),
281 'other': ('/fake/unchanged', 'constant_hash'),
282 }
283
284 after = {
285 'autotest': ('/usr/local/autotest', 'auto_after'),
286 'autotest_tools': ('/dir/autotest_tools', 'a1598f7'),
287 'other': ('/fake/unchanged', 'constant_hash'),
288 }
289
290 run_cmd.return_value = 'hash1 Fix change.\nhash2 Bad change.\n'
291
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700292 result = dsl.report_changes(before, after)
Don Garrettfa2c1c42014-12-11 12:11:49 -0800293
294 self.assertEqual(result, """autotest:
295hash1 Fix change.
296hash2 Bad change.
297
298autotest_private:
299Removed.
300
301autotest_tools:
302Added.
303
304other:
305No Change.
306""")
307
308 run_cmd.assert_called_with(
309 ['git', 'log', 'auto_before..auto_after', '--oneline'],
310 cwd='/usr/local/autotest', stderr=subprocess.STDOUT)
311
Don Garrett03432d62014-11-19 18:18:35 -0800312 def test_parse_arguments(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700313 """Test deploy_server_local.parse_arguments."""
Don Garrett03432d62014-11-19 18:18:35 -0800314 # No arguments.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700315 results = dsl.parse_arguments([])
Don Garrette3718912014-12-05 13:11:44 -0800316 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800317 {'verify': True, 'update': True, 'actions': True,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700318 'report': True, 'dryrun': False, 'update_push_servers': False},
319 vars(results))
320
321 # Update test_push servers.
322 results = dsl.parse_arguments(['--update_push_servers'])
323 self.assertDictContainsSubset(
324 {'verify': True, 'update': True, 'actions': True,
325 'report': True, 'dryrun': False, 'update_push_servers': True},
Don Garrette3718912014-12-05 13:11:44 -0800326 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800327
328 # Dryrun.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700329 results = dsl.parse_arguments(['--dryrun'])
Don Garrette3718912014-12-05 13:11:44 -0800330 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800331 {'verify': False, 'update': False, 'actions': True,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700332 'report': True, 'dryrun': True, 'update_push_servers': False},
Don Garrette3718912014-12-05 13:11:44 -0800333 vars(results))
334
335 # Restart only.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700336 results = dsl.parse_arguments(['--actions-only'])
Don Garrette3718912014-12-05 13:11:44 -0800337 self.assertDictContainsSubset(
338 {'verify': False, 'update': False, 'actions': True,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700339 'report': False, 'dryrun': False,
340 'update_push_servers': False},
Don Garrette3718912014-12-05 13:11:44 -0800341 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800342
343 # All skip arguments.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700344 results = dsl.parse_arguments(['--skip-verify', '--skip-update',
Don Garrett03432d62014-11-19 18:18:35 -0800345 '--skip-actions', '--skip-report'])
Don Garrette3718912014-12-05 13:11:44 -0800346 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800347 {'verify': False, 'update': False, 'actions': False,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700348 'report': False, 'dryrun': False,
349 'update_push_servers': False},
Don Garrette3718912014-12-05 13:11:44 -0800350 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800351
352 # All arguments.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700353 results = dsl.parse_arguments(['--skip-verify', '--skip-update',
Don Garrett03432d62014-11-19 18:18:35 -0800354 '--skip-actions', '--skip-report',
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700355 '--actions-only', '--dryrun',
356 '--update_push_servers'])
Don Garrette3718912014-12-05 13:11:44 -0800357 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800358 {'verify': False, 'update': False, 'actions': False,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700359 'report': False, 'dryrun': True, 'update_push_servers': True},
Don Garrette3718912014-12-05 13:11:44 -0800360 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800361
Don Garrettd0321722014-11-18 16:03:33 -0800362
363if __name__ == '__main__':
364 unittest.main()