Merge lp:~mabac/svammel/get-success-logs into lp:svammel
- get-success-logs
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | James Westby |
Approved revision: | 83 |
Merged at revision: | 84 |
Proposed branch: | lp:~mabac/svammel/get-success-logs |
Merge into: | lp:svammel |
Prerequisite: | lp:~mabac/svammel/add-version-check-and-tests |
Diff against target: |
701 lines (+428/-106) 5 files modified
config.py (+3/-0) data_parsing.py (+78/-11) file-failures.py (+14/-13) tests/test_bug_logging.py (+1/-1) tests/test_fail_filer.py (+332/-81) |
To merge this branch: | bzr merge lp:~mabac/svammel/get-success-logs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Westby (community) | Approve | ||
Review via email: mp+53643@code.launchpad.net |
Commit message
Description of the change
Hi,
This branch adds cross referencing successful builds before filing bugs. The action is added to filter_spph which did get quite messy. :/
Well, what it does for each package not already rejected is to iterate over all archives and ask for successful builds. We then get the successful build of the most recent package version and compare that to the version of the failed build.
If there are any successful builds in any archive the only way the failed build survives is if it is of a higher version than any of the successful builds. My reasoning is that if the fail is of the most recent version, it should be reported. And if there is any successful build for a more recent package there is nothing to report.
The interesting case is when we find a successful build of the same version of the package that we have already found a failure for. I think that this would mean that there isn't a porting issue then since the version can be built on armel so no bug will be filed.
Thanks,
Mattias
- 74. By Mattias Backman
-
Merge changes from add-version-
and-tests. - 75. By Mattias Backman
-
Docstring indentation and whitespace fix.
- 76. By Mattias Backman
-
Add basic filtering tests.
- 77. By Mattias Backman
-
Break long lines and add get_build_list tests.
- 78. By Mattias Backman
-
Add more filtering tests.
- 79. By Mattias Backman
-
remove double import.
- 80. By Mattias Backman
-
Make --dryrun enable -v output.
- 81. By Mattias Backman
-
Do not raise error for null queue.
- 82. By Mattias Backman
-
Improve test.
Mattias Backman (mabac) wrote : | # |
> 9 + help='Disable bug filing. Combine with -v to enable useful
> output.')
>
> Should -v just be implied?
Yeah, that's a good idea. Fixed.
>
> 61 + if spph_queue is None:
> 62 + raise NoVersionError(
>
> I tend to not code defensively in cases like this. The developer
> will get an error that is almost as obvious when it tries to iterate the
> list, so I lean towards brevity. I reserve the checks for when the error
> would be obtuse, or the code will do the wrong thing.
>
> That's just my preference though, if you prefer this then leave it as is.
Mostly this is about fear of Coverity Prevent which flags any remotely theoretical possibility of an unchecked null pointer as a defect. I can probably take it more easy with this in svammel and get cleaner code. :)
>
> 126 + if spph is None:
> 127 + continue
>
> ...
>
> 150 + spph = None
>
> Could that just be a "break" where you set spph to None?
Yes, that's true.
- 83. By Mattias Backman
-
Remove unused Error.
- 84. By Mattias Backman
-
Merged changes from add-version-
check-and- tests. - 85. By Mattias Backman
-
Merge changes from trunk.
- 86. By Mattias Backman
-
Merge James' fix for not shadowing logging.
- 87. By Mattias Backman
-
Fix build_build_record defect.
Preview Diff
1 | === renamed file 'logging.py' => 'bug_logging.py' |
2 | === modified file 'config.py' |
3 | --- config.py 2011-03-22 10:17:01 +0000 |
4 | +++ config.py 2011-03-30 07:39:33 +0000 |
5 | @@ -104,6 +104,9 @@ |
6 | '-v', '--verbose', action='store_true', dest='verbose', |
7 | help='Enable verbose messages.') |
8 | parser.add_argument( |
9 | + '--dryrun', action='store_true', dest='dryrun', |
10 | + help='Disable bug filing and enable verbose messages.') |
11 | + parser.add_argument( |
12 | '--serviceroot', default='production', |
13 | choices=['production', 'staging', 'qastaging'], |
14 | help='The Launchpad environment to connect to.') |
15 | |
16 | === modified file 'data_parsing.py' |
17 | --- data_parsing.py 2011-03-30 07:39:33 +0000 |
18 | +++ data_parsing.py 2011-03-30 07:39:33 +0000 |
19 | @@ -85,14 +85,48 @@ |
20 | self.version) < 0) |
21 | |
22 | |
23 | +def get_build_list(archive, state, source=None): |
24 | + |
25 | + buildlist = archive.getBuildRecords(build_state=state, source_name=source) |
26 | + |
27 | + # XXX mabac 2011-03-16: getBuildRecords filters on substrings |
28 | + # so buildlist probably contains non exact matches. |
29 | + # https://bugs.launchpad.net/launchpad/+bug/231862 |
30 | + if source is not None: |
31 | + filter_list = [] |
32 | + for build in buildlist: |
33 | + csp = build.current_source_publication |
34 | + if csp is not None and csp.source_package_name == source: |
35 | + filter_list.append(build) |
36 | + return filter_list |
37 | + |
38 | + return buildlist |
39 | + |
40 | + |
41 | +def get_highest_version(spph_queue): |
42 | + """Returns the spph of the highest version in the list. |
43 | + |
44 | + If more than one spph with the same version is in the list, |
45 | + the first of the identical versions in the list is returned. |
46 | + """ |
47 | + candidate_spph = None |
48 | + while len(spph_queue) > 0: |
49 | + new_spph = spph_queue.pop(0) |
50 | + if new_spph is None: |
51 | + continue |
52 | + if new_spph.is_higher_version_than(candidate_spph): |
53 | + candidate_spph = new_spph |
54 | + |
55 | + return candidate_spph |
56 | + |
57 | + |
58 | def fetch_pkg_list(archives): |
59 | all_spph = dict() |
60 | for archive, archive_name in archives: |
61 | print_message("The following packages have failed to build " \ |
62 | "in '%s'." % archive_name) |
63 | |
64 | - buildlist = archive.getBuildRecords(build_state=FAILED_BUILD_STATE) |
65 | - |
66 | + buildlist = get_build_list(archive, FAILED_BUILD_STATE) |
67 | for build in buildlist: |
68 | csp = build.current_source_publication |
69 | if csp is None: |
70 | @@ -112,13 +146,14 @@ |
71 | return all_spph |
72 | |
73 | |
74 | -def filter_spph(all_spph_list, fail_arch, ok_archs): |
75 | +def filter_spph(all_spph_list, fail_arch, ok_archs, archives): |
76 | """Filter out the build failures that are unique to the target arch. |
77 | |
78 | Arguments: |
79 | all_spph_list -- List of all spphs to investigate. |
80 | fail_arch -- The arch on which the builds should have failed. |
81 | ok_archs -- A list of archs on which the builds have not failed. |
82 | + archives -- A list of archives to cross check for successful builds. |
83 | |
84 | Returns: |
85 | A subset of all_spph_list which represents the interesting packages. |
86 | @@ -126,13 +161,45 @@ |
87 | filtered_list = [] |
88 | for spph in all_spph_list.values(): |
89 | if not spph.is_ftbfs(fail_arch): |
90 | - # Drop this spph since it did not fail on target arch. |
91 | - continue |
92 | - if next((arch for arch in ok_archs if spph.is_ftbfs(arch)), |
93 | - None) is not None: |
94 | - # Drop this spph since it did fail on other arch. |
95 | - continue |
96 | - filtered_list.append(spph) |
97 | + print_message("Ignoring package '%s' version '%s' since it did " \ |
98 | + "not fail on architecture '%s'." % \ |
99 | + (spph.package_name, spph.version, fail_arch)) |
100 | + continue |
101 | + also_failed = next((arch for arch in ok_archs |
102 | + if spph.is_ftbfs(arch)), None) |
103 | + if also_failed is not None: |
104 | + print_message("Ignoring package '%s' version '%s' since it also " \ |
105 | + "failed to build on architecture '%s'." % \ |
106 | + (spph.package_name, spph.version, also_failed)) |
107 | + continue |
108 | + |
109 | + for archive, archive_name in archives: |
110 | + # Get list of successful builds for the same package |
111 | + success_list = get_build_list(archive, SUCCESS_BUILD_STATE, |
112 | + spph.package_name) |
113 | + success_spph_list = [] |
114 | + for success_build in success_list: |
115 | + success_spph = SPPH(success_build.current_source_publication) |
116 | + if success_build.arch_tag == fail_arch: |
117 | + success_spph_list.append(success_spph) |
118 | + |
119 | + candidate_success_spph = get_highest_version(success_spph_list) |
120 | + if spph.is_higher_version_than(candidate_success_spph): |
121 | + # Only care about the failed build if it is of a higher |
122 | + # version than any successful build of the same package. |
123 | + pass |
124 | + else: |
125 | + print_message("Failed build for package '%s' version '%s' " \ |
126 | + "overridden by successful build of " \ |
127 | + "version '%s' in archive '%s'." % \ |
128 | + (spph.package_name, spph.version, |
129 | + candidate_success_spph.version, |
130 | + archive_name)) |
131 | + spph = None |
132 | + break |
133 | + |
134 | + if spph is not None: |
135 | + filtered_list.append(spph) |
136 | |
137 | return filtered_list |
138 | |
139 | @@ -179,4 +246,4 @@ |
140 | print_message("Will be getting builds from archives " + ", ".join( |
141 | name for (archive, name) in archives)) |
142 | spph_list = fetch_pkg_list(archives) |
143 | - return filter_spph(spph_list, fail_platform, ok_platforms) |
144 | + return filter_spph(spph_list, fail_platform, ok_platforms, archives) |
145 | |
146 | === modified file 'file-failures.py' |
147 | --- file-failures.py 2011-03-30 07:39:33 +0000 |
148 | +++ file-failures.py 2011-03-30 07:39:33 +0000 |
149 | @@ -13,7 +13,6 @@ |
150 | from data_parsing import ( |
151 | get_tags_for_fail, |
152 | get_build_status, |
153 | - filter_spph, |
154 | ) |
155 | from bug_reporting import ( |
156 | file_bug_by_url, |
157 | @@ -30,7 +29,7 @@ |
158 | get_file_contents, |
159 | get_interesting_part, |
160 | ) |
161 | -from logging import ( |
162 | +from bug_logging import ( |
163 | Log, |
164 | LogEntry, |
165 | ) |
166 | @@ -46,7 +45,7 @@ |
167 | |
168 | parser = get_args_parser() |
169 | args = parser.parse_args() |
170 | -set_verbose_messages(args.verbose) |
171 | +set_verbose_messages(args.verbose or args.dryrun) |
172 | |
173 | init(args.serviceroot, 'testing', '~/.launchpadlib/cache/') |
174 | |
175 | @@ -80,7 +79,7 @@ |
176 | |
177 | build_record = spph.get_arch(fail_platform) |
178 | if build_record is not None: |
179 | - build_build_record = get_file_contents(log.build_log_url) |
180 | + build_log = get_file_contents(build_record.build_log_url) |
181 | else: |
182 | print "%s build record not available for %s version %s." % \ |
183 | (fail_platform, spph.package_name, spph.version) |
184 | @@ -99,12 +98,14 @@ |
185 | """ % (bug_title, build_record.web_link, build_record.build_log_url, |
186 | interesting_log_part) |
187 | |
188 | - print_message( |
189 | - "Will file bug for %s\n desc: %s\n title: %s\n tags: %s" % |
190 | - (spph.package_name, bug_description[0:220], bug_title, bug_tags)) |
191 | - bug = file_bug_by_url(spph.url, bug_description, bug_title, |
192 | - bug_tags, get_launchpad()) |
193 | - if bug is not None and args.logfile is not None: |
194 | - bug_log.write_entry( |
195 | - LogEntry(spph.package_name, spph.version, fail_platform, |
196 | - bug.self_link).to_string()) |
197 | + print_message("Will file bug for %s version %s with tags: %s" % \ |
198 | + (spph.package_name, spph.version, bug_tags)) |
199 | + if not args.dryrun: |
200 | + bug = file_bug_by_url(spph.url, bug_description, bug_title, |
201 | + bug_tags, get_launchpad()) |
202 | + if bug is not None and args.logfile is not None: |
203 | + bug_log.write_entry( |
204 | + LogEntry(spph.package_name, spph.version, fail_platform, |
205 | + bug.self_link).to_string()) |
206 | + else: |
207 | + print_message(" ... but didn't since dryrun is specified.") |
208 | |
209 | === modified file 'tests/test_bug_logging.py' |
210 | --- tests/test_bug_logging.py 2011-03-23 11:12:12 +0000 |
211 | +++ tests/test_bug_logging.py 2011-03-30 07:39:33 +0000 |
212 | @@ -15,7 +15,7 @@ |
213 | TestCaseWithFixtures, |
214 | MockSomethingFixture, |
215 | ) |
216 | -from logging import ( |
217 | +from bug_logging import ( |
218 | LOG_ITEM_SEPARATOR, |
219 | Log, |
220 | LogEntry, |
221 | |
222 | === modified file 'tests/test_fail_filer.py' |
223 | --- tests/test_fail_filer.py 2011-03-30 07:39:33 +0000 |
224 | +++ tests/test_fail_filer.py 2011-03-30 07:39:33 +0000 |
225 | @@ -9,8 +9,6 @@ |
226 | # Linaro Infrastructure Team - initial implementation |
227 | ############################################################################### |
228 | from testtools import TestCase |
229 | - |
230 | -from testtools import TestCase |
231 | from datetime import ( |
232 | datetime, |
233 | ) |
234 | @@ -25,13 +23,13 @@ |
235 | SUCCESS_BUILD_STATE, |
236 | SPPH, |
237 | get_tags_for_fail, |
238 | + get_highest_version, |
239 | + filter_spph, |
240 | + get_build_list, |
241 | ) |
242 | from bug_reporting import ( |
243 | bug_already_filed_by_url, |
244 | -# get_project_url, |
245 | -# file_bug, |
246 | ) |
247 | -import config |
248 | from config import ( |
249 | get_service_root, |
250 | get_base_url, |
251 | @@ -42,9 +40,14 @@ |
252 | inited, |
253 | ConfigInitError, |
254 | LaunchpadError, |
255 | + set_verbose_messages, |
256 | ) |
257 | |
258 | |
259 | +TEST_FAIL_ARCH = 'armel' |
260 | +TEST_OK_ARCHS = ['i386', 'amd64'] |
261 | + |
262 | + |
263 | class TestBugTags(TestCase): |
264 | |
265 | def setUp(self): |
266 | @@ -69,6 +72,206 @@ |
267 | msg='Got more than default tags without match.') |
268 | |
269 | |
270 | +class TestFilter(TestCaseWithFixtures): |
271 | + |
272 | + class MockPackage(object): |
273 | + def __init__(self, name, version): |
274 | + self.source_package_version = version |
275 | + self.source_package_name = name |
276 | + |
277 | + class MockRecord(object): |
278 | + class CSP: |
279 | + def __init__(self, name, version): |
280 | + self.source_package_name = name |
281 | + self.source_package_version = version |
282 | + |
283 | + def __init__(self, arch, datecreated, state=FAILED_BUILD_STATE, |
284 | + name='packagename', version='1'): |
285 | + self.arch_tag = arch |
286 | + self.datecreated = datecreated |
287 | + self.buildstate = state |
288 | + self.current_source_publication = self.CSP(name, version) |
289 | + |
290 | + class MockArchive(object): |
291 | + def __init__(self, name, records_to_return=[]): |
292 | + self.name = name |
293 | + self.records_to_return = records_to_return |
294 | + |
295 | + def getBuildRecords(self, build_state, source_name): |
296 | + return self.records_to_return |
297 | + |
298 | + def setUp(self): |
299 | + super(TestFilter, self).setUp() |
300 | + |
301 | + def init_dummy_config(self): |
302 | + def mock_func(obj, appid, root, cachedir): |
303 | + return 'this is a launchpad instance' |
304 | + |
305 | + self.useFixture(MockSomethingFixture( |
306 | + Launchpad, 'login_with', classmethod(mock_func))) |
307 | + init('staging', 'dummyapp', 'dummycache') |
308 | + |
309 | + def test_filter_fail_record_not_filtered(self): |
310 | + self.init_dummy_config() |
311 | + spph = SPPH(self.MockPackage('packagefail', '1')) |
312 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
313 | + FAILED_BUILD_STATE) |
314 | + spph.add_build_record(failrecord) |
315 | + spph_list = dict() |
316 | + spph_list[spph.package_name] = spph |
317 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
318 | + []) |
319 | + self.assertIn(spph, filtered_list) |
320 | + |
321 | + def test_filter_success_record_filtered(self): |
322 | + self.init_dummy_config() |
323 | + spph = SPPH(self.MockPackage('packagesuccess', '1')) |
324 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
325 | + SUCCESS_BUILD_STATE) |
326 | + spph.add_build_record(failrecord) |
327 | + spph_list = dict() |
328 | + spph_list[spph.package_name] = spph |
329 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
330 | + []) |
331 | + self.assertNotIn(spph, filtered_list) |
332 | + |
333 | + def test_filter_only_other_arch_filtered(self): |
334 | + self.init_dummy_config() |
335 | + spph = SPPH(self.MockPackage('packageotherarch', '1')) |
336 | + failrecord = self.MockRecord(TEST_OK_ARCHS[0], datetime.now(), |
337 | + FAILED_BUILD_STATE) |
338 | + spph.add_build_record(failrecord) |
339 | + spph_list = dict() |
340 | + spph_list[spph.package_name] = spph |
341 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
342 | + []) |
343 | + self.assertNotIn(spph, filtered_list) |
344 | + |
345 | + def test_filter_no_arch_filtered(self): |
346 | + self.init_dummy_config() |
347 | + spph = SPPH(self.MockPackage('packagenobuilds', '1')) |
348 | + spph_list = dict() |
349 | + spph_list[spph.package_name] = spph |
350 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
351 | + []) |
352 | + self.assertNotIn(spph, filtered_list) |
353 | + |
354 | + def test_get_build_list_only_returns_exact_matches(self): |
355 | + packagename = 'packagesubstring' |
356 | + exactrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
357 | + SUCCESS_BUILD_STATE, packagename) |
358 | + nonexactrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
359 | + SUCCESS_BUILD_STATE, |
360 | + 'pre' + packagename + 'post') |
361 | + archive = self.MockArchive('archivename', |
362 | + [exactrecord, nonexactrecord]) |
363 | + build_records = get_build_list(archive, SUCCESS_BUILD_STATE, |
364 | + packagename) |
365 | + self.assertIn(exactrecord, build_records) |
366 | + self.assertNotIn(nonexactrecord, build_records) |
367 | + |
368 | + def test_filter_success_on_same_arch_same_version_filtered(self): |
369 | + self.init_dummy_config() |
370 | + packagename = 'packagefailandok' |
371 | + version = '1' |
372 | + fail_spph = SPPH(self.MockPackage(packagename, version)) |
373 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
374 | + FAILED_BUILD_STATE, packagename, version) |
375 | + successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
376 | + SUCCESS_BUILD_STATE, packagename, |
377 | + version) |
378 | + fail_spph.add_build_record(failrecord) |
379 | + spph_list = dict() |
380 | + spph_list[fail_spph.package_name] = fail_spph |
381 | + archive = self.MockArchive('archivename', [successrecord]) |
382 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
383 | + [(archive, 'archivename')]) |
384 | + self.assertNotIn(fail_spph, filtered_list) |
385 | + |
386 | + def test_filter_success_on_other_arch_not_filtered(self): |
387 | + self.init_dummy_config() |
388 | + packagename = 'packagename' |
389 | + version = '1' |
390 | + fail_spph = SPPH(self.MockPackage(packagename, version)) |
391 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
392 | + FAILED_BUILD_STATE, packagename, version) |
393 | + successrecord = self.MockRecord(TEST_OK_ARCHS[0], datetime.now(), |
394 | + SUCCESS_BUILD_STATE, packagename, |
395 | + version) |
396 | + fail_spph.add_build_record(failrecord) |
397 | + spph_list = dict() |
398 | + spph_list[fail_spph.package_name] = fail_spph |
399 | + archive = self.MockArchive('archivename', [successrecord]) |
400 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
401 | + [(archive, 'archivename')]) |
402 | + self.assertIn(fail_spph, filtered_list) |
403 | + |
404 | + def test_filter_success_on_higher_version_filtered(self): |
405 | + self.init_dummy_config() |
406 | + packagename = 'packagename' |
407 | + low_version = '1' |
408 | + high_version = '1.2.3' |
409 | + fail_spph = SPPH(self.MockPackage(packagename, low_version)) |
410 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
411 | + FAILED_BUILD_STATE, packagename, low_version) |
412 | + successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
413 | + SUCCESS_BUILD_STATE, packagename, |
414 | + high_version) |
415 | + fail_spph.add_build_record(failrecord) |
416 | + spph_list = dict() |
417 | + spph_list[fail_spph.package_name] = fail_spph |
418 | + archive = self.MockArchive('archivename', [successrecord]) |
419 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
420 | + [(archive, 'archivename')]) |
421 | + self.assertNotIn(fail_spph, filtered_list) |
422 | + |
423 | + def test_filter_success_on_lower_version_not_filtered(self): |
424 | + self.init_dummy_config() |
425 | + packagename = 'packagename' |
426 | + low_version = '1' |
427 | + high_version = '1.2.3' |
428 | + fail_spph = SPPH(self.MockPackage(packagename, high_version)) |
429 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
430 | + FAILED_BUILD_STATE, packagename, high_version) |
431 | + successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
432 | + SUCCESS_BUILD_STATE, packagename, |
433 | + low_version) |
434 | + fail_spph.add_build_record(failrecord) |
435 | + spph_list = dict() |
436 | + spph_list[fail_spph.package_name] = fail_spph |
437 | + archive = self.MockArchive('archivename', [successrecord]) |
438 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
439 | + [(archive, 'archivename')]) |
440 | + self.assertIn(fail_spph, filtered_list) |
441 | + |
442 | + def test_filter_success_on_lower_and_higher_version_filtered(self): |
443 | + self.init_dummy_config() |
444 | + packagename = 'midpackage' |
445 | + low_version = '1' |
446 | + mid_version = '2.1.3-1' |
447 | + high_version = '3.2.3' |
448 | + fail_spph = SPPH(self.MockPackage(packagename, mid_version)) |
449 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
450 | + FAILED_BUILD_STATE, packagename, mid_version) |
451 | + low_successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
452 | + SUCCESS_BUILD_STATE, packagename, |
453 | + low_version) |
454 | + high_successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
455 | + SUCCESS_BUILD_STATE, packagename, |
456 | + high_version) |
457 | + fail_spph.add_build_record(failrecord) |
458 | + spph_list = dict() |
459 | + spph_list[fail_spph.package_name] = fail_spph |
460 | + low_archive = self.MockArchive('archive_with_lower_version', |
461 | + [low_successrecord]) |
462 | + high_archive = self.MockArchive('archive_with_higher_version', |
463 | + [high_successrecord]) |
464 | + filtered_list = filter_spph(spph_list, TEST_FAIL_ARCH, TEST_OK_ARCHS, |
465 | + [(low_archive, 'lo_archivename'), |
466 | + (high_archive, 'hi_archivename')]) |
467 | + self.assertNotIn(fail_spph, filtered_list) |
468 | + |
469 | + |
470 | class TestSPPH(TestCaseWithFixtures): |
471 | |
472 | class MockPackage(object): |
473 | @@ -76,7 +279,7 @@ |
474 | self.source_package_version = version |
475 | self.source_package_name = name |
476 | |
477 | - class MockLog(object): |
478 | + class MockRecord(object): |
479 | def __init__(self, arch, datecreated, state=FAILED_BUILD_STATE): |
480 | self.arch_tag = arch |
481 | self.datecreated = datecreated |
482 | @@ -103,90 +306,96 @@ |
483 | spph = SPPH(self.MockPackage('dummy', '1.1.2-3')) |
484 | self.assertEquals(spph.version, '1.1.2-3') |
485 | |
486 | - def test_new_sppg_has_no_logs(self): |
487 | + def test_new_spph_has_no_records(self): |
488 | self.init_dummy_config() |
489 | spph = SPPH(self.MockPackage('dummy', '1.1.2-3')) |
490 | - self.assertTrue(len(spph.logs) == 0) |
491 | + self.assertEqual({}, spph.records) |
492 | |
493 | - def test_add_build_log_does_so(self): |
494 | + def test_add_build_record_does_so(self): |
495 | self.init_dummy_config() |
496 | spph = SPPH(self.MockPackage('dummy', '1')) |
497 | - log = self.MockLog('armel', datetime.now()) |
498 | - spph.add_build_log(log) |
499 | - self.assertEquals(spph.logs['armel'], log) |
500 | + record = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
501 | + spph.add_build_record(record) |
502 | + self.assertEquals(spph.records[TEST_FAIL_ARCH], record) |
503 | |
504 | def test_get_arch_does_so(self): |
505 | self.init_dummy_config() |
506 | spph = SPPH(self.MockPackage('dummy', '1')) |
507 | - log = self.MockLog('armel', datetime.now()) |
508 | - spph.add_build_log(log) |
509 | - self.assertEquals(spph.get_arch('armel'), log) |
510 | - self.assertEquals(spph.get_arch('i386'), None) |
511 | - |
512 | - def test_add_newer_build_log_replaces(self): |
513 | - self.init_dummy_config() |
514 | - spph = SPPH(self.MockPackage('dummy', '1')) |
515 | - oldlog = self.MockLog('armel', datetime.now()) |
516 | - newlog = self.MockLog('armel', datetime.now()) |
517 | - spph.add_build_log(oldlog) |
518 | - spph.add_build_log(newlog) |
519 | - self.assertEquals(spph.logs['armel'], newlog) |
520 | - |
521 | - def test_add_older_build_log_dont_replace(self): |
522 | - self.init_dummy_config() |
523 | - spph = SPPH(self.MockPackage('dummy', '1')) |
524 | - oldlog = self.MockLog('armel', datetime.now()) |
525 | - newlog = self.MockLog('armel', datetime.now()) |
526 | - spph.add_build_log(newlog) |
527 | - spph.add_build_log(oldlog) |
528 | - self.assertEquals(spph.logs['armel'], newlog) |
529 | - |
530 | - def test_add_other_arch_build_log_dont_replace(self): |
531 | - self.init_dummy_config() |
532 | - spph = SPPH(self.MockPackage('dummy', '1')) |
533 | - armlog = self.MockLog('armel', datetime.now()) |
534 | - i386log = self.MockLog('i386', datetime.now()) |
535 | - spph.add_build_log(armlog) |
536 | - spph.add_build_log(i386log) |
537 | - self.assertEquals(spph.logs['armel'], armlog) |
538 | - self.assertEquals(spph.logs['i386'], i386log) |
539 | - |
540 | - def test_is_not_ftbfs_when_no_log(self): |
541 | - self.init_dummy_config() |
542 | - spph = SPPH(self.MockPackage('dummy', '1')) |
543 | - self.assertFalse(spph.is_ftbfs('armel')) |
544 | - |
545 | - def test_is_ftbfs_when_failed_log(self): |
546 | - self.init_dummy_config() |
547 | - spph = SPPH(self.MockPackage('dummy', '1')) |
548 | - faillog = self.MockLog('armel', datetime.now(), FAILED_BUILD_STATE) |
549 | - spph.add_build_log(faillog) |
550 | - self.assertTrue(spph.is_ftbfs('armel')) |
551 | - |
552 | - def test_is_not_ftbfs_when_success_log(self): |
553 | - self.init_dummy_config() |
554 | - spph = SPPH(self.MockPackage('dummy', '1')) |
555 | - successlog = self.MockLog('armel', datetime.now(), SUCCESS_BUILD_STATE) |
556 | - spph.add_build_log(successlog) |
557 | - self.assertFalse(spph.is_ftbfs('armel')) |
558 | - |
559 | - def test_is_not_ftbfs_when_replaced_log(self): |
560 | - self.init_dummy_config() |
561 | - spph = SPPH(self.MockPackage('dummy', '1')) |
562 | - faillog = self.MockLog('armel', datetime.now(), FAILED_BUILD_STATE) |
563 | - successlog = self.MockLog('armel', datetime.now(), SUCCESS_BUILD_STATE) |
564 | - spph.add_build_log(faillog) |
565 | - spph.add_build_log(successlog) |
566 | - self.assertFalse(spph.is_ftbfs('armel')) |
567 | - |
568 | - def test_is_ftbfs_when_replaced_log(self): |
569 | - self.init_dummy_config() |
570 | - spph = SPPH(self.MockPackage('dummy', '1')) |
571 | - successlog = self.MockLog('armel', datetime.now(), SUCCESS_BUILD_STATE) |
572 | - faillog = self.MockLog('armel', datetime.now(), FAILED_BUILD_STATE) |
573 | - spph.add_build_log(successlog) |
574 | - spph.add_build_log(faillog) |
575 | - self.assertTrue(spph.is_ftbfs('armel')) |
576 | + record = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
577 | + spph.add_build_record(record) |
578 | + self.assertEquals(spph.get_arch(TEST_FAIL_ARCH), record) |
579 | + self.assertEquals(spph.get_arch(TEST_OK_ARCHS[0]), None) |
580 | + |
581 | + def test_add_newer_build_record_replaces(self): |
582 | + self.init_dummy_config() |
583 | + spph = SPPH(self.MockPackage('dummy', '1')) |
584 | + oldrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
585 | + newrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
586 | + spph.add_build_record(oldrecord) |
587 | + spph.add_build_record(newrecord) |
588 | + self.assertEquals(spph.records[TEST_FAIL_ARCH], newrecord) |
589 | + |
590 | + def test_add_older_build_record_dont_replace(self): |
591 | + self.init_dummy_config() |
592 | + spph = SPPH(self.MockPackage('dummy', '1')) |
593 | + oldrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
594 | + newrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
595 | + spph.add_build_record(newrecord) |
596 | + spph.add_build_record(oldrecord) |
597 | + self.assertEquals(spph.records[TEST_FAIL_ARCH], newrecord) |
598 | + |
599 | + def test_add_other_arch_build_record_dont_replace(self): |
600 | + self.init_dummy_config() |
601 | + spph = SPPH(self.MockPackage('dummy', '1')) |
602 | + armrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now()) |
603 | + i386record = self.MockRecord(TEST_OK_ARCHS[0], datetime.now()) |
604 | + spph.add_build_record(armrecord) |
605 | + spph.add_build_record(i386record) |
606 | + self.assertEquals(spph.records[TEST_FAIL_ARCH], armrecord) |
607 | + self.assertEquals(spph.records[TEST_OK_ARCHS[0]], i386record) |
608 | + |
609 | + def test_is_not_ftbfs_when_no_record(self): |
610 | + self.init_dummy_config() |
611 | + spph = SPPH(self.MockPackage('dummy', '1')) |
612 | + self.assertFalse(spph.is_ftbfs(TEST_FAIL_ARCH)) |
613 | + |
614 | + def test_is_ftbfs_when_failed_record(self): |
615 | + self.init_dummy_config() |
616 | + spph = SPPH(self.MockPackage('dummy', '1')) |
617 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
618 | + FAILED_BUILD_STATE) |
619 | + spph.add_build_record(failrecord) |
620 | + self.assertTrue(spph.is_ftbfs(TEST_FAIL_ARCH)) |
621 | + |
622 | + def test_is_not_ftbfs_when_success_record(self): |
623 | + self.init_dummy_config() |
624 | + spph = SPPH(self.MockPackage('dummy', '1')) |
625 | + successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
626 | + SUCCESS_BUILD_STATE) |
627 | + spph.add_build_record(successrecord) |
628 | + self.assertFalse(spph.is_ftbfs(TEST_FAIL_ARCH)) |
629 | + |
630 | + def test_is_not_ftbfs_when_replaced_record(self): |
631 | + self.init_dummy_config() |
632 | + spph = SPPH(self.MockPackage('dummy', '1')) |
633 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
634 | + FAILED_BUILD_STATE) |
635 | + successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
636 | + SUCCESS_BUILD_STATE) |
637 | + spph.add_build_record(failrecord) |
638 | + spph.add_build_record(successrecord) |
639 | + self.assertFalse(spph.is_ftbfs(TEST_FAIL_ARCH)) |
640 | + |
641 | + def test_is_ftbfs_when_replaced_record(self): |
642 | + self.init_dummy_config() |
643 | + spph = SPPH(self.MockPackage('dummy', '1')) |
644 | + successrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
645 | + SUCCESS_BUILD_STATE) |
646 | + failrecord = self.MockRecord(TEST_FAIL_ARCH, datetime.now(), |
647 | + FAILED_BUILD_STATE) |
648 | + spph.add_build_record(successrecord) |
649 | + spph.add_build_record(failrecord) |
650 | + self.assertTrue(spph.is_ftbfs(TEST_FAIL_ARCH)) |
651 | |
652 | def test_spph_is_higher_version(self): |
653 | self.init_dummy_config() |
654 | @@ -212,6 +421,48 @@ |
655 | newspph = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu2')) |
656 | self.assertTrue(newspph.is_higher_version_than(oldspph)) |
657 | |
658 | + def test_get_highest_version_finds_single_version(self): |
659 | + self.init_dummy_config() |
660 | + spph = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu2')) |
661 | + spphlist = [spph] |
662 | + self.assertEquals(spph, get_highest_version(spphlist)) |
663 | + |
664 | + def test_get_highest_version_returns_first_of_same_version(self): |
665 | + self.init_dummy_config() |
666 | + spph_good = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu2')) |
667 | + spph_bad = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu2')) |
668 | + spphlist = [spph_good, spph_bad] |
669 | + self.assertEquals(spph_good, get_highest_version(spphlist)) |
670 | + |
671 | + def test_get_highest_version_returns_highest_version_in_order(self): |
672 | + self.init_dummy_config() |
673 | + spph_good = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu3')) |
674 | + spph_bad = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu2')) |
675 | + spphlist = [spph_good, spph_bad] |
676 | + self.assertEquals(spph_good, get_highest_version(spphlist)) |
677 | + |
678 | + def test_get_highest_version_returns_highest_version_out_of_order(self): |
679 | + self.init_dummy_config() |
680 | + spph_good = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu3')) |
681 | + spph_bad = SPPH(self.MockPackage('packageversion', '0.5.32-0ubuntu2')) |
682 | + spphlist = [spph_bad, spph_good] |
683 | + self.assertEquals(spph_good, get_highest_version(spphlist)) |
684 | + |
685 | + def test_get_highest_version_returns_highest_version_mixed_order(self): |
686 | + self.init_dummy_config() |
687 | + spph_good = SPPH(self.MockPackage('packageversion', '99')) |
688 | + spph_bad1 = SPPH(self.MockPackage('packageversion', '1')) |
689 | + spph_bad2 = SPPH(self.MockPackage('packageversion', '2')) |
690 | + spph_bad3 = SPPH(self.MockPackage('packageversion', '3')) |
691 | + spphlist = [spph_bad1, spph_bad2, spph_bad1, spph_good, spph_bad3] |
692 | + self.assertEquals(spph_good, get_highest_version(spphlist)) |
693 | + |
694 | + def test_get_highest_version_returns_null(self): |
695 | + self.init_dummy_config() |
696 | + self.assertTrue(get_highest_version([]) is None) |
697 | + self.assertTrue(get_highest_version([None]) is None) |
698 | + self.assertTrue(get_highest_version([None, None]) is None) |
699 | + |
700 | |
701 | class TestFileBug(TestCase): |
702 |
9 + help='Disable bug filing. Combine with -v to enable useful output.')
Should -v just be implied?
61 + if spph_queue is None: "None supplied as list.")
62 + raise NoVersionError(
I tend to not code defensively in cases like this. The developer
will get an error that is almost as obvious when it tries to iterate the
list, so I lean towards brevity. I reserve the checks for when the error
would be obtuse, or the code will do the wrong thing.
That's just my preference though, if you prefer this then leave it as is.
126 + if spph is None:
127 + continue
...
150 + spph = None
Could that just be a "break" where you set spph to None?
This looks good otherwise.
Thanks,
James