Merge lp:~james-w/pkgme-service/review-click into lp:pkgme-service

Proposed by James Westby
Status: Merged
Approved by: James Westby
Approved revision: no longer in the source branch.
Merged at revision: 146
Proposed branch: lp:~james-w/pkgme-service/review-click
Merge into: lp:pkgme-service
Diff against target: 122 lines (+54/-11)
2 files modified
src/djpkgme/tasks.py (+15/-4)
src/djpkgme/tests/test_tasks.py (+39/-7)
To merge this branch: bzr merge lp:~james-w/pkgme-service/review-click
Reviewer Review Type Date Requested Status
Matias Bordese (community) Approve
Review via email: mp+191505@code.launchpad.net

Commit message

Turn the unpacking in to a check that the package is a valid click package.

Description of the change

Hi,

Previously if the unpack failed then there would be an oops and no
results reported to sca. This changes that so that if it fails then
it is reported as not being a valid click package.

Thanks,

James

To post a comment you must log in.
Revision history for this message
Matias Bordese (matiasb) wrote :

(06:31:50 PM) matiasb: james_w: looks good, just one question, why are the changes in l.93-98 required?
(06:32:16 PM) james_w: hmm
(06:32:23 PM) james_w: I should probably extract that in to a method
(06:32:32 PM) james_w: the code under test does
(06:32:38 PM) james_w: with TempDir() as tempdir:
(06:32:43 PM) james_w: to create a temporary directory
(06:33:06 PM) james_w: and we need to fill that tempdir with stuff as part of mocking the download/extract methods
(06:33:14 PM) james_w: there are two ways we could do this:
(06:33:32 PM) james_w: 1. fill it as a side_effect of the extract mock, exactly like it would be for real
(06:33:55 PM) james_w: but this makes it impossible to assert that the correct path is passed to the download mock
(06:34:05 PM) james_w: (l.105)
(06:34:29 PM) james_w: so I chose 2. mock the TempDir() fixture to return a known directory that is pre-filled with the stuff we need
(06:34:47 PM) james_w: it's so ugly because it's mocking a return from a class that is a content manager that returns itself
(06:34:59 PM) james_w: I couldn't find a nicer way to mock it
(06:35:03 PM) james_w: suggestions welcome
(06:36:19 PM) james_w: (the previous approach to mocking it wasn't working right, as when __enter__ was called on the TempDir object we were setting in the mock, it created a new temporary directory, meaning the files we created then weren't found by the code under test)
(06:36:45 PM) james_w: at the very least I should make that a replace_tempdir method or something to make the intent clearer
(06:37:13 PM) matiasb: hmm... I see, sounds good; no brain for suggestions at this time of the day, with that change, works for me :)

review: Approve
146. By James Westby

