Merge lp:~smoser/curtin/trunk.subp-more-tests into lp:~curtin-dev/curtin/trunk

Proposed by Scott Moser
Status: Merged
Merged at revision: 422
Proposed branch: lp:~smoser/curtin/trunk.subp-more-tests
Merge into: lp:~curtin-dev/curtin/trunk
Diff against target: 123 lines (+81/-14)
1 file modified
tests/unittests/test_util.py (+81/-14)
To merge this branch: bzr merge lp:~smoser/curtin/trunk.subp-more-tests
Reviewer Review Type Date Requested Status
Ryan Harper (community) Approve
Server Team CI bot continuous-integration Needs Fixing
Review via email: mp+304297@code.launchpad.net

Commit message

tests: more subp tests

Better test util.subp, exercising its target=/ and target=/some/root, and also verifying that exception is raised if subprocess exits non-zero.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ryan Harper (raharper) wrote :

Nice additional tests.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'tests/unittests/test_util.py'
--- tests/unittests/test_util.py 2016-08-08 18:40:17 +0000
+++ tests/unittests/test_util.py 2016-08-29 20:00:46 +0000
@@ -145,6 +145,8 @@
145145
146 stdin2err = ['bash', '-c', 'cat >&2']146 stdin2err = ['bash', '-c', 'cat >&2']
147 stdin2out = ['cat']147 stdin2out = ['cat']
148 bin_true = ['bash', '-c', ':']
149 exit_with_value = ['bash', '-c', 'exit ${1:-0}', 'test_subp_exit_val']
148 utf8_invalid = b'ab\xaadef'150 utf8_invalid = b'ab\xaadef'
149 utf8_valid = b'start \xc3\xa9 end'151 utf8_valid = b'start \xc3\xa9 end'
150 utf8_valid_2 = b'd\xc3\xa9j\xc8\xa7'152 utf8_valid_2 = b'd\xc3\xa9j\xc8\xa7'
@@ -161,6 +163,27 @@
161 (out, _err) = util.subp(cmd, capture=True)163 (out, _err) = util.subp(cmd, capture=True)
162 self.assertEqual(out, self.utf8_valid_2.decode('utf-8'))164 self.assertEqual(out, self.utf8_valid_2.decode('utf-8'))
163165
166
167 def test_subp_target_as_different_fors_of_slash_works(self):
168 # passing target=/ in any form should work.
169
170 # it is assumed that if chroot was used, then test case would
171 # fail unless user was root ('chroot /' is still priviledged)
172 util.subp(self.bin_true, target="/")
173 util.subp(self.bin_true, target="//")
174 util.subp(self.bin_true, target="///")
175 util.subp(self.bin_true, target="//etc/..//")
176
177 def test_subp_exit_nonzero_raises(self):
178 exc = None
179 try:
180 util.subp(self.exit_with_value + ["9"])
181 except util.ProcessExecutionError as e:
182 self.assertEqual(9, e.exit_code)
183 exc = e
184
185 self.assertNotEqual(exc, None)
186
164 def test_subp_respects_decode_false(self):187 def test_subp_respects_decode_false(self):
165 (out, err) = util.subp(self.stdin2out, capture=True, decode=False,188 (out, err) = util.subp(self.stdin2out, capture=True, decode=False,
166 data=self.utf8_valid)189 data=self.utf8_valid)
@@ -203,24 +226,68 @@
203 self.assertEqual(err, None)226 self.assertEqual(err, None)
204 self.assertEqual(out, None)227 self.assertEqual(out, None)
205228
206 @mock.patch("curtin.util.subprocess.Popen")229 def _subp_wrap_popen(self, cmd, kwargs,
207 def test_with_target_gets_chroot(self, m_popen):230 returncode=0, stdout=b'', stderr=b''):
208 noexist_pname = "mocked-away-does-not-matter"231 # mocks the subprocess.Popen as expected from subp
209 sp = mock.Mock()232 # checks that subp returned the output of 'communicate' and
210 m_popen.return_value = sp233 # returns the (args, kwargs) that Popen() was called with.
211 sp.communicate.return_value = (b'out-foo', b'err-foo')234
212 sp.returncode = 0235 capture = kwargs.get('capture')
213236
214 ret = util.subp([noexist_pname], target="/mytarget",237 with mock.patch("curtin.util.subprocess.Popen") as m_popen:
215 capture=True, decode=None)238 sp = mock.Mock()
239 m_popen.return_value = sp
240 if capture:
241 sp.communicate.return_value = (stdout, stderr)
242 else:
243 sp.communicate.return_value = (None, None)
244 sp.returncode = returncode
245 ret = util.subp(cmd, **kwargs)
246
247 # popen should only ever be called once
216 self.assertTrue(m_popen.called)248 self.assertTrue(m_popen.called)
217 self.assertEqual(1, m_popen.call_count)249 self.assertEqual(1, m_popen.call_count)
250 # communicate() needs to have been called.
218 self.assertTrue(sp.communicate.called)251 self.assertTrue(sp.communicate.called)
219252
220 # Popen should have been called with chroot253 if capture:
221 args, kwargs = m_popen.call_args254 # capture response is decoded if decode is not False
222 self.assertEqual(['chroot', '/mytarget', noexist_pname], args[0])255 decode = kwargs.get('decode', "replace")
223 self.assertEqual((b'out-foo', b'err-foo'), ret)256 if decode is False:
257 self.assertEqual(stdout.decode(stdout, stderr), ret)
258 else:
259 self.assertEqual((stdout.decode(errors=decode),
260 stderr.decode(errors=decode)), ret)
261 else:
262 # if capture is false, then return is None, None
263 self.assertEqual((None, None), ret)
264
265 popen_args, popen_kwargs = m_popen.call_args
266
267 # if target is not provided or is /, chroot should not be used
268 target = util.target_path(kwargs.get('target', None))
269 if target == "/":
270 self.assertEqual(cmd, popen_args[0])
271 else:
272 self.assertEqual(['chroot', target] + list(cmd), popen_args[0])
273 return m_popen.call_args
274
275 def test_with_target_gets_chroot(self):
276 args, kwargs = self._subp_wrap_popen(["my-command"],
277 {'target': "/mytarget"})
278 self.assertIn('chroot', args[0])
279
280 def test_with_target_as_slash_does_not_chroot(self):
281 args, kwargs = self._subp_wrap_popen(
282 ['whatever'], {'capture': True, 'target': "/"})
283 self.assertNotIn('chroot', args[0])
284
285 def test_with_no_target_does_not_chroot(self):
286 args, kwargs = self._subp_wrap_popen(['whatever'], {'capture': True})
287 # note this path is reasonably tested with all of the above
288 # tests that do not mock Popen as if we did try to chroot the
289 # unit tests would fail unless they were run as root.
290 self.assertNotIn('chroot', args[0])
224291
225292
226class TestHuman2Bytes(TestCase):293class TestHuman2Bytes(TestCase):

Subscribers

People subscribed via source and target branches