Merge lp:~bac/launchpad/bug-987898 into lp:launchpad

Proposed by Brad Crittenden on 2012-05-02
Status: Merged
Approved by: Gary Poster on 2012-05-02
Approved revision: no longer in the source branch.
Merged at revision: 15191
Proposed branch: lp:~bac/launchpad/bug-987898
Merge into: lp:launchpad
Diff against target: 223 lines (+36/-21)
3 files modified
lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt (+7/-7)
lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt (+7/-6)
lib/lp/bugs/tests/externalbugtracker.py (+22/-8)
To merge this branch: bzr merge lp:~bac/launchpad/bug-987898
Reviewer Review Type Date Requested Status
Gary Poster (community) 2012-05-02 Approve on 2012-05-02
Review via email: mp+104399@code.launchpad.net

Commit Message

The use of mutable class data in a mock transport caused test isolation issues. Fix by copying class data to instance data in init.

Description of the Change

= Summary =

Test isolation error causes failure when tests are run out of order
and sample data is changed.

Normally the following tests are run in this order:
lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt
lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt

However, due to shuffling in the parallel test environment they may be
run in the opposite order which exposes an error.

bugzilla-api-xmlrpc-transport.txt modifies the sample data for bug 1
which is then queried by bugzilla-xmlrpc-transport.txt. The expected
results are now modified when the ordering changes.

== Proposed fix ==

To account for the tests being run in either order, the offending data
is wildcarded with ellipsis in the doctest.

== Pre-implementation notes ==

None

== Implementation details ==

As above.

== Tests ==
bin/test -vv --load-list tests.txt

Where tests.txt contains:
lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt
lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt

== Demo and Q/A ==

N/A

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt

./lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt
     451: source exceeds 78 characters.

Will fix the lint.

To post a comment you must log in.
Gary Poster (gary) wrote :

Brad and I talked. I have admittedly discouraged taking time on digging into some bugfixes, favoring doing the known right thing rather than digging into the underlying cause that makes the known right thing necessary (see bug 987903). However, in this case, switching from sample data to factories is a known better fix, and Brad says it should take a relatively small amount of time (less than a day) and that he is game to do so. I prefer that.

Gary Poster (gary) wrote :

Very nice!

