blob: fb5a9f9299bd2a8093608c9435374f03576f97c3 [file] [log] [blame]
Mike Frysingerd13faeb2013-09-05 16:00:46 -04001#!/usr/bin/python
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
6"""Unittests for pushimage.py"""
7
Mike Frysinger6791b1d2014-03-04 20:52:22 -05008from __future__ import print_function
9
Mike Frysingerd13faeb2013-09-05 16:00:46 -040010import logging
11import os
12import sys
13
14sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
15 '..', '..'))
Mike Frysinger6791b1d2014-03-04 20:52:22 -050016from chromite.lib import cros_build_lib
Mike Frysingerd13faeb2013-09-05 16:00:46 -040017from chromite.lib import cros_test_lib
18from chromite.lib import git
19from chromite.lib import gs
20from chromite.lib import gs_unittest
21from chromite.lib import osutils
22from chromite.lib import signing
23from chromite.scripts import pushimage
24
25
26class InputInsnsTest(cros_test_lib.MockTestCase):
27 """Tests for InputInsns"""
28
29 def testBasic(self):
30 """Simple smoke test"""
31 insns = pushimage.InputInsns('test.board')
32 insns.GetInsnFile('recovery')
33 self.assertEqual(insns.GetChannels(), ['dev', 'canary'])
34 self.assertEqual(insns.GetKeysets(), ['stumpy-mp-v3'])
35
36 def testGetInsnFile(self):
37 """Verify various inputs result in right insns path"""
38 testdata = (
39 ('UPPER_CAPS', 'UPPER_CAPS'),
40 ('recovery', 'test.board'),
41 ('firmware', 'test.board.firmware'),
42 ('factory', 'test.board.factory'),
43 )
44 insns = pushimage.InputInsns('test.board')
45 for image_type, filename in testdata:
46 ret = insns.GetInsnFile(image_type)
47 self.assertEqual(os.path.basename(ret), '%s.instructions' % (filename))
48
49 def testSplitCfgField(self):
50 """Verify splitting behavior behaves"""
51 testdata = (
52 ('', []),
53 ('a b c', ['a', 'b', 'c']),
54 ('a, b', ['a', 'b']),
55 ('a,b', ['a', 'b']),
56 ('a,\tb', ['a', 'b']),
57 ('a\tb', ['a', 'b']),
58 )
59 for val, exp in testdata:
60 ret = pushimage.InputInsns.SplitCfgField(val)
61 self.assertEqual(ret, exp)
62
63 def testOutputInsnsBasic(self):
64 """Verify output instructions are sane"""
65 exp_content = """[insns]
66keyset = stumpy-mp-v3
67channel = dev canary
68chromeos_shell = false
69ensure_no_password = true
70firmware_update = true
71security_checks = true
72create_nplusone = true
73
74[general]
75"""
76
77 insns = pushimage.InputInsns('test.board')
78 m = self.PatchObject(osutils, 'WriteFile')
79 insns.OutputInsns('recovery', '/bogus', {}, {})
80 self.assertTrue(m.called)
81 content = m.call_args_list[0][0][1]
82 self.assertEqual(content.rstrip(), exp_content.rstrip())
83
84 def testOutputInsnsReplacements(self):
85 """Verify output instructions can be updated"""
86 exp_content = """[insns]
87keyset = batman
88channel = dev
89chromeos_shell = false
90ensure_no_password = true
91firmware_update = true
92security_checks = true
93create_nplusone = true
94
95[general]
96board = board
97config_board = test.board
98"""
99 sect_insns = {
100 'channel': 'dev',
101 'keyset': 'batman',
102 }
103 sect_general = {
104 'config_board': 'test.board',
105 'board': 'board',
106 }
107
108 insns = pushimage.InputInsns('test.board')
109 m = self.PatchObject(osutils, 'WriteFile')
110 insns.OutputInsns('recovery', '/a/file', sect_insns, sect_general)
111 self.assertTrue(m.called)
112 content = m.call_args_list[0][0][1]
113 self.assertEqual(content.rstrip(), exp_content.rstrip())
114
115
116class MarkImageToBeSignedTest(cros_test_lib.MockTestCase):
117 """Tests for MarkImageToBeSigned()"""
118
119 def setUp(self):
120 self.gs_mock = self.StartPatcher(gs_unittest.GSContextMock())
121 self.gs_mock.SetDefaultCmdResult()
122 self.ctx = gs.GSContext()
123
124 # Minor optimization -- we call this for logging purposes in the main
125 # code, but don't really care about it for testing. It just slows us.
Mike Frysinger6791b1d2014-03-04 20:52:22 -0500126 self.PatchObject(git, 'RunGit',
127 return_value=cros_build_lib.CommandResult(output='1234\n'))
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400128
129 def testBasic(self):
130 """Simple smoke test"""
131 tbs_base = 'gs://some-bucket'
132 insns_path = 'chan/board/ver/file.instructions'
133 tbs_file = '%s/tobesigned/90,chan,board,ver,file.instructions' % tbs_base
134 ret = pushimage.MarkImageToBeSigned(self.ctx, tbs_base, insns_path, 90)
135 self.assertEqual(ret, tbs_file)
136
137 def testPriority(self):
138 """Verify diff priority values get used correctly"""
139 for prio, sprio in ((0, '00'), (9, '09'), (35, '35'), (99, '99')):
140 ret = pushimage.MarkImageToBeSigned(self.ctx, '', '', prio)
141 self.assertEquals(ret, '/tobesigned/%s,' % sprio)
142
143 def testBadPriority(self):
144 """Verify we reject bad priority values"""
145 for prio in (-10, -1, 100, 91239):
146 self.assertRaises(ValueError, pushimage.MarkImageToBeSigned, self.ctx,
147 '', '', prio)
148
149 def testTbsFile(self):
150 """Make sure the tbs file we write has useful data"""
151 WriteFile = osutils.WriteFile
152 def _write_check(*args, **kwargs):
153 # We can't mock every call, so do the actual write for most.
154 WriteFile(*args, **kwargs)
155
156 m = self.PatchObject(osutils, 'WriteFile')
157 m.side_effect = _write_check
158 pushimage.MarkImageToBeSigned(self.ctx, '', '', 50)
159 # We assume the first call is the one we care about.
160 self.assertTrue(m.called)
Mike Frysingere68da372014-02-04 03:10:45 -0500161 content = m.call_args_list[0][0][1]
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400162 self.assertIn('USER=', content)
163 self.assertIn('HOSTNAME=', content)
Mike Frysinger6791b1d2014-03-04 20:52:22 -0500164 self.assertIn('GIT_REV=1234', content)
Mike Frysingere68da372014-02-04 03:10:45 -0500165 self.assertIn('\n', content)
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400166
167 def testTbsUpload(self):
168 """Make sure we actually try to upload the file"""
169 pushimage.MarkImageToBeSigned(self.ctx, '', '', 50)
170 self.gs_mock.assertCommandContains(['cp', '--'])
171
172
173class PushImageTests(cros_test_lib.MockTestCase):
174 """Tests for PushImage()"""
175
176 def setUp(self):
177 self.gs_mock = self.StartPatcher(gs_unittest.GSContextMock())
178 self.gs_mock.SetDefaultCmdResult()
179 self.ctx = gs.GSContext()
180
181 self.mark_mock = self.PatchObject(pushimage, 'MarkImageToBeSigned')
182
183 def testBasic(self):
184 """Simple smoke test"""
Don Garrett9459c2f2014-01-22 18:20:24 -0800185 EXPECTED = {
186 'canary': [
187 'gs://chromeos-releases/canary-channel/test.board-hi/5126.0.0/'
188 'ChromeOS-recovery-R34-5126.0.0-test.board-hi.instructions'],
189 'dev': [
190 'gs://chromeos-releases/dev-channel/test.board-hi/5126.0.0/'
191 'ChromeOS-recovery-R34-5126.0.0-test.board-hi.instructions'],
192 }
193 urls = pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
194 profile='hi')
195
196 self.assertEqual(urls, EXPECTED)
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400197
198 def testBasicMock(self):
199 """Simple smoke test in mock mode"""
200 pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
201 dry_run=True, mock=True)
202
203 def testBadVersion(self):
204 """Make sure we barf on bad version strings"""
205 self.assertRaises(ValueError, pushimage.PushImage, '', '', 'asdf')
206
207 def testNoInsns(self):
208 """Boards w/out insn files should get skipped"""
Don Garrett9459c2f2014-01-22 18:20:24 -0800209 urls = pushimage.PushImage('/src', 'a bad bad board', 'R34-5126.0.0')
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400210 self.assertEqual(self.gs_mock.call_count, 0)
Don Garrett9459c2f2014-01-22 18:20:24 -0800211 self.assertEqual(urls, None)
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400212
213 def testSignTypesRecovery(self):
214 """Only sign the requested recovery type"""
Don Garrett9459c2f2014-01-22 18:20:24 -0800215 EXPECTED = {
216 'canary': [
217 'gs://chromeos-releases/canary-channel/test.board/5126.0.0/'
218 'ChromeOS-recovery-R34-5126.0.0-test.board.instructions'],
219 'dev': [
220 'gs://chromeos-releases/dev-channel/test.board/5126.0.0/'
221 'ChromeOS-recovery-R34-5126.0.0-test.board.instructions'],
222 }
223
224 urls = pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
225 sign_types=['recovery'])
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400226 self.assertEqual(self.gs_mock.call_count, 18)
227 self.assertTrue(self.mark_mock.called)
Don Garrett9459c2f2014-01-22 18:20:24 -0800228 self.assertEqual(urls, EXPECTED)
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400229
230 def testSignTypesNone(self):
231 """Verify nothing is signed when we request an unavailable type"""
Don Garrett9459c2f2014-01-22 18:20:24 -0800232 urls = pushimage.PushImage('/src', 'test.board', 'R34-5126.0.0',
233 sign_types=['nononononono'])
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400234 self.assertEqual(self.gs_mock.call_count, 16)
235 self.assertFalse(self.mark_mock.called)
Don Garrett9459c2f2014-01-22 18:20:24 -0800236 self.assertEqual(urls, {})
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400237
238
239class MainTests(cros_test_lib.MockTestCase):
240 """Tests for main()"""
241
242 def setUp(self):
243 self.PatchObject(pushimage, 'PushImage')
244
245 def testBasic(self):
246 """Simple smoke test"""
Mike Frysinger09fe0122014-02-09 02:44:05 -0500247 pushimage.main(['--board', 'test.board', '/src', '--yes'])
Mike Frysingerd13faeb2013-09-05 16:00:46 -0400248
249
250if __name__ == '__main__':
251 # Use our local copy of insns for testing as the main one is not
252 # available in the public manifest.
253 signing.INPUT_INSN_DIR = signing.TEST_INPUT_INSN_DIR
254
255 # Run the tests.
256 cros_test_lib.main(level=logging.INFO)