blob: 0e2bf94abbca455490f8f56aed0e3a0c242820ec [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."""
Shuqian Zhao79f248d2018-05-10 14:47:55 -0700225 dsl.HOSTNAME = 'test_server'
Don Garrettd0321722014-11-18 16:03:33 -0800226 single_stable = {'foo': ['status_ok', 'status_ok']}
227 double_stable = {'foo': ['status_a', 'status_a'],
228 'bar': ['status_b', 'status_b']}
229
230 # Verify we can handle stable services.
231 self._test_restart_services(single_stable)
232 self._test_restart_services(double_stable)
233
234 single_unstable = {'foo': ['status_ok', 'status_not_ok']}
235 triple_unstable = {'foo': ['status_a', 'status_a'],
236 'bar': ['status_b', 'status_b_not_ok'],
237 'joe': ['status_c', 'status_c_not_ok']}
238
239 # Verify we can handle unstable services and report the right failures.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700240 with self.assertRaises(dsl.UnstableServices) as unstable:
Don Garrettd0321722014-11-18 16:03:33 -0800241 self._test_restart_services(single_unstable)
Shuqian Zhao79f248d2018-05-10 14:47:55 -0700242 self.assertEqual(unstable.exception.args[0],
243 "test_server service restart failed: ['foo']")
Don Garrettd0321722014-11-18 16:03:33 -0800244
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700245 with self.assertRaises(dsl.UnstableServices) as unstable:
Don Garrettd0321722014-11-18 16:03:33 -0800246 self._test_restart_services(triple_unstable)
Shuqian Zhao79f248d2018-05-10 14:47:55 -0700247 self.assertEqual(unstable.exception.args[0],
248 "test_server service restart failed: ['bar', 'joe']")
Don Garrettd0321722014-11-18 16:03:33 -0800249
Don Garrettfa2c1c42014-12-11 12:11:49 -0800250 @mock.patch('subprocess.check_output', autospec=True)
Don Garrett35711212014-12-18 14:33:41 -0800251 def test_report_changes_no_update(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700252 """Test deploy_server_local.report_changes.
Don Garrett35711212014-12-18 14:33:41 -0800253
254 @param run_cmd: Mock of subprocess call used.
255 """
256
257 before = {
258 'autotest': ('/usr/local/autotest', 'auto_before'),
259 'autotest_private': ('/dir/autotest_private', '78b9626'),
260 'other': ('/fake/unchanged', 'constant_hash'),
261 }
262
263 run_cmd.return_value = 'hash1 Fix change.\nhash2 Bad change.\n'
264
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700265 result = dsl.report_changes(before, None)
Don Garrett35711212014-12-18 14:33:41 -0800266
267 self.assertEqual(result, """autotest: auto_before
268autotest_private: 78b9626
269other: constant_hash
270""")
271
272 self.assertFalse(run_cmd.called)
273
274 @mock.patch('subprocess.check_output', autospec=True)
275 def test_report_changes_diff(self, run_cmd):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700276 """Test deploy_server_local.report_changes.
Don Garrettfa2c1c42014-12-11 12:11:49 -0800277
278 @param run_cmd: Mock of subprocess call used.
279 """
280
281 before = {
282 'autotest': ('/usr/local/autotest', 'auto_before'),
283 'autotest_private': ('/dir/autotest_private', '78b9626'),
284 'other': ('/fake/unchanged', 'constant_hash'),
285 }
286
287 after = {
288 'autotest': ('/usr/local/autotest', 'auto_after'),
289 'autotest_tools': ('/dir/autotest_tools', 'a1598f7'),
290 'other': ('/fake/unchanged', 'constant_hash'),
291 }
292
293 run_cmd.return_value = 'hash1 Fix change.\nhash2 Bad change.\n'
294
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700295 result = dsl.report_changes(before, after)
Don Garrettfa2c1c42014-12-11 12:11:49 -0800296
297 self.assertEqual(result, """autotest:
298hash1 Fix change.
299hash2 Bad change.
300
301autotest_private:
302Removed.
303
304autotest_tools:
305Added.
306
307other:
308No Change.
309""")
310
311 run_cmd.assert_called_with(
312 ['git', 'log', 'auto_before..auto_after', '--oneline'],
313 cwd='/usr/local/autotest', stderr=subprocess.STDOUT)
314
Don Garrett03432d62014-11-19 18:18:35 -0800315 def test_parse_arguments(self):
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700316 """Test deploy_server_local.parse_arguments."""
Don Garrett03432d62014-11-19 18:18:35 -0800317 # No arguments.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700318 results = dsl.parse_arguments([])
Don Garrette3718912014-12-05 13:11:44 -0800319 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800320 {'verify': True, 'update': True, 'actions': True,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700321 'report': True, 'dryrun': False, 'update_push_servers': False},
322 vars(results))
323
324 # Update test_push servers.
325 results = dsl.parse_arguments(['--update_push_servers'])
326 self.assertDictContainsSubset(
327 {'verify': True, 'update': True, 'actions': True,
328 'report': True, 'dryrun': False, 'update_push_servers': True},
Don Garrette3718912014-12-05 13:11:44 -0800329 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800330
331 # Dryrun.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700332 results = dsl.parse_arguments(['--dryrun'])
Don Garrette3718912014-12-05 13:11:44 -0800333 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800334 {'verify': False, 'update': False, 'actions': True,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700335 'report': True, 'dryrun': True, 'update_push_servers': False},
Don Garrette3718912014-12-05 13:11:44 -0800336 vars(results))
337
338 # Restart only.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700339 results = dsl.parse_arguments(['--actions-only'])
Don Garrette3718912014-12-05 13:11:44 -0800340 self.assertDictContainsSubset(
341 {'verify': False, 'update': False, 'actions': True,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700342 'report': False, 'dryrun': False,
343 'update_push_servers': False},
Don Garrette3718912014-12-05 13:11:44 -0800344 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800345
346 # All skip arguments.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700347 results = dsl.parse_arguments(['--skip-verify', '--skip-update',
Don Garrett03432d62014-11-19 18:18:35 -0800348 '--skip-actions', '--skip-report'])
Don Garrette3718912014-12-05 13:11:44 -0800349 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800350 {'verify': False, 'update': False, 'actions': False,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700351 'report': False, 'dryrun': False,
352 'update_push_servers': False},
Don Garrette3718912014-12-05 13:11:44 -0800353 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800354
355 # All arguments.
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700356 results = dsl.parse_arguments(['--skip-verify', '--skip-update',
Don Garrett03432d62014-11-19 18:18:35 -0800357 '--skip-actions', '--skip-report',
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700358 '--actions-only', '--dryrun',
359 '--update_push_servers'])
Don Garrette3718912014-12-05 13:11:44 -0800360 self.assertDictContainsSubset(
Don Garrett03432d62014-11-19 18:18:35 -0800361 {'verify': False, 'update': False, 'actions': False,
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700362 'report': False, 'dryrun': True, 'update_push_servers': True},
Don Garrette3718912014-12-05 13:11:44 -0800363 vars(results))
Don Garrett03432d62014-11-19 18:18:35 -0800364
Don Garrettd0321722014-11-18 16:03:33 -0800365
366if __name__ == '__main__':
367 unittest.main()