[r=matiasb] Turn the unpacking in to a check that the package is a valid click package.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/djpkgme/tasks.py'
2--- src/djpkgme/tasks.py 2013-10-16 13:30:05 +0000
3+++ src/djpkgme/tasks.py 2013-10-30 21:15:22 +0000
4@@ -382,16 +382,27 @@
5
6 def unpack_package(self, package_file, temp_dir):
7 dest = os.path.join(temp_dir, 'unpacked')
8- subprocess.check_call(['dpkg-deb', '-R', package_file, dest])
9- return dest
10+ passed = True
11+ try:
12+ subprocess.check_call(['dpkg-deb', '-R', package_file, dest])
13+ except subprocess.CalledProcessError:
14+ passed = False
15+ dest = None
16+ return dest, {
17+ 'description': 'Is a valid click package',
18+ 'passed': passed,
19+ }
20
21 def run(self, metadata, overrides, logger):
22 working_dirs = []
23 results = []
24 with TempDir() as temp_dir:
25 package_file = self.download_package(metadata, temp_dir.path, logger)
26- unpacked = self.unpack_package(package_file, temp_dir.path)
27- results.append(self.check_package_name_matches(metadata, unpacked))
28+ unpacked, unpack_result = self.unpack_package(
29+ package_file, temp_dir.path)
30+ results.append(unpack_result)
31+ if unpack_result['passed']:
32+ results.append(self.check_package_name_matches(metadata, unpacked))
33 return results
34
35 def check_package_name_matches(self, metadata, package):
36
37=== modified file 'src/djpkgme/tests/test_tasks.py'
38--- src/djpkgme/tests/test_tasks.py 2013-10-16 13:30:05 +0000
39+++ src/djpkgme/tests/test_tasks.py 2013-10-30 21:15:22 +0000
40@@ -4,6 +4,7 @@
41 import json
42 import logging
43 import os
44+import subprocess
45 import sys
46 import tarfile
47 import traceback
48@@ -475,8 +476,24 @@
49 package_file = 'some/package'
50 temp_dir = 'temp/dir'
51 unpack_path = os.path.join(temp_dir, 'unpacked')
52- returned_path = job.unpack_package(package_file, temp_dir)
53+ returned_path, check = job.unpack_package(package_file, temp_dir)
54 self.assertEqual(unpack_path, returned_path)
55+ self.assertEqual(
56+ check, dict(passed=True, description="Is a valid click package"))
57+ mock_call.assert_called_with(
58+ ['dpkg-deb', '-R', package_file, unpack_path])
59+
60+ @patch('djpkgme.tasks.subprocess.check_call')
61+ def test_unpack_package_fails(self, mock_call):
62+ job = ReviewClickJob()
63+ package_file = 'some/package'
64+ temp_dir = 'temp/dir'
65+ unpack_path = os.path.join(temp_dir, 'unpacked')
66+ mock_call.side_effect = subprocess.CalledProcessError(1, 'command')
67+ returned_path, check = job.unpack_package(package_file, temp_dir)
68+ self.assertEqual(None, returned_path)
69+ self.assertEqual(
70+ check, dict(passed=False, description="Is a valid click package"))
71 mock_call.assert_called_with(
72 ['dpkg-deb', '-R', package_file, unpack_path])
73
74@@ -507,11 +524,25 @@
75 result = job.check_package_name_matches(metadata, tempdir)
76 self.assertEqual(False, result['passed'])
77
78- @patch('djpkgme.tasks.ReviewClickJob.unpack_package')
79+ def make_tempdir_fixture_mock(self, path):
80+ """Return a mock suitable for mocking the fixtures.TempDir class.
81+
82+ The mock will return the passed path as the tempdir path.
83+
84+ It also handles the result being used as a context manager.
85+ """
86+ tempdir_mock = mock.Mock()
87+ path_holder = mock.Mock()
88+ path_holder.path = path
89+ tempdir_mock.__enter__ = mock.Mock(return_value=path_holder)
90+ tempdir_mock.__exit__ = mock.Mock(return_value=False)
91+ return tempdir_mock
92+
93+ @patch('djpkgme.tasks.subprocess.check_call')
94 @patch('djpkgme.tasks.ReviewClickJob.download_package')
95 @patch('djpkgme.tasks.TempDir')
96 def test_integration(self, mock_tempdir, mock_download_package,
97- mock_unpack_package):
98+ mock_call):
99 tempdir = self.useFixture(TempDir())
100 downloaded_path = 'some/path'
101 unpacked_path = os.path.join(tempdir.path, 'unpacked')
102@@ -521,15 +552,16 @@
103 logger = logging.getLogger()
104 self.make_manifest_file(dict(name=package_fullname), unpacked_path)
105
106- mock_tempdir.return_value = tempdir
107+ mock_tempdir.return_value = self.make_tempdir_fixture_mock(
108+ tempdir.path)
109 mock_download_package.return_value = downloaded_path
110- mock_unpack_package.return_value = unpacked_path
111
112 job = ReviewClickJob()
113 results = job.run(metadata, {}, logger)
114
115 mock_download_package.assert_called_with(
116 metadata, tempdir.path, logger)
117- mock_unpack_package.assert_called_with(downloaded_path, tempdir.path)
118- self.assertEqual(1, len(results))
119+ mock_call.assert_called_with(
120+ ['dpkg-deb', '-R', downloaded_path, unpacked_path])
121+ self.assertEqual(2, len(results))
122 self.assertEqual(True, results[0]['passed'])

Subscribers

People subscribed via source and target branches