Merge lp:~adeuring/launchpad/bug-594247-unittests-for-searchtasks-4 into lp:launchpad
- bug-594247-unittests-for-searchtasks-4
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Gavin Panella |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11864 |
Proposed branch: | lp:~adeuring/launchpad/bug-594247-unittests-for-searchtasks-4 |
Merge into: | lp:launchpad |
Diff against target: |
733 lines (+302/-115) 4 files modified
lib/lp/bugs/interfaces/bugtask.py (+2/-2) lib/lp/bugs/tests/test_bugtask_search.py (+267/-113) lib/lp/testing/factory.py (+11/-0) lib/lp/testing/tests/test_factory.py (+22/-0) |
To merge this branch: | bzr merge lp:~adeuring/launchpad/bug-594247-unittests-for-searchtasks-4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+39991@code.launchpad.net |
Commit message
unit tests of BugtaskSet.search() and BugTaskSet.
Description of the change
new attempt, hopefully without merge conflict and an overly huge diff...
This branch adds more unit tests for BugTaskSet.search() and for
BugTaskSet.
BugTaskSearchParams not covered.
Aside for these additional tests, I added a new method
assertSearchFinds() (suggested by Gavin in a previous review
of these tests), which makes reading the tests slightly less
boring and a bit more readable. Working on this change, I
noticed that one tests missed an assert...
Working on tests to find bugs being created or modified after a
given time, I noticed that it was possible to pass the parameters
created_since and modified_since to the constructor of
BugTaskSearchpa
and modified_since were always set to None. This is now fixed.
One test needed access to a product which is not the main
target of the current test; an already existing test modifies
the bug task of this "other target"
(changeStatusOf
this "other bugtask" into a separate method
(findBugtaskFor
ini comparison with the old implementation to find the "other
bugtask".
test: ./bin/test -vvt test_bugtask_search
no lint.
Preview Diff
1 | === modified file 'lib/lp/bugs/interfaces/bugtask.py' | |||
2 | --- lib/lp/bugs/interfaces/bugtask.py 2010-11-03 14:31:33 +0000 | |||
3 | +++ lib/lp/bugs/interfaces/bugtask.py 2010-11-04 15:56:18 +0000 | |||
4 | @@ -1188,8 +1188,8 @@ | |||
5 | 1188 | self.hardware_is_linked_to_bug = hardware_is_linked_to_bug | 1188 | self.hardware_is_linked_to_bug = hardware_is_linked_to_bug |
6 | 1189 | self.linked_branches = linked_branches | 1189 | self.linked_branches = linked_branches |
7 | 1190 | self.structural_subscriber = structural_subscriber | 1190 | self.structural_subscriber = structural_subscriber |
10 | 1191 | self.modified_since = None | 1191 | self.modified_since = modified_since |
11 | 1192 | self.created_since = None | 1192 | self.created_since = created_since |
12 | 1193 | 1193 | ||
13 | 1194 | def setProduct(self, product): | 1194 | def setProduct(self, product): |
14 | 1195 | """Set the upstream context on which to filter the search.""" | 1195 | """Set the upstream context on which to filter the search.""" |
15 | 1196 | 1196 | ||
16 | === modified file 'lib/lp/bugs/tests/test_bugtask_search.py' | |||
17 | --- lib/lp/bugs/tests/test_bugtask_search.py 2010-10-29 13:00:57 +0000 | |||
18 | +++ lib/lp/bugs/tests/test_bugtask_search.py 2010-11-04 15:56:18 +0000 | |||
19 | @@ -25,6 +25,7 @@ | |||
20 | 25 | 25 | ||
21 | 26 | from lp.bugs.interfaces.bugattachment import BugAttachmentType | 26 | from lp.bugs.interfaces.bugattachment import BugAttachmentType |
22 | 27 | from lp.bugs.interfaces.bugtask import ( | 27 | from lp.bugs.interfaces.bugtask import ( |
23 | 28 | BugBranchSearch, | ||
24 | 28 | BugTaskImportance, | 29 | BugTaskImportance, |
25 | 29 | BugTaskSearchParams, | 30 | BugTaskSearchParams, |
26 | 30 | BugTaskStatus, | 31 | BugTaskStatus, |
27 | @@ -53,29 +54,30 @@ | |||
28 | 53 | super(SearchTestBase, self).setUp() | 54 | super(SearchTestBase, self).setUp() |
29 | 54 | self.bugtask_set = getUtility(IBugTaskSet) | 55 | self.bugtask_set = getUtility(IBugTaskSet) |
30 | 55 | 56 | ||
31 | 57 | def assertSearchFinds(self, params, expected_bugtasks): | ||
32 | 58 | # Run a search for the given search parameters and check if | ||
33 | 59 | # the result matches the expected bugtasks. | ||
34 | 60 | search_result = self.runSearch(params) | ||
35 | 61 | expected = self.resultValuesForBugtasks(expected_bugtasks) | ||
36 | 62 | self.assertEqual(expected, search_result) | ||
37 | 63 | |||
38 | 56 | def test_search_all_bugtasks_for_target(self): | 64 | def test_search_all_bugtasks_for_target(self): |
39 | 57 | # BugTaskSet.search() returns all bug tasks for a given bug | 65 | # BugTaskSet.search() returns all bug tasks for a given bug |
40 | 58 | # target, if only the bug target is passed as a search parameter. | 66 | # target, if only the bug target is passed as a search parameter. |
41 | 59 | params = self.getBugTaskSearchParams(user=None) | 67 | params = self.getBugTaskSearchParams(user=None) |
45 | 60 | search_result = self.runSearch(params) | 68 | self.assertSearchFinds(params, self.bugtasks) |
43 | 61 | expected = self.resultValuesForBugtasks(self.bugtasks) | ||
44 | 62 | self.assertEqual(expected, search_result) | ||
46 | 63 | 69 | ||
47 | 64 | def test_private_bug_in_search_result(self): | 70 | def test_private_bug_in_search_result(self): |
48 | 65 | # Private bugs are not included in search results for anonymous users. | 71 | # Private bugs are not included in search results for anonymous users. |
49 | 66 | with person_logged_in(self.owner): | 72 | with person_logged_in(self.owner): |
50 | 67 | self.bugtasks[-1].bug.setPrivate(True, self.owner) | 73 | self.bugtasks[-1].bug.setPrivate(True, self.owner) |
51 | 68 | params = self.getBugTaskSearchParams(user=None) | 74 | params = self.getBugTaskSearchParams(user=None) |
55 | 69 | search_result = self.runSearch(params) | 75 | self.assertSearchFinds(params, self.bugtasks[:-1]) |
53 | 70 | expected = self.resultValuesForBugtasks(self.bugtasks)[:-1] | ||
54 | 71 | self.assertEqual(expected, search_result) | ||
56 | 72 | 76 | ||
57 | 73 | # Private bugs are not included in search results for ordinary users. | 77 | # Private bugs are not included in search results for ordinary users. |
58 | 74 | user = self.factory.makePerson() | 78 | user = self.factory.makePerson() |
59 | 75 | params = self.getBugTaskSearchParams(user=user) | 79 | params = self.getBugTaskSearchParams(user=user) |
63 | 76 | search_result = self.runSearch(params) | 80 | self.assertSearchFinds(params, self.bugtasks[:-1]) |
61 | 77 | expected = self.resultValuesForBugtasks(self.bugtasks)[:-1] | ||
62 | 78 | self.assertEqual(expected, search_result) | ||
64 | 79 | 81 | ||
65 | 80 | # If the user is subscribed to the bug, it is included in the | 82 | # If the user is subscribed to the bug, it is included in the |
66 | 81 | # search result. | 83 | # search result. |
67 | @@ -83,16 +85,12 @@ | |||
68 | 83 | with person_logged_in(self.owner): | 85 | with person_logged_in(self.owner): |
69 | 84 | self.bugtasks[-1].bug.subscribe(user, self.owner) | 86 | self.bugtasks[-1].bug.subscribe(user, self.owner) |
70 | 85 | params = self.getBugTaskSearchParams(user=user) | 87 | params = self.getBugTaskSearchParams(user=user) |
74 | 86 | search_result = self.runSearch(params) | 88 | self.assertSearchFinds(params, self.bugtasks) |
72 | 87 | expected = self.resultValuesForBugtasks(self.bugtasks) | ||
73 | 88 | self.assertEqual(expected, search_result) | ||
75 | 89 | 89 | ||
76 | 90 | # Private bugs are included in search results for admins. | 90 | # Private bugs are included in search results for admins. |
77 | 91 | admin = getUtility(IPersonSet).getByEmail('foo.bar@canonical.com') | 91 | admin = getUtility(IPersonSet).getByEmail('foo.bar@canonical.com') |
78 | 92 | params = self.getBugTaskSearchParams(user=admin) | 92 | params = self.getBugTaskSearchParams(user=admin) |
82 | 93 | search_result = self.runSearch(params) | 93 | self.assertSearchFinds(params, self.bugtasks) |
80 | 94 | expected = self.resultValuesForBugtasks(self.bugtasks) | ||
81 | 95 | self.assertEqual(expected, search_result) | ||
83 | 96 | 94 | ||
84 | 97 | def test_search_by_bug_reporter(self): | 95 | def test_search_by_bug_reporter(self): |
85 | 98 | # Search results can be limited to bugs filed by a given person. | 96 | # Search results can be limited to bugs filed by a given person. |
86 | @@ -100,9 +98,7 @@ | |||
87 | 100 | reporter = bugtask.bug.owner | 98 | reporter = bugtask.bug.owner |
88 | 101 | params = self.getBugTaskSearchParams( | 99 | params = self.getBugTaskSearchParams( |
89 | 102 | user=None, bug_reporter=reporter) | 100 | user=None, bug_reporter=reporter) |
93 | 103 | search_result = self.runSearch(params) | 101 | self.assertSearchFinds(params, [bugtask]) |
91 | 104 | expected = self.resultValuesForBugtasks([bugtask]) | ||
92 | 105 | self.assertEqual(expected, search_result) | ||
94 | 106 | 102 | ||
95 | 107 | def test_search_by_bug_commenter(self): | 103 | def test_search_by_bug_commenter(self): |
96 | 108 | # Search results can be limited to bugs having a comment from a | 104 | # Search results can be limited to bugs having a comment from a |
97 | @@ -118,9 +114,7 @@ | |||
98 | 118 | expected.bug.newMessage(owner=commenter, content='a comment') | 114 | expected.bug.newMessage(owner=commenter, content='a comment') |
99 | 119 | params = self.getBugTaskSearchParams( | 115 | params = self.getBugTaskSearchParams( |
100 | 120 | user=None, bug_commenter=commenter) | 116 | user=None, bug_commenter=commenter) |
104 | 121 | search_result = self.runSearch(params) | 117 | self.assertSearchFinds(params, [expected]) |
102 | 122 | expected = self.resultValuesForBugtasks([expected]) | ||
103 | 123 | self.assertEqual(expected, search_result) | ||
105 | 124 | 118 | ||
106 | 125 | def test_search_by_person_affected_by_bug(self): | 119 | def test_search_by_person_affected_by_bug(self): |
107 | 126 | # Search results can be limited to bugs which affect a given person. | 120 | # Search results can be limited to bugs which affect a given person. |
108 | @@ -130,9 +124,7 @@ | |||
109 | 130 | expected.bug.markUserAffected(affected_user) | 124 | expected.bug.markUserAffected(affected_user) |
110 | 131 | params = self.getBugTaskSearchParams( | 125 | params = self.getBugTaskSearchParams( |
111 | 132 | user=None, affected_user=affected_user) | 126 | user=None, affected_user=affected_user) |
115 | 133 | search_result = self.runSearch(params) | 127 | self.assertSearchFinds(params, [expected]) |
113 | 134 | expected = self.resultValuesForBugtasks([expected]) | ||
114 | 135 | self.assertEqual(expected, search_result) | ||
116 | 136 | 128 | ||
117 | 137 | def test_search_by_bugtask_assignee(self): | 129 | def test_search_by_bugtask_assignee(self): |
118 | 138 | # Search results can be limited to bugtask assigned to a given | 130 | # Search results can be limited to bugtask assigned to a given |
119 | @@ -142,9 +134,7 @@ | |||
120 | 142 | with person_logged_in(assignee): | 134 | with person_logged_in(assignee): |
121 | 143 | expected.transitionToAssignee(assignee) | 135 | expected.transitionToAssignee(assignee) |
122 | 144 | params = self.getBugTaskSearchParams(user=None, assignee=assignee) | 136 | params = self.getBugTaskSearchParams(user=None, assignee=assignee) |
126 | 145 | search_result = self.runSearch(params) | 137 | self.assertSearchFinds(params, [expected]) |
124 | 146 | expected = self.resultValuesForBugtasks([expected]) | ||
125 | 147 | self.assertEqual(expected, search_result) | ||
127 | 148 | 138 | ||
128 | 149 | def test_search_by_bug_subscriber(self): | 139 | def test_search_by_bug_subscriber(self): |
129 | 150 | # Search results can be limited to bugs to which a given person | 140 | # Search results can be limited to bugs to which a given person |
130 | @@ -154,9 +144,69 @@ | |||
131 | 154 | with person_logged_in(subscriber): | 144 | with person_logged_in(subscriber): |
132 | 155 | expected.bug.subscribe(subscriber, subscribed_by=subscriber) | 145 | expected.bug.subscribe(subscriber, subscribed_by=subscriber) |
133 | 156 | params = self.getBugTaskSearchParams(user=None, subscriber=subscriber) | 146 | params = self.getBugTaskSearchParams(user=None, subscriber=subscriber) |
137 | 157 | search_result = self.runSearch(params) | 147 | self.assertSearchFinds(params, [expected]) |
138 | 158 | expected = self.resultValuesForBugtasks([expected]) | 148 | |
139 | 159 | self.assertEqual(expected, search_result) | 149 | def subscribeToTarget(self, subscriber): |
140 | 150 | # Subscribe the given person to the search target. | ||
141 | 151 | with person_logged_in(subscriber): | ||
142 | 152 | self.searchtarget.addSubscription( | ||
143 | 153 | subscriber, subscribed_by=subscriber) | ||
144 | 154 | |||
145 | 155 | def _findBugtaskForOtherProduct(self, bugtask, main_product): | ||
146 | 156 | # Return the bugtask for the product that is not related to the | ||
147 | 157 | # main bug target. | ||
148 | 158 | # | ||
149 | 159 | # The default bugtasks of this test suite are created by | ||
150 | 160 | # ObjectFactory.makeBugTask() as follows: | ||
151 | 161 | # - a new bug is created having a new product as the target. | ||
152 | 162 | # - another bugtask is created for self.searchtarget (or, | ||
153 | 163 | # when self.searchtarget is a milestone, for the product | ||
154 | 164 | # of the milestone) | ||
155 | 165 | # This method returns the bug task for the product that is not | ||
156 | 166 | # related to the main bug target. | ||
157 | 167 | bug = bugtask.bug | ||
158 | 168 | for other_task in bug.bugtasks: | ||
159 | 169 | other_target = other_task.target | ||
160 | 170 | if (IProduct.providedBy(other_target) | ||
161 | 171 | and other_target != main_product): | ||
162 | 172 | return other_task | ||
163 | 173 | self.fail( | ||
164 | 174 | 'No bug task found for a product that is not the target of ' | ||
165 | 175 | 'the main test bugtask.') | ||
166 | 176 | |||
167 | 177 | def findBugtaskForOtherProduct(self, bugtask): | ||
168 | 178 | # Return the bugtask for the product that is not related to the | ||
169 | 179 | # main bug target. | ||
170 | 180 | # | ||
171 | 181 | # This method must ober overridden for product related tests. | ||
172 | 182 | return self._findBugtaskForOtherProduct(bugtask, None) | ||
173 | 183 | |||
174 | 184 | def test_search_by_structural_subscriber(self): | ||
175 | 185 | # Search results can be limited to bugs with a bug target to which | ||
176 | 186 | # a given person has a structural subscription. | ||
177 | 187 | subscriber = self.factory.makePerson() | ||
178 | 188 | # If the given person is not subscribed, no bugtasks are returned. | ||
179 | 189 | params = self.getBugTaskSearchParams( | ||
180 | 190 | user=None, structural_subscriber=subscriber) | ||
181 | 191 | self.assertSearchFinds(params, []) | ||
182 | 192 | # When the person is subscribed, all bugtasks are returned. | ||
183 | 193 | self.subscribeToTarget(subscriber) | ||
184 | 194 | params = self.getBugTaskSearchParams( | ||
185 | 195 | user=None, structural_subscriber=subscriber) | ||
186 | 196 | self.assertSearchFinds(params, self.bugtasks) | ||
187 | 197 | |||
188 | 198 | # Searching for a structural subscriber does not return a bugtask, | ||
189 | 199 | # if the person is subscribed to another target than the main | ||
190 | 200 | # bug target. | ||
191 | 201 | other_subscriber = self.factory.makePerson() | ||
192 | 202 | other_bugtask = self.findBugtaskForOtherProduct(self.bugtasks[0]) | ||
193 | 203 | other_target = other_bugtask.target | ||
194 | 204 | with person_logged_in(other_subscriber): | ||
195 | 205 | other_target.addSubscription( | ||
196 | 206 | other_subscriber, subscribed_by=other_subscriber) | ||
197 | 207 | params = self.getBugTaskSearchParams( | ||
198 | 208 | user=None, structural_subscriber=other_subscriber) | ||
199 | 209 | self.assertSearchFinds(params, []) | ||
200 | 160 | 210 | ||
201 | 161 | def test_search_by_bug_attachment(self): | 211 | def test_search_by_bug_attachment(self): |
202 | 162 | # Search results can be limited to bugs having attachments of | 212 | # Search results can be limited to bugs having attachments of |
203 | @@ -171,23 +221,17 @@ | |||
204 | 171 | # We can search for bugs with non-patch attachments... | 221 | # We can search for bugs with non-patch attachments... |
205 | 172 | params = self.getBugTaskSearchParams( | 222 | params = self.getBugTaskSearchParams( |
206 | 173 | user=None, attachmenttype=BugAttachmentType.UNSPECIFIED) | 223 | user=None, attachmenttype=BugAttachmentType.UNSPECIFIED) |
210 | 174 | search_result = self.runSearch(params) | 224 | self.assertSearchFinds(params, self.bugtasks[:1]) |
208 | 175 | expected = self.resultValuesForBugtasks(self.bugtasks[:1]) | ||
209 | 176 | self.assertEqual(expected, search_result) | ||
211 | 177 | # ... for bugs with patches... | 225 | # ... for bugs with patches... |
212 | 178 | params = self.getBugTaskSearchParams( | 226 | params = self.getBugTaskSearchParams( |
213 | 179 | user=None, attachmenttype=BugAttachmentType.PATCH) | 227 | user=None, attachmenttype=BugAttachmentType.PATCH) |
217 | 180 | search_result = self.runSearch(params) | 228 | self.assertSearchFinds(params, self.bugtasks[1:2]) |
215 | 181 | expected = self.resultValuesForBugtasks(self.bugtasks[1:2]) | ||
216 | 182 | self.assertEqual(expected, search_result) | ||
218 | 183 | # and for bugs with patches or attachments | 229 | # and for bugs with patches or attachments |
219 | 184 | params = self.getBugTaskSearchParams( | 230 | params = self.getBugTaskSearchParams( |
220 | 185 | user=None, attachmenttype=any( | 231 | user=None, attachmenttype=any( |
221 | 186 | BugAttachmentType.PATCH, | 232 | BugAttachmentType.PATCH, |
222 | 187 | BugAttachmentType.UNSPECIFIED)) | 233 | BugAttachmentType.UNSPECIFIED)) |
226 | 188 | search_result = self.runSearch(params) | 234 | self.assertSearchFinds(params, self.bugtasks[:2]) |
224 | 189 | expected = self.resultValuesForBugtasks(self.bugtasks[:2]) | ||
225 | 190 | self.assertEqual(expected, search_result) | ||
227 | 191 | 235 | ||
228 | 192 | def setUpFullTextSearchTests(self): | 236 | def setUpFullTextSearchTests(self): |
229 | 193 | # Set text fields indexed by Bug.fti, BugTask.fti or | 237 | # Set text fields indexed by Bug.fti, BugTask.fti or |
230 | @@ -205,40 +249,30 @@ | |||
231 | 205 | self.setUpFullTextSearchTests() | 249 | self.setUpFullTextSearchTests() |
232 | 206 | params = self.getBugTaskSearchParams( | 250 | params = self.getBugTaskSearchParams( |
233 | 207 | user=None, searchtext='one title') | 251 | user=None, searchtext='one title') |
237 | 208 | search_result = self.runSearch(params) | 252 | self.assertSearchFinds(params, self.bugtasks[:1]) |
235 | 209 | expected = self.resultValuesForBugtasks(self.bugtasks[:1]) | ||
236 | 210 | self.assertEqual(expected, search_result) | ||
238 | 211 | # ... by BugTask.fti ... | 253 | # ... by BugTask.fti ... |
239 | 212 | params = self.getBugTaskSearchParams( | 254 | params = self.getBugTaskSearchParams( |
240 | 213 | user=None, searchtext='two explanation') | 255 | user=None, searchtext='two explanation') |
244 | 214 | search_result = self.runSearch(params) | 256 | self.assertSearchFinds(params, self.bugtasks[1:2]) |
242 | 215 | expected = self.resultValuesForBugtasks(self.bugtasks[1:2]) | ||
243 | 216 | self.assertEqual(expected, search_result) | ||
245 | 217 | # ...and by MessageChunk.fti | 257 | # ...and by MessageChunk.fti |
246 | 218 | params = self.getBugTaskSearchParams( | 258 | params = self.getBugTaskSearchParams( |
247 | 219 | user=None, searchtext='three comment') | 259 | user=None, searchtext='three comment') |
251 | 220 | search_result = self.runSearch(params) | 260 | self.assertSearchFinds(params, self.bugtasks[2:3]) |
249 | 221 | expected = self.resultValuesForBugtasks(self.bugtasks[2:3]) | ||
250 | 222 | self.assertEqual(expected, search_result) | ||
252 | 223 | 261 | ||
253 | 224 | def test_fast_fulltext_search(self): | 262 | def test_fast_fulltext_search(self): |
254 | 225 | # Fast full text searches find text indexed by Bug.fti... | 263 | # Fast full text searches find text indexed by Bug.fti... |
255 | 226 | self.setUpFullTextSearchTests() | 264 | self.setUpFullTextSearchTests() |
256 | 227 | params = self.getBugTaskSearchParams( | 265 | params = self.getBugTaskSearchParams( |
257 | 228 | user=None, fast_searchtext='one title') | 266 | user=None, fast_searchtext='one title') |
261 | 229 | search_result = self.runSearch(params) | 267 | self.assertSearchFinds(params, self.bugtasks[:1]) |
259 | 230 | expected = self.resultValuesForBugtasks(self.bugtasks[:1]) | ||
260 | 231 | self.assertEqual(expected, search_result) | ||
262 | 232 | # ... but not text indexed by BugTask.fti ... | 268 | # ... but not text indexed by BugTask.fti ... |
263 | 233 | params = self.getBugTaskSearchParams( | 269 | params = self.getBugTaskSearchParams( |
264 | 234 | user=None, fast_searchtext='two explanation') | 270 | user=None, fast_searchtext='two explanation') |
267 | 235 | search_result = self.runSearch(params) | 271 | self.assertSearchFinds(params, []) |
266 | 236 | self.assertEqual([], search_result) | ||
268 | 237 | # ..or by MessageChunk.fti | 272 | # ..or by MessageChunk.fti |
269 | 238 | params = self.getBugTaskSearchParams( | 273 | params = self.getBugTaskSearchParams( |
270 | 239 | user=None, fast_searchtext='three comment') | 274 | user=None, fast_searchtext='three comment') |
273 | 240 | search_result = self.runSearch(params) | 275 | self.assertSearchFinds(params, []) |
272 | 241 | self.assertEqual([], search_result) | ||
274 | 242 | 276 | ||
275 | 243 | def test_has_no_upstream_bugtask(self): | 277 | def test_has_no_upstream_bugtask(self): |
276 | 244 | # Search results can be limited to bugtasks of bugs that do | 278 | # Search results can be limited to bugtasks of bugs that do |
277 | @@ -258,13 +292,13 @@ | |||
278 | 258 | IDistributionSourcePackage.providedBy(self.searchtarget)): | 292 | IDistributionSourcePackage.providedBy(self.searchtarget)): |
279 | 259 | if IDistribution.providedBy(self.searchtarget): | 293 | if IDistribution.providedBy(self.searchtarget): |
280 | 260 | bug = self.factory.makeBug(distribution=self.searchtarget) | 294 | bug = self.factory.makeBug(distribution=self.searchtarget) |
282 | 261 | expected = self.resultValuesForBugtasks([bug.default_bugtask]) | 295 | expected = [bug.default_bugtask] |
283 | 262 | else: | 296 | else: |
284 | 263 | bug = self.factory.makeBug( | 297 | bug = self.factory.makeBug( |
285 | 264 | distribution=self.searchtarget.distribution) | 298 | distribution=self.searchtarget.distribution) |
286 | 265 | bugtask = self.factory.makeBugTask( | 299 | bugtask = self.factory.makeBugTask( |
287 | 266 | bug=bug, target=self.searchtarget) | 300 | bug=bug, target=self.searchtarget) |
289 | 267 | expected = self.resultValuesForBugtasks([bugtask]) | 301 | expected = [bugtask] |
290 | 268 | else: | 302 | else: |
291 | 269 | # Bugs without distribution related bugtasks have always at | 303 | # Bugs without distribution related bugtasks have always at |
292 | 270 | # least one product related bugtask, hence a | 304 | # least one product related bugtask, hence a |
293 | @@ -273,23 +307,14 @@ | |||
294 | 273 | expected = [] | 307 | expected = [] |
295 | 274 | params = self.getBugTaskSearchParams( | 308 | params = self.getBugTaskSearchParams( |
296 | 275 | user=None, has_no_upstream_bugtask=True) | 309 | user=None, has_no_upstream_bugtask=True) |
299 | 276 | search_result = self.runSearch(params) | 310 | self.assertSearchFinds(params, expected) |
298 | 277 | self.assertEqual(expected, search_result) | ||
300 | 278 | 311 | ||
301 | 279 | def changeStatusOfBugTaskForOtherProduct(self, bugtask, new_status): | 312 | def changeStatusOfBugTaskForOtherProduct(self, bugtask, new_status): |
302 | 280 | # Change the status of another bugtask of the same bug to the | 313 | # Change the status of another bugtask of the same bug to the |
303 | 281 | # given status. | 314 | # given status. |
315 | 282 | bug = bugtask.bug | 315 | other_task = self.findBugtaskForOtherProduct(bugtask) |
316 | 283 | for other_task in bug.bugtasks: | 316 | with person_logged_in(other_task.target.owner): |
317 | 284 | other_target = other_task.target | 317 | other_task.transitionToStatus(new_status, other_task.target.owner) |
307 | 285 | if other_task != bugtask and IProduct.providedBy(other_target): | ||
308 | 286 | with person_logged_in(other_target.owner): | ||
309 | 287 | other_task.transitionToStatus( | ||
310 | 288 | new_status, other_target.owner) | ||
311 | 289 | return | ||
312 | 290 | self.fail( | ||
313 | 291 | 'No bug task found for a product that is not the target of ' | ||
314 | 292 | 'the main test bugtask.') | ||
318 | 293 | 318 | ||
319 | 294 | def test_upstream_status(self): | 319 | def test_upstream_status(self): |
320 | 295 | # Search results can be filtered by the status of an upstream | 320 | # Search results can be filtered by the status of an upstream |
321 | @@ -299,14 +324,11 @@ | |||
322 | 299 | # with status NEW for the "other" product, hence all bug tasks | 324 | # with status NEW for the "other" product, hence all bug tasks |
323 | 300 | # will be returned in a search for bugs that are open upstream. | 325 | # will be returned in a search for bugs that are open upstream. |
324 | 301 | params = self.getBugTaskSearchParams(user=None, open_upstream=True) | 326 | params = self.getBugTaskSearchParams(user=None, open_upstream=True) |
328 | 302 | search_result = self.runSearch(params) | 327 | self.assertSearchFinds(params, self.bugtasks) |
326 | 303 | expected = self.resultValuesForBugtasks(self.bugtasks) | ||
327 | 304 | self.assertEqual(expected, search_result) | ||
329 | 305 | # A search for tasks resolved upstream does not yield any bugtask. | 328 | # A search for tasks resolved upstream does not yield any bugtask. |
330 | 306 | params = self.getBugTaskSearchParams( | 329 | params = self.getBugTaskSearchParams( |
331 | 307 | user=None, resolved_upstream=True) | 330 | user=None, resolved_upstream=True) |
334 | 308 | search_result = self.runSearch(params) | 331 | self.assertSearchFinds(params, []) |
333 | 309 | self.assertEqual([], search_result) | ||
335 | 310 | # But if we set upstream bug tasks to "fix committed" or "fix | 332 | # But if we set upstream bug tasks to "fix committed" or "fix |
336 | 311 | # released", the related bug tasks for our test target appear in | 333 | # released", the related bug tasks for our test target appear in |
337 | 312 | # the search result. | 334 | # the search result. |
338 | @@ -314,14 +336,11 @@ | |||
339 | 314 | self.bugtasks[0], BugTaskStatus.FIXCOMMITTED) | 336 | self.bugtasks[0], BugTaskStatus.FIXCOMMITTED) |
340 | 315 | self.changeStatusOfBugTaskForOtherProduct( | 337 | self.changeStatusOfBugTaskForOtherProduct( |
341 | 316 | self.bugtasks[1], BugTaskStatus.FIXRELEASED) | 338 | self.bugtasks[1], BugTaskStatus.FIXRELEASED) |
345 | 317 | search_result = self.runSearch(params) | 339 | self.assertSearchFinds(params, self.bugtasks[:2]) |
343 | 318 | expected = self.resultValuesForBugtasks(self.bugtasks[:2]) | ||
344 | 319 | self.assertEqual(expected, search_result) | ||
346 | 320 | # A search for bug tasks open upstream now returns only one | 340 | # A search for bug tasks open upstream now returns only one |
347 | 321 | # test task. | 341 | # test task. |
348 | 322 | params = self.getBugTaskSearchParams(user=None, open_upstream=True) | 342 | params = self.getBugTaskSearchParams(user=None, open_upstream=True) |
351 | 323 | search_result = self.runSearch(params) | 343 | self.assertSearchFinds(params, self.bugtasks[2:]) |
350 | 324 | expected = self.resultValuesForBugtasks(self.bugtasks[2:]) | ||
352 | 325 | 344 | ||
353 | 326 | def test_tags(self): | 345 | def test_tags(self): |
354 | 327 | # Search results can be limited to bugs having given tags. | 346 | # Search results can be limited to bugs having given tags. |
355 | @@ -330,44 +349,31 @@ | |||
356 | 330 | self.bugtasks[1].bug.tags = ['tag1', 'tag3'] | 349 | self.bugtasks[1].bug.tags = ['tag1', 'tag3'] |
357 | 331 | params = self.getBugTaskSearchParams( | 350 | params = self.getBugTaskSearchParams( |
358 | 332 | user=None, tag=any('tag2', 'tag3')) | 351 | user=None, tag=any('tag2', 'tag3')) |
362 | 333 | search_result = self.runSearch(params) | 352 | self.assertSearchFinds(params, self.bugtasks[:2]) |
360 | 334 | expected = self.resultValuesForBugtasks(self.bugtasks[:2]) | ||
361 | 335 | self.assertEqual(expected, search_result) | ||
363 | 336 | 353 | ||
364 | 337 | params = self.getBugTaskSearchParams( | 354 | params = self.getBugTaskSearchParams( |
365 | 338 | user=None, tag=all('tag2', 'tag3')) | 355 | user=None, tag=all('tag2', 'tag3')) |
368 | 339 | search_result = self.runSearch(params) | 356 | self.assertSearchFinds(params, []) |
367 | 340 | self.assertEqual([], search_result) | ||
369 | 341 | 357 | ||
370 | 342 | params = self.getBugTaskSearchParams( | 358 | params = self.getBugTaskSearchParams( |
371 | 343 | user=None, tag=all('tag1', 'tag3')) | 359 | user=None, tag=all('tag1', 'tag3')) |
375 | 344 | search_result = self.runSearch(params) | 360 | self.assertSearchFinds(params, self.bugtasks[1:2]) |
373 | 345 | expected = self.resultValuesForBugtasks(self.bugtasks[1:2]) | ||
374 | 346 | self.assertEqual(expected, search_result) | ||
376 | 347 | 361 | ||
377 | 348 | params = self.getBugTaskSearchParams( | 362 | params = self.getBugTaskSearchParams( |
378 | 349 | user=None, tag=all('tag1', '-tag3')) | 363 | user=None, tag=all('tag1', '-tag3')) |
382 | 350 | search_result = self.runSearch(params) | 364 | self.assertSearchFinds(params, self.bugtasks[:1]) |
380 | 351 | expected = self.resultValuesForBugtasks(self.bugtasks[:1]) | ||
381 | 352 | self.assertEqual(expected, search_result) | ||
383 | 353 | 365 | ||
384 | 354 | params = self.getBugTaskSearchParams( | 366 | params = self.getBugTaskSearchParams( |
385 | 355 | user=None, tag=all('-tag1')) | 367 | user=None, tag=all('-tag1')) |
389 | 356 | search_result = self.runSearch(params) | 368 | self.assertSearchFinds(params, self.bugtasks[2:]) |
387 | 357 | expected = self.resultValuesForBugtasks(self.bugtasks[2:]) | ||
388 | 358 | self.assertEqual(expected, search_result) | ||
390 | 359 | 369 | ||
391 | 360 | params = self.getBugTaskSearchParams( | 370 | params = self.getBugTaskSearchParams( |
392 | 361 | user=None, tag=all('*')) | 371 | user=None, tag=all('*')) |
396 | 362 | search_result = self.runSearch(params) | 372 | self.assertSearchFinds(params, self.bugtasks[:2]) |
394 | 363 | expected = self.resultValuesForBugtasks(self.bugtasks[:2]) | ||
395 | 364 | self.assertEqual(expected, search_result) | ||
397 | 365 | 373 | ||
398 | 366 | params = self.getBugTaskSearchParams( | 374 | params = self.getBugTaskSearchParams( |
399 | 367 | user=None, tag=all('-*')) | 375 | user=None, tag=all('-*')) |
403 | 368 | search_result = self.runSearch(params) | 376 | self.assertSearchFinds(params, self.bugtasks[2:]) |
401 | 369 | expected = self.resultValuesForBugtasks(self.bugtasks[2:]) | ||
402 | 370 | self.assertEqual(expected, search_result) | ||
404 | 371 | 377 | ||
405 | 372 | def test_date_closed(self): | 378 | def test_date_closed(self): |
406 | 373 | # Search results can be filtered by the date_closed time | 379 | # Search results can be filtered by the date_closed time |
407 | @@ -379,13 +385,106 @@ | |||
408 | 379 | self.assertTrue(utc_now >= self.bugtasks[2].date_closed) | 385 | self.assertTrue(utc_now >= self.bugtasks[2].date_closed) |
409 | 380 | params = self.getBugTaskSearchParams( | 386 | params = self.getBugTaskSearchParams( |
410 | 381 | user=None, date_closed=greater_than(utc_now-timedelta(days=1))) | 387 | user=None, date_closed=greater_than(utc_now-timedelta(days=1))) |
414 | 382 | search_result = self.runSearch(params) | 388 | self.assertSearchFinds(params, self.bugtasks[2:]) |
412 | 383 | expected = self.resultValuesForBugtasks(self.bugtasks[2:]) | ||
413 | 384 | self.assertEqual(expected, search_result) | ||
415 | 385 | params = self.getBugTaskSearchParams( | 389 | params = self.getBugTaskSearchParams( |
416 | 386 | user=None, date_closed=greater_than(utc_now+timedelta(days=1))) | 390 | user=None, date_closed=greater_than(utc_now+timedelta(days=1))) |
419 | 387 | search_result = self.runSearch(params) | 391 | self.assertSearchFinds(params, []) |
420 | 388 | self.assertEqual([], search_result) | 392 | |
421 | 393 | def test_created_since(self): | ||
422 | 394 | # Search results can be limited to bugtasks created after a | ||
423 | 395 | # given time. | ||
424 | 396 | one_day_ago = self.bugtasks[0].datecreated - timedelta(days=1) | ||
425 | 397 | two_days_ago = self.bugtasks[0].datecreated - timedelta(days=2) | ||
426 | 398 | with person_logged_in(self.owner): | ||
427 | 399 | self.bugtasks[0].datecreated = two_days_ago | ||
428 | 400 | params = self.getBugTaskSearchParams( | ||
429 | 401 | user=None, created_since=one_day_ago) | ||
430 | 402 | self.assertSearchFinds(params, self.bugtasks[1:]) | ||
431 | 403 | |||
432 | 404 | def test_modified_since(self): | ||
433 | 405 | # Search results can be limited to bugs modified after a | ||
434 | 406 | # given time. | ||
435 | 407 | one_day_ago = ( | ||
436 | 408 | self.bugtasks[0].bug.date_last_updated - timedelta(days=1)) | ||
437 | 409 | two_days_ago = ( | ||
438 | 410 | self.bugtasks[0].bug.date_last_updated - timedelta(days=2)) | ||
439 | 411 | with person_logged_in(self.owner): | ||
440 | 412 | self.bugtasks[0].bug.date_last_updated = two_days_ago | ||
441 | 413 | params = self.getBugTaskSearchParams( | ||
442 | 414 | user=None, modified_since=one_day_ago) | ||
443 | 415 | self.assertSearchFinds(params, self.bugtasks[1:]) | ||
444 | 416 | |||
445 | 417 | def test_branches_linked(self): | ||
446 | 418 | # Search results can be limited to bugs with or without linked | ||
447 | 419 | # branches. | ||
448 | 420 | with person_logged_in(self.owner): | ||
449 | 421 | branch = self.factory.makeBranch() | ||
450 | 422 | self.bugtasks[0].bug.linkBranch(branch, self.owner) | ||
451 | 423 | params = self.getBugTaskSearchParams( | ||
452 | 424 | user=None, linked_branches=BugBranchSearch.BUGS_WITH_BRANCHES) | ||
453 | 425 | self.assertSearchFinds(params, self.bugtasks[:1]) | ||
454 | 426 | params = self.getBugTaskSearchParams( | ||
455 | 427 | user=None, linked_branches=BugBranchSearch.BUGS_WITHOUT_BRANCHES) | ||
456 | 428 | self.assertSearchFinds(params, self.bugtasks[1:]) | ||
457 | 429 | |||
458 | 430 | def test_limit_search_to_one_bug(self): | ||
459 | 431 | # Search results can be limited to a given bug. | ||
460 | 432 | params = self.getBugTaskSearchParams( | ||
461 | 433 | user=None, bug=self.bugtasks[0].bug) | ||
462 | 434 | self.assertSearchFinds(params, self.bugtasks[:1]) | ||
463 | 435 | other_bug = self.factory.makeBug() | ||
464 | 436 | params = self.getBugTaskSearchParams(user=None, bug=other_bug) | ||
465 | 437 | self.assertSearchFinds(params, []) | ||
466 | 438 | |||
467 | 439 | def test_filter_by_status(self): | ||
468 | 440 | # Search results can be limited to bug tasks with a given status. | ||
469 | 441 | params = self.getBugTaskSearchParams( | ||
470 | 442 | user=None, status=BugTaskStatus.FIXCOMMITTED) | ||
471 | 443 | self.assertSearchFinds(params, self.bugtasks[2:]) | ||
472 | 444 | params = self.getBugTaskSearchParams( | ||
473 | 445 | user=None, status=any(BugTaskStatus.NEW, BugTaskStatus.TRIAGED)) | ||
474 | 446 | self.assertSearchFinds(params, self.bugtasks[:2]) | ||
475 | 447 | params = self.getBugTaskSearchParams( | ||
476 | 448 | user=None, status=BugTaskStatus.WONTFIX) | ||
477 | 449 | self.assertSearchFinds(params, []) | ||
478 | 450 | |||
479 | 451 | def test_filter_by_importance(self): | ||
480 | 452 | # Search results can be limited to bug tasks with a given importance. | ||
481 | 453 | params = self.getBugTaskSearchParams( | ||
482 | 454 | user=None, importance=BugTaskImportance.HIGH) | ||
483 | 455 | self.assertSearchFinds(params, self.bugtasks[:1]) | ||
484 | 456 | params = self.getBugTaskSearchParams( | ||
485 | 457 | user=None, | ||
486 | 458 | importance=any(BugTaskImportance.HIGH, BugTaskImportance.LOW)) | ||
487 | 459 | self.assertSearchFinds(params, self.bugtasks[:2]) | ||
488 | 460 | params = self.getBugTaskSearchParams( | ||
489 | 461 | user=None, importance=BugTaskImportance.MEDIUM) | ||
490 | 462 | self.assertSearchFinds(params, []) | ||
491 | 463 | |||
492 | 464 | def test_omit_duplicate_bugs(self): | ||
493 | 465 | # Duplicate bugs can optionally be excluded from search results. | ||
494 | 466 | # The default behaviour is to include duplicates. | ||
495 | 467 | duplicate_bug = self.bugtasks[0].bug | ||
496 | 468 | master_bug = self.bugtasks[1].bug | ||
497 | 469 | with person_logged_in(self.owner): | ||
498 | 470 | duplicate_bug.markAsDuplicate(master_bug) | ||
499 | 471 | params = self.getBugTaskSearchParams(user=None) | ||
500 | 472 | self.assertSearchFinds(params, self.bugtasks) | ||
501 | 473 | # If we explicitly pass the parameter omit_duplicates=False, we get | ||
502 | 474 | # the same result. | ||
503 | 475 | params = self.getBugTaskSearchParams(user=None, omit_dupes=False) | ||
504 | 476 | self.assertSearchFinds(params, self.bugtasks) | ||
505 | 477 | # If omit_duplicates is set to True, the first task bug is omitted. | ||
506 | 478 | params = self.getBugTaskSearchParams(user=None, omit_dupes=True) | ||
507 | 479 | self.assertSearchFinds(params, self.bugtasks[1:]) | ||
508 | 480 | |||
509 | 481 | def test_has_cve(self): | ||
510 | 482 | # Search results can be limited to bugs linked to a CVE. | ||
511 | 483 | with person_logged_in(self.owner): | ||
512 | 484 | cve = self.factory.makeCVE('2010-0123') | ||
513 | 485 | self.bugtasks[0].bug.linkCVE(cve, self.owner) | ||
514 | 486 | params = self.getBugTaskSearchParams(user=None, has_cve=True) | ||
515 | 487 | self.assertSearchFinds(params, self.bugtasks[:1]) | ||
516 | 389 | 488 | ||
517 | 390 | 489 | ||
518 | 391 | class ProductAndDistributionTests: | 490 | class ProductAndDistributionTests: |
519 | @@ -405,9 +504,7 @@ | |||
520 | 405 | self.bugtasks[0].bug.addNomination(nominator, series1) | 504 | self.bugtasks[0].bug.addNomination(nominator, series1) |
521 | 406 | self.bugtasks[1].bug.addNomination(nominator, series2) | 505 | self.bugtasks[1].bug.addNomination(nominator, series2) |
522 | 407 | params = self.getBugTaskSearchParams(user=None, nominated_for=series1) | 506 | params = self.getBugTaskSearchParams(user=None, nominated_for=series1) |
526 | 408 | search_result = self.runSearch(params) | 507 | self.assertSearchFinds(params, self.bugtasks[:1]) |
524 | 409 | expected = self.resultValuesForBugtasks(self.bugtasks[:1]) | ||
525 | 410 | self.assertEqual(expected, search_result) | ||
527 | 411 | 508 | ||
528 | 412 | 509 | ||
529 | 413 | class BugTargetTestBase: | 510 | class BugTargetTestBase: |
530 | @@ -445,15 +542,12 @@ | |||
531 | 445 | supervisor = self.factory.makeTeam(owner=self.owner) | 542 | supervisor = self.factory.makeTeam(owner=self.owner) |
532 | 446 | params = self.getBugTaskSearchParams( | 543 | params = self.getBugTaskSearchParams( |
533 | 447 | user=None, bug_supervisor=supervisor) | 544 | user=None, bug_supervisor=supervisor) |
536 | 448 | search_result = self.runSearch(params) | 545 | self.assertSearchFinds(params, []) |
535 | 449 | self.assertEqual([], search_result) | ||
537 | 450 | 546 | ||
538 | 451 | # If we appoint a bug supervisor, searching for bug tasks | 547 | # If we appoint a bug supervisor, searching for bug tasks |
539 | 452 | # by supervisor will return all bugs for our test target. | 548 | # by supervisor will return all bugs for our test target. |
540 | 453 | self.setSupervisor(supervisor) | 549 | self.setSupervisor(supervisor) |
544 | 454 | search_result = self.runSearch(params) | 550 | self.assertSearchFinds(params, self.bugtasks) |
542 | 455 | expected = self.resultValuesForBugtasks(self.bugtasks) | ||
543 | 456 | self.assertEqual(expected, search_result) | ||
545 | 457 | 551 | ||
546 | 458 | def setSupervisor(self, supervisor): | 552 | def setSupervisor(self, supervisor): |
547 | 459 | """Set the bug supervisor for the bug task target.""" | 553 | """Set the bug supervisor for the bug task target.""" |
548 | @@ -484,6 +578,11 @@ | |||
549 | 484 | """See `ProductAndDistributionTests`.""" | 578 | """See `ProductAndDistributionTests`.""" |
550 | 485 | return self.factory.makeProductSeries(product=self.searchtarget) | 579 | return self.factory.makeProductSeries(product=self.searchtarget) |
551 | 486 | 580 | ||
552 | 581 | def findBugtaskForOtherProduct(self, bugtask): | ||
553 | 582 | # Return the bugtask for the product that is not related to the | ||
554 | 583 | # main bug target. | ||
555 | 584 | return self._findBugtaskForOtherProduct(bugtask, self.searchtarget) | ||
556 | 585 | |||
557 | 487 | 586 | ||
558 | 488 | class ProductSeriesTarget(BugTargetTestBase): | 587 | class ProductSeriesTarget(BugTargetTestBase): |
559 | 489 | """Use a product series as the bug target.""" | 588 | """Use a product series as the bug target.""" |
560 | @@ -503,6 +602,31 @@ | |||
561 | 503 | params.setProductSeries(self.searchtarget) | 602 | params.setProductSeries(self.searchtarget) |
562 | 504 | return params | 603 | return params |
563 | 505 | 604 | ||
564 | 605 | def changeStatusOfBugTaskForOtherProduct(self, bugtask, new_status): | ||
565 | 606 | # Change the status of another bugtask of the same bug to the | ||
566 | 607 | # given status. | ||
567 | 608 | # | ||
568 | 609 | # This method is called by SearchTestBase.test_upstream_status(). | ||
569 | 610 | # A search for bugs which are open or closed upstream has an | ||
570 | 611 | # odd behaviour when the search target is a product series: In | ||
571 | 612 | # this case, all bugs with an open or closed bug task for _any_ | ||
572 | 613 | # product are returned, including bug tasks for the main product | ||
573 | 614 | # of the series. Hence we must set the status for all products | ||
574 | 615 | # in order to avoid a failure of test_upstream_status(). | ||
575 | 616 | bug = bugtask.bug | ||
576 | 617 | for other_task in bugtask.related_tasks: | ||
577 | 618 | other_target = other_task.target | ||
578 | 619 | if IProduct.providedBy(other_target): | ||
579 | 620 | with person_logged_in(other_target.owner): | ||
580 | 621 | other_task.transitionToStatus( | ||
581 | 622 | new_status, other_target.owner) | ||
582 | 623 | |||
583 | 624 | def findBugtaskForOtherProduct(self, bugtask): | ||
584 | 625 | # Return the bugtask for the product that not related to the | ||
585 | 626 | # main bug target. | ||
586 | 627 | return self._findBugtaskForOtherProduct( | ||
587 | 628 | bugtask, self.searchtarget.product) | ||
588 | 629 | |||
589 | 506 | 630 | ||
590 | 507 | class ProjectGroupTarget(BugTargetTestBase, BugTargetWithBugSuperVisor): | 631 | class ProjectGroupTarget(BugTargetTestBase, BugTargetWithBugSuperVisor): |
591 | 508 | """Use a project group as the bug target.""" | 632 | """Use a project group as the bug target.""" |
592 | @@ -525,8 +649,10 @@ | |||
593 | 525 | def makeBugTasks(self): | 649 | def makeBugTasks(self): |
594 | 526 | """Create bug tasks for the search target.""" | 650 | """Create bug tasks for the search target.""" |
595 | 527 | self.bugtasks = [] | 651 | self.bugtasks = [] |
596 | 652 | self.products = [] | ||
597 | 528 | with person_logged_in(self.owner): | 653 | with person_logged_in(self.owner): |
598 | 529 | product = self.factory.makeProduct(owner=self.owner) | 654 | product = self.factory.makeProduct(owner=self.owner) |
599 | 655 | self.products.append(product) | ||
600 | 530 | product.project = self.searchtarget | 656 | product.project = self.searchtarget |
601 | 531 | self.bugtasks.append( | 657 | self.bugtasks.append( |
602 | 532 | self.factory.makeBugTask(target=product)) | 658 | self.factory.makeBugTask(target=product)) |
603 | @@ -535,6 +661,7 @@ | |||
604 | 535 | BugTaskStatus.TRIAGED, self.owner) | 661 | BugTaskStatus.TRIAGED, self.owner) |
605 | 536 | 662 | ||
606 | 537 | product = self.factory.makeProduct(owner=self.owner) | 663 | product = self.factory.makeProduct(owner=self.owner) |
607 | 664 | self.products.append(product) | ||
608 | 538 | product.project = self.searchtarget | 665 | product.project = self.searchtarget |
609 | 539 | self.bugtasks.append( | 666 | self.bugtasks.append( |
610 | 540 | self.factory.makeBugTask(target=product)) | 667 | self.factory.makeBugTask(target=product)) |
611 | @@ -543,6 +670,7 @@ | |||
612 | 543 | BugTaskStatus.NEW, self.owner) | 670 | BugTaskStatus.NEW, self.owner) |
613 | 544 | 671 | ||
614 | 545 | product = self.factory.makeProduct(owner=self.owner) | 672 | product = self.factory.makeProduct(owner=self.owner) |
615 | 673 | self.products.append(product) | ||
616 | 546 | product.project = self.searchtarget | 674 | product.project = self.searchtarget |
617 | 547 | self.bugtasks.append( | 675 | self.bugtasks.append( |
618 | 548 | self.factory.makeBugTask(target=product)) | 676 | self.factory.makeBugTask(target=product)) |
619 | @@ -557,6 +685,19 @@ | |||
620 | 557 | for bugtask in self.bugtasks: | 685 | for bugtask in self.bugtasks: |
621 | 558 | bugtask.target.setBugSupervisor(supervisor, self.owner) | 686 | bugtask.target.setBugSupervisor(supervisor, self.owner) |
622 | 559 | 687 | ||
623 | 688 | def findBugtaskForOtherProduct(self, bugtask): | ||
624 | 689 | # Return the bugtask for the product that not related to the | ||
625 | 690 | # main bug target. | ||
626 | 691 | bug = bugtask.bug | ||
627 | 692 | for other_task in bug.bugtasks: | ||
628 | 693 | other_target = other_task.target | ||
629 | 694 | if (IProduct.providedBy(other_target) | ||
630 | 695 | and other_target not in self.products): | ||
631 | 696 | return other_task | ||
632 | 697 | self.fail( | ||
633 | 698 | 'No bug task found for a product that is not the target of ' | ||
634 | 699 | 'the main test bugtask.') | ||
635 | 700 | |||
636 | 560 | 701 | ||
637 | 561 | class MilestoneTarget(BugTargetTestBase): | 702 | class MilestoneTarget(BugTargetTestBase): |
638 | 562 | """Use a milestone as the bug target.""" | 703 | """Use a milestone as the bug target.""" |
639 | @@ -583,6 +724,11 @@ | |||
640 | 583 | for bugtask in self.bugtasks: | 724 | for bugtask in self.bugtasks: |
641 | 584 | bugtask.transitionToMilestone(self.searchtarget, self.owner) | 725 | bugtask.transitionToMilestone(self.searchtarget, self.owner) |
642 | 585 | 726 | ||
643 | 727 | def findBugtaskForOtherProduct(self, bugtask): | ||
644 | 728 | # Return the bugtask for the product that not related to the | ||
645 | 729 | # main bug target. | ||
646 | 730 | return self._findBugtaskForOtherProduct(bugtask, self.product) | ||
647 | 731 | |||
648 | 586 | 732 | ||
649 | 587 | class DistributionTarget(BugTargetTestBase, ProductAndDistributionTests, | 733 | class DistributionTarget(BugTargetTestBase, ProductAndDistributionTests, |
650 | 588 | BugTargetWithBugSuperVisor): | 734 | BugTargetWithBugSuperVisor): |
651 | @@ -645,6 +791,14 @@ | |||
652 | 645 | params.setSourcePackage(self.searchtarget) | 791 | params.setSourcePackage(self.searchtarget) |
653 | 646 | return params | 792 | return params |
654 | 647 | 793 | ||
655 | 794 | def subscribeToTarget(self, subscriber): | ||
656 | 795 | # Subscribe the given person to the search target. | ||
657 | 796 | # Source packages do not support structural subscriptions, | ||
658 | 797 | # so we subscribe to the distro series instead. | ||
659 | 798 | with person_logged_in(subscriber): | ||
660 | 799 | self.searchtarget.distroseries.addSubscription( | ||
661 | 800 | subscriber, subscribed_by=subscriber) | ||
662 | 801 | |||
663 | 648 | 802 | ||
664 | 649 | class DistributionSourcePackageTarget(BugTargetTestBase, | 803 | class DistributionSourcePackageTarget(BugTargetTestBase, |
665 | 650 | BugTargetWithBugSuperVisor): | 804 | BugTargetWithBugSuperVisor): |
666 | 651 | 805 | ||
667 | === modified file 'lib/lp/testing/factory.py' | |||
668 | --- lib/lp/testing/factory.py 2010-11-03 23:44:56 +0000 | |||
669 | +++ lib/lp/testing/factory.py 2010-11-04 15:56:18 +0000 | |||
670 | @@ -111,6 +111,10 @@ | |||
671 | 111 | IBugTrackerSet, | 111 | IBugTrackerSet, |
672 | 112 | ) | 112 | ) |
673 | 113 | from lp.bugs.interfaces.bugwatch import IBugWatchSet | 113 | from lp.bugs.interfaces.bugwatch import IBugWatchSet |
674 | 114 | from lp.bugs.interfaces.cve import ( | ||
675 | 115 | CveStatus, | ||
676 | 116 | ICveSet, | ||
677 | 117 | ) | ||
678 | 114 | from lp.buildmaster.enums import ( | 118 | from lp.buildmaster.enums import ( |
679 | 115 | BuildFarmJobType, | 119 | BuildFarmJobType, |
680 | 116 | BuildStatus, | 120 | BuildStatus, |
681 | @@ -3230,6 +3234,13 @@ | |||
682 | 3230 | consumer, reviewed_by=owner, access_level=access_level) | 3234 | consumer, reviewed_by=owner, access_level=access_level) |
683 | 3231 | return request_token.createAccessToken() | 3235 | return request_token.createAccessToken() |
684 | 3232 | 3236 | ||
685 | 3237 | def makeCVE(self, sequence, description=None, | ||
686 | 3238 | cvestate=CveStatus.CANDIDATE): | ||
687 | 3239 | """Create a new CVE record.""" | ||
688 | 3240 | if description is None: | ||
689 | 3241 | description = self.getUniqueString() | ||
690 | 3242 | return getUtility(ICveSet).new(sequence, description, cvestate) | ||
691 | 3243 | |||
692 | 3233 | 3244 | ||
693 | 3234 | # Some factory methods return simple Python types. We don't add | 3245 | # Some factory methods return simple Python types. We don't add |
694 | 3235 | # security wrappers for them, as well as for objects created by | 3246 | # security wrappers for them, as well as for objects created by |
695 | 3236 | 3247 | ||
696 | === modified file 'lib/lp/testing/tests/test_factory.py' | |||
697 | --- lib/lp/testing/tests/test_factory.py 2010-10-25 19:11:46 +0000 | |||
698 | +++ lib/lp/testing/tests/test_factory.py 2010-11-04 15:56:18 +0000 | |||
699 | @@ -17,6 +17,10 @@ | |||
700 | 17 | DatabaseFunctionalLayer, | 17 | DatabaseFunctionalLayer, |
701 | 18 | LaunchpadZopelessLayer, | 18 | LaunchpadZopelessLayer, |
702 | 19 | ) | 19 | ) |
703 | 20 | from lp.bugs.interfaces.cve import ( | ||
704 | 21 | CveStatus, | ||
705 | 22 | ICve, | ||
706 | 23 | ) | ||
707 | 20 | from lp.buildmaster.enums import BuildStatus | 24 | from lp.buildmaster.enums import BuildStatus |
708 | 21 | from lp.code.enums import ( | 25 | from lp.code.enums import ( |
709 | 22 | BranchType, | 26 | BranchType, |
710 | @@ -492,6 +496,24 @@ | |||
711 | 492 | ssp = self.factory.makeSuiteSourcePackage() | 496 | ssp = self.factory.makeSuiteSourcePackage() |
712 | 493 | self.assertThat(ssp, ProvidesAndIsProxied(ISuiteSourcePackage)) | 497 | self.assertThat(ssp, ProvidesAndIsProxied(ISuiteSourcePackage)) |
713 | 494 | 498 | ||
714 | 499 | # makeCVE | ||
715 | 500 | def test_makeCVE_returns_cve(self): | ||
716 | 501 | cve = self.factory.makeCVE(sequence='2000-1234') | ||
717 | 502 | self.assertThat(cve, ProvidesAndIsProxied(ICve)) | ||
718 | 503 | |||
719 | 504 | def test_makeCVE_uses_sequence(self): | ||
720 | 505 | cve = self.factory.makeCVE(sequence='2000-1234') | ||
721 | 506 | self.assertEqual('2000-1234', cve.sequence) | ||
722 | 507 | |||
723 | 508 | def test_makeCVE_uses_description(self): | ||
724 | 509 | cve = self.factory.makeCVE(sequence='2000-1234', description='foo') | ||
725 | 510 | self.assertEqual('foo', cve.description) | ||
726 | 511 | |||
727 | 512 | def test_makeCVE_uses_cve_status(self): | ||
728 | 513 | cve = self.factory.makeCVE( | ||
729 | 514 | sequence='2000-1234', cvestate=CveStatus.DEPRECATED) | ||
730 | 515 | self.assertEqual(CveStatus.DEPRECATED, cve.status) | ||
731 | 516 | |||
732 | 495 | 517 | ||
733 | 496 | class TestFactoryWithLibrarian(TestCaseWithFactory): | 518 | class TestFactoryWithLibrarian(TestCaseWithFactory): |
734 | 497 | 519 |
Sorry for taking so long to review this. Reading unit tests can be
hard work :-/
A general comment is that the findBugtaskForO therProduct and its OtherProduct started to get a bit convoluted. I
helper _findBugtaskFor
don't have a suggestion for making it better though. I think I
wouldn't have separated it out into two methods; I would have just
overridden the method and called up, but that's a matter of
preference.
It's great to have some clear and accurate definitions of search
behaviour.
+1
[1]
+ # Return the bugtask for the product that not related to the
+ # main bug target.
s/that/that is/
[2]
+ def _findBugtaskFor OtherProduct( self, bugtask, main_product):
To summarize this, just to check my understanding:
Return the first bugtask of the given bugtask's bug that is (a)
targeted to an IProduct and (b) not targeted to main_product.
[3]
+ # Search results can be limited to bugs with a bug target to which
+ # a given person has a structural subscription.
Oh my, I was not aware of this. This could get complicated with
filters. For now I'm going to ignore it :)
[4]
+ def changeStatusOfB ugTaskForOtherP roduct( self, bugtask, new_status): providedBy( other_target) : logged_ in(other_ target. owner): transitionToSta tus(
+ # Change the status of another bugtask of the same bug to the
+ # given status.
...
+ bug = bugtask.bug
+ for other_task in bug.bugtasks:
+ other_target = other_task.target
+ if IProduct.
+ with person_
+ other_task.
+ new_status, other_target.owner)
This will change the status of bugtask too, which might be fine but is
not what is implied by the method name and comment.
If you only wish to change the status of other tasks, the
related_tasks property could be useful:
for other_task in bugtask. related_ tasks:
other_ target = other_task.target providedBy( other_target) : logged_ in(other_ target. owner):
other_ task.transition ToStatus(
new_ status, other_target.owner)
if IProduct.
with person_
[5]
+ def makeCVE(self, sequence, description=None, CveStatus. CANDIDATE) :
+ cvestate=
This probably ought to have a simple test or two. I only just noticed
that there are tests for the factory methods.