Merge lp:~fginther/ubuntu-ci-services-itself/lander-binary-fixes into lp:ubuntu-ci-services-itself

Proposed by Francis Ginther
Status: Merged
Approved by: Chris Johnston
Approved revision: 291
Merged at revision: 301
Proposed branch: lp:~fginther/ubuntu-ci-services-itself/lander-binary-fixes
Merge into: lp:ubuntu-ci-services-itself
Diff against target: 159 lines (+81/-29)
2 files modified
lander/bin/lander_service_wrapper.py (+33/-10)
lander/lander/tests/test_service_wrapper.py (+48/-19)
To merge this branch: bzr merge lp:~fginther/ubuntu-ci-services-itself/lander-binary-fixes
Reviewer Review Type Date Requested Status
Chris Johnston (community) Approve
Andy Doan (community) Approve
Francis Ginther Needs Resubmitting
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+208872@code.launchpad.net

Commit message

Add support for processing the removed_binaries list and fix issue of a null added_binaries list.

Description of the change

Add support for processing the removed_binaries list and fix issue of a null added_binaries list.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:290
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/266/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/266/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Andy Doan (doanac) wrote :

46 + packages = request_parameters.get('added_binaries', '')
47 + if packages:
48 + packages = packages.split(',')

I don't think you need 47 & 48, python's split should be safe there.

63 + parameters = {'added_binaries': ','.join(packages),
64 + 'removed_binaries': None}

Bikeshedding, but most of our code is declaring dictionaries styled like:

  parameters = {
      'added_binaries': ','.join(packages),
      'removed_binaries': None
  }

20 + if added_list:
21 + for package_name in added_list.split(','):
22 + if package_name not in package_list:
23 + # Only add packages not already in the global list
24 + package_list.append(package_name)
25 +
26 + # Finally remove the list of removed binaries from the ticket request
27 + removed_list = request_parameters.get('removed_binaries', '')
28 + if removed_list:
29 + for package_name in removed_list.split(','):
30 + try:
31 + package_list.remove(package_name)
32 + except ValueError:
33 + # This is ok, multiple queued tickets could be trying
34 + # to remove the same binary.
35 + logger.info('Package to remove not found: '
36 + '{}'.format(package_list))
37 +

Not a big deal, and I could see some people advocate what you have there. But I often find it easier to use Python "sets" for things like this. I think you could simplify this to something like:

 packages = set(ticket.get_binaries())
 packages = packages + set(request_parameters.get('added_binaries', '').split(','))
 packages = packages - set(request_parameters.get('removed_binaries', '').split(','))

None of my comments are really a big deal as the code looks like it works to me. I'll just ack the MP and you can decide whether or not you want to do anything with my comments.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:290
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/273/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/273/rebuild