(You communicated with me on IRC that the issue here was more complicated that a sample data -> factory change; what you've done here looks good in terms of adding better isolation.)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt'
2--- lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-12-23 12:14:59 +0000
3+++ lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2012-05-02 17:37:24 +0000
4@@ -102,7 +102,7 @@
5 >>> [bug_dict] = return_value['bugs']
6 >>> for key in sorted(bug_dict):
7 ... print "%s: %s" % (key, bug_dict[key])
8- alias:
9+ alias:
10 assigned_to: test@canonical.com
11 component: GPPSystems
12 creation_time: 2008-06-10 16:19:53
13@@ -156,7 +156,7 @@
14 last_change_time: 2008-06-11 09:24:29
15 priority: P1
16 product: HeartOfGold
17- resolution:
18+ resolution:
19 see_also: []
20 severity: high
21 status: NEW
22@@ -175,7 +175,7 @@
23 >>> for bug_dict in bug_dicts:
24 ... for key in sorted(bug_dict):
25 ... print "%s: %s" % (key, bug_dict[key])
26- alias:
27+ alias:
28 assigned_to: test@canonical.com
29 component: GPPSystems
30 creation_time: 2008-06-10 16:19:53
31@@ -224,7 +224,7 @@
32 last_change_time: 2008-06-11 09:24:29
33 priority: P1
34 product: HeartOfGold
35- resolution:
36+ resolution:
37 see_also: []
38 severity: high
39 status: NEW
40@@ -239,7 +239,7 @@
41 >>> for bug_dict in bug_dicts:
42 ... for key in sorted(bug_dict):
43 ... print "%s: %s" % (key, bug_dict[key])
44- alias:
45+ alias:
46 assigned_to: test@canonical.com
47 component: GPPSystems
48 creation_time: 2008-06-10 16:19:53
49@@ -264,7 +264,7 @@
50 last_change_time: 2008-06-11 09:24:29
51 priority: P1
52 product: HeartOfGold
53- resolution:
54+ resolution:
55 see_also: []
56 severity: high
57 status: NEW
58@@ -481,7 +481,7 @@
59 >>> bug_dict = return_value['bugs'][0]
60 >>> for key in sorted(bug_dict):
61 ... print "%s: %s" % (key, bug_dict.get(key))
62- alias:
63+ alias:
64 assigned_to: test@canonical.com
65 component: GPPSystems
66 creation_time: 2008-06-10 16:19:53
67
68=== modified file 'lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt'
69--- lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2010-11-08 14:16:17 +0000
70+++ lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2012-05-02 17:37:24 +0000
71@@ -141,7 +141,7 @@
72 >>> [bug_dict] = return_value['bugs']
73 >>> for key in sorted(bug_dict):
74 ... print "%s: %s" % (key, bug_dict[key])
75- alias:
76+ alias:
77 assigned_to: test@canonical.com
78 component: GPPSystems
79 creation_time: 2008-06-10 16:19:53
80@@ -167,7 +167,7 @@
81 ... for key in sorted(bug_dict):
82 ... print "%s: %s" % (key, bug_dict[key])
83 ... print
84- alias:
85+ alias:
86 assigned_to: test@canonical.com
87 component: GPPSystems
88 creation_time: 2008-06-10 16:19:53
89@@ -216,7 +216,7 @@
90 last_change_time: 2008-06-11 09:24:29
91 priority: P1
92 product: HeartOfGold
93- resolution:
94+ resolution:
95 see_also: []
96 severity: high
97 status: NEW
98@@ -252,7 +252,7 @@
99 last_change_time: 2008-06-11 09:24:29
100 priority: P1
101 product: HeartOfGold
102- resolution:
103+ resolution:
104 see_also: []
105 severity: high
106 status: NEW
107@@ -298,7 +298,7 @@
108 last_change_time: 2008-06-11 09:24:29
109 priority: P1
110 product: HeartOfGold
111- resolution:
112+ resolution:
113 see_also: []
114 severity: high
115 status: NEW
116@@ -448,7 +448,8 @@
117
118 >>> comment = "Didn't we have a lovely time the day we went to Bangor?"
119 >>> bugzilla_transport.auth_cookie = 'open sesame'
120- >>> return_dict = server.Launchpad.add_comment({'id': 1, 'comment': comment})
121+ >>> return_dict = server.Launchpad.add_comment(
122+ ... {'id': 1, 'comment': comment})
123 >>> print return_dict['comment_id']
124 5
125
126
127=== modified file 'lib/lp/bugs/tests/externalbugtracker.py'
128--- lib/lp/bugs/tests/externalbugtracker.py 2012-01-20 16:11:11 +0000
129+++ lib/lp/bugs/tests/externalbugtracker.py 2012-05-02 17:37:24 +0000
130@@ -7,6 +7,7 @@
131
132 __metaclass__ = type
133
134+from copy import deepcopy
135 from datetime import (
136 datetime,
137 timedelta,
138@@ -390,7 +391,7 @@
139 utc_offset = 0
140 print_method_calls = False
141
142- bugs = {
143+ _bugs = {
144 1: {'alias': '',
145 'assigned_to': 'test@canonical.com',
146 'component': 'GPPSystems',
147@@ -426,14 +427,14 @@
148 }
149
150 # Map aliases onto bugs.
151- bug_aliases = {
152+ _bug_aliases = {
153 'bug-two': 2,
154 }
155
156 # Comments are mapped to bug IDs.
157 comment_id_index = 4
158 new_comment_time = datetime(2008, 6, 20, 11, 42, 42)
159- bug_comments = {
160+ _bug_comments = {
161 1: {
162 1: {'author': 'trillian',
163 'id': 1,
164@@ -467,26 +468,35 @@
165
166 # Map namespaces onto method names.
167 methods = {
168- 'Launchpad': [
169+ 'Launchpad': (
170 'add_comment',
171 'comments',
172 'get_bugs',
173 'login',
174 'time',
175 'set_link',
176- ],
177+ ),
178 'Test': ['login_required'],
179 }
180
181 # Methods that require authentication.
182- auth_required_methods = [
183+ auth_required_methods = (
184 'add_comment',
185 'login_required',
186 'set_link',
187- ]
188+ )
189
190 expired_cookie = None
191
192+ def __init__(self, *args, **kwargs):
193+ """Ensure mutable class data is copied to the instance."""
194+ # UrlLib2Transport is not a new style class so 'super' cannot be
195+ # used.
196+ UrlLib2Transport.__init__(self, *args, **kwargs)
197+ self.bugs = deepcopy(TestBugzillaXMLRPCTransport._bugs)
198+ self.bug_aliases = deepcopy(self._bug_aliases)
199+ self.bug_comments = deepcopy(self._bug_comments)
200+
201 def expireCookie(self, cookie):
202 """Mark the cookie as expired."""
203 self.expired_cookie = cookie
204@@ -800,7 +810,7 @@
205 ]
206
207 # A list of comments on bugs.
208- bug_comments = {
209+ _bug_comments = {
210 1: {
211 1: {'author': 'trillian',
212 'bug_id': 1,
213@@ -836,6 +846,10 @@
214 },
215 }
216
217+ def __init__(self, *args, **kwargs):
218+ """Ensure mutable class data is copied to the instance."""
219+ TestBugzillaXMLRPCTransport.__init__(self, *args, **kwargs)
220+
221 def version(self):
222 """Return the version of Bugzilla being used."""
223 # This is to work around the old "xmlrpclib tries to expand