review: Approve (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

> 46 + packages = request_parameters.get('added_binaries', '')
> 47 + if packages:
> 48 + packages = packages.split(',')
>
> I don't think you need 47 & 48, python's split should be safe there.

added_binaries and removed_binaries can be defined as None in which case "AttributeError: 'NoneType' object has no attribute 'split'" can be raised.

> 63 + parameters = {'added_binaries': ','.join(packages),
> 64 + 'removed_binaries': None}
>
> Bikeshedding, but most of our code is declaring dictionaries styled like:
>
> parameters = {
> 'added_binaries': ','.join(packages),
> 'removed_binaries': None
> }

I wasn't aware of this, I can switch.

> 20 + if added_list:
> 21 + for package_name in added_list.split(','):
> 22 + if package_name not in package_list:
> 23 + # Only add packages not already in the global list
> 24 + package_list.append(package_name)
> 25 +
> 26 + # Finally remove the list of removed binaries from the ticket
> request
> 27 + removed_list = request_parameters.get('removed_binaries', '')
> 28 + if removed_list:
> 29 + for package_name in removed_list.split(','):
> 30 + try:
> 31 + package_list.remove(package_name)
> 32 + except ValueError:
> 33 + # This is ok, multiple queued tickets could be trying
> 34 + # to remove the same binary.
> 35 + logger.info('Package to remove not found: '
> 36 + '{}'.format(package_list))
> 37 +
>
> Not a big deal, and I could see some people advocate what you have there. But
> I often find it easier to use Python "sets" for things like this. I think you
> could simplify this to something like:
>
> packages = set(ticket.get_binaries())
> packages = packages + set(request_parameters.get('added_binaries',
> '').split(','))
> packages = packages - set(request_parameters.get('removed_binaries',
> '').split(','))

I like your recommendation here, it's much cleaner. Unit tests are in place, so it's an easy change to test.

> None of my comments are really a big deal as the code looks like it works to
> me. I'll just ack the MP and you can decide whether or not you want to do
> anything with my comments.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:290
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/275/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/275/rebuild

review: Approve (continuous-integration)
291. By Francis Ginther

Use sets for computing the binary package lists, test cleanup.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:291
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/278/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/278/rebuild

review: Approve (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

Andy, these changes should address your comments.

review: Needs Resubmitting
Revision history for this message
Andy Doan (doanac) :
review: Approve
Revision history for this message
Chris Johnston (cjohnston) wrote :

 merge approved

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lander/bin/lander_service_wrapper.py'
2--- lander/bin/lander_service_wrapper.py 2014-02-28 09:25:47 +0000
3+++ lander/bin/lander_service_wrapper.py 2014-03-03 20:15:56 +0000
4@@ -179,17 +179,36 @@
5
6
7 def _get_binary_packages(ticket, request_parameters):
8- package_list = []
9+ # Start with the set of golden binary packages
10+ package_list = set(ticket.get_binaries())
11
12 # Extract the list of added packages from the ticket request
13- added_list = request_parameters.get('added_binaries', '')
14- if len(added_list) > 0:
15- package_list = added_list.split(',')
16-
17- # Now add the set of golden binary packages
18- package_list.extend(ticket.get_binaries())
19- logger.info('Binaries all: {}'.format(package_list))
20- return package_list
21+ try:
22+ package_list = package_list | set(
23+ request_parameters.get('added_binaries', None).split(','))
24+ except AttributeError:
25+ # Expected when added_binaries is None.
26+ pass
27+
28+ # Finally remove the list of removed binaries from the ticket request
29+ try:
30+ removed_list = set(
31+ request_parameters.get('removed_binaries', None).split(','))
32+ # Log a warning if any package in the removed_binaries is not in the
33+ # package_list. This is not an error because multiple queued tickets
34+ # may attempt to remove the same package. However, This could be an
35+ # indicator of a mis-typed package name.
36+ diff_list = removed_list - package_list
37+ if diff_list:
38+ logger.warning('Package(s) to remove not found: '
39+ '{}'.format(list(diff_list)))
40+ package_list = package_list - removed_list
41+
42+ except AttributeError:
43+ # Expected when removed_binaries is None.
44+ pass
45+
46+ return list(package_list)
47
48
49 def _handle_image_builder(args):
50@@ -232,7 +251,11 @@
51 url = '%s/api/v1/ppa_copy/' % config['master']['ppa_assigner_url']
52
53 request_parameters = config['master']['request_parameters']
54- packages = request_parameters.get('added_binaries', '').split(',')
55+ try:
56+ packages = request_parameters.get('added_binaries', None).split(',')
57+ except AttributeError:
58+ # Expected when added_binaries is None.
59+ packages = []
60
61 params = {
62 'series': request_parameters['series'],
63
64=== modified file 'lander/lander/tests/test_service_wrapper.py'
65--- lander/lander/tests/test_service_wrapper.py 2014-02-28 09:25:47 +0000
66+++ lander/lander/tests/test_service_wrapper.py 2014-03-03 20:15:56 +0000
67@@ -84,44 +84,73 @@
68 @mock.patch('lander_service_wrapper.TicketApi')
69 def testGetBinaryPackagesAddedOnly(self, api):
70 '''Verify that packages from the current ticket are added.'''
71- packages = ['add_package1', 'add_package2']
72- parameters = {'added_binaries': ','.join(packages)}
73+ packages = ['add_package1']
74+ parameters = {
75+ 'added_binaries': ','.join(packages),
76+ 'removed_binaries': None}
77 api.get_binaries = mock.Mock(return_value=[])
78 actual = lander_service_wrapper._get_binary_packages(api, parameters)
79- self.assertEqual(packages, actual)
80+ self.assertItemsEqual(packages, actual)
81
82 @mock.patch('lander_service_wrapper.TicketApi')
83 def testGetBinaryPackagesNone(self, api):
84 '''Verify that no packages are added when none are specified.'''
85- packages = []
86- parameters = {'added_binaries': ','.join(packages)}
87- api.get_binaries = mock.Mock(return_value=[])
88- actual = lander_service_wrapper._get_binary_packages(api, parameters)
89- self.assertEqual(packages, actual)
90+ parameters = {
91+ 'added_binaries': None,
92+ 'removed_binaries': None}
93+ api.get_binaries = mock.Mock(return_value=[])
94+ actual = lander_service_wrapper._get_binary_packages(api, parameters)
95+ self.assertEqual([], actual)
96+
97+ @mock.patch('lander_service_wrapper.TicketApi')
98+ def testGetBinaryPackagesRemovedOnly(self, api):
99+ '''Verify that removing packages that aren't there is ok.'''
100+ packages = ['remove_package1', 'remove_package2']
101+ parameters = {
102+ 'added_binaries': None,
103+ 'removed_binaries': ','.join(packages)}
104+ api.get_binaries = mock.Mock(return_value=[])
105+ actual = lander_service_wrapper._get_binary_packages(api, parameters)
106+ self.assertEqual([], actual)
107
108 @mock.patch('lander_service_wrapper.TicketApi')
109 def testGetBinaryPackagesGlobalOnly(self, api):
110 '''Verify that packages only from the global list are added.'''
111- packages = []
112 golden = ['golden_package1', 'golden_package2']
113- parameters = {'added_binaries': ','.join(packages)}
114+ parameters = {
115+ 'added_binaries': None,
116+ 'removed_binaries': None}
117 api.get_binaries = mock.Mock(return_value=golden)
118 actual = lander_service_wrapper._get_binary_packages(api, parameters)
119- expected = packages
120- expected.extend(golden)
121- self.assertEqual(packages, actual)
122+ self.assertItemsEqual(golden, actual)
123
124 @mock.patch('lander_service_wrapper.TicketApi')
125 def testGetBinaryPackagesAddedAndGlobal(self, api):
126 '''Verify that packages from the ticket and global list are added.'''
127 packages = ['add_package1', 'add_package2']
128 golden = ['golden_package1', 'golden_package2']
129- parameters = {'added_binaries': ','.join(packages)}
130- api.get_binaries = mock.Mock(return_value=golden)
131- actual = lander_service_wrapper._get_binary_packages(api, parameters)
132- expected = packages
133- expected.extend(golden)
134- self.assertEqual(packages, actual)
135+ parameters = {
136+ 'added_binaries': ','.join(packages),
137+ 'removed_binaries': None}
138+ api.get_binaries = mock.Mock(return_value=golden)
139+ actual = lander_service_wrapper._get_binary_packages(api, parameters)
140+ expected = golden
141+ expected.extend(packages)
142+ self.assertItemsEqual(expected, actual)
143+
144+ @mock.patch('lander_service_wrapper.TicketApi')
145+ def testGetBinaryPackagesAddedRemovedAndGlobal(self, api):
146+ '''Verify that packages from all three lists are processed.'''
147+ add_packages = ['add_package1', 'add_package2']
148+ remove_packages = ['add_package1', 'golden_package2']
149+ golden = ['golden_package1', 'golden_package2']
150+ parameters = {
151+ 'added_binaries': ','.join(add_packages),
152+ 'removed_binaries': ','.join(remove_packages)}
153+ api.get_binaries = mock.Mock(return_value=golden)
154+ actual = lander_service_wrapper._get_binary_packages(api, parameters)
155+ expected = ['golden_package1', 'add_package2']
156+ self.assertItemsEqual(expected, actual)
157
158 @mock.patch('lander_service_wrapper._post')
159 def testPPAAssigner404(self, post):

Subscribers

People subscribed via source and target branches