Merge lp:~jtv/launchpad/bug-533668 into lp:launchpad

Proposed by Jeroen T. Vermeulen on 2010-03-08
Status: Merged
Approved by: Aaron Bentley on 2010-03-08
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~jtv/launchpad/bug-533668
Merge into: lp:launchpad
Diff against target: 101 lines (+30/-9)
3 files modified
lib/lp/translations/doc/translations-export-to-branch.txt (+4/-3)
lib/lp/translations/scripts/tests/test_translations_to_branch.py (+24/-1)
lib/lp/translations/scripts/translations_to_branch.py (+2/-5)
To merge this branch: bzr merge lp:~jtv/launchpad/bug-533668
Reviewer Review Type Date Requested Status
Aaron Bentley (community) Approve on 2010-03-08
Canonical Launchpad Engineering code 2010-03-08 Pending
Review via email: mp+20902@code.launchpad.net

Commit Message

Hande non-ascii exceptions in translations-to-bzr exports.

Description of the Change

== Bug 533668 ==

When a project name has non-ascii characters, and translations export to a branch fails for that project, the attempt to log an error message breaks. This happened with µBlogger the other day.

Actually, even before we get to logging a message, it's the attempt to produce a sensible error message out of the exception that breaks.

So this branch replaces the logic with a built-in one: Exception.__repr__. In the duck-typing tradition, this takes the question of str-vs-unicode out of our code and also does the right thing with exceptions without messages, as well as extra arguments describing the exception.

To test:
{{{
./bin/test -vv -t exportToBranches_handles_nonascii
}}}

No lint.

To Q/A, have this run on the staging codehosting server, against the staging db. The export for µBlogger should fail and produce a sensible error message, after which the script should recover and continue to run rather than bail out.

Jeroen

To post a comment you must log in.
Aaron Bentley (abentley) wrote :

As discussed on IRC, please use repr(e) rather than e.__repr__(). Aside from that, looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/translations/doc/translations-export-to-branch.txt'
2--- lib/lp/translations/doc/translations-export-to-branch.txt 2009-11-18 13:26:03 +0000
3+++ lib/lp/translations/doc/translations-export-to-branch.txt 2010-03-09 04:39:30 +0000
4@@ -242,7 +242,7 @@
5 <BLANKLINE>
6 DEBUG ...
7 INFO Unlock.
8- ERROR Failure: Simulated race condition.
9+ ERROR Failure: ConcurrentUpdateError(...Simulated race condition...)
10 INFO Processed 1 item(s); 1 failure(s).
11
12
13@@ -261,8 +261,9 @@
14 >>> script.main()
15 INFO Exporting to translations branches.
16 INFO Exporting Gazblachko trunk series.
17- ERROR Failure: Translations branch for Gazblachko trunk series
18- has pending translations changes. Not committing.
19+ ERROR Failure: ConcurrentUpdateError(...Translations branch for
20+ Gazblachko trunk series has pending translations changes.
21+ Not committing...)
22 INFO Processed 1 item(s); 1 failure(s).
23
24 There is one problem with detecting this race condition. Jobs are never
25
26=== modified file 'lib/lp/translations/scripts/tests/test_translations_to_branch.py'
27--- lib/lp/translations/scripts/tests/test_translations_to_branch.py 2009-10-19 10:09:25 +0000
28+++ lib/lp/translations/scripts/tests/test_translations_to_branch.py 2010-03-09 04:39:30 +0000
29@@ -1,4 +1,4 @@
30-# Copyright 2009 Canonical Ltd. This software is licensed under the
31+# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
32 # GNU Affero General Public License version 3 (see the file LICENSE).
33
34 """Acceptance test for the translations-export-to-branch script."""
35@@ -11,15 +11,21 @@
36
37 from zope.security.proxy import removeSecurityProxy
38
39+from canonical.launchpad.scripts.logger import QuietFakeLogger
40 from canonical.launchpad.scripts.tests import run_script
41 from canonical.testing import ZopelessAppServerLayer
42
43 from lp.testing import map_branch_contents, TestCaseWithFactory
44+from lp.testing.fakemethod import FakeMethod
45
46 from lp.translations.scripts.translations_to_branch import (
47 ExportTranslationsToBranch)
48
49
50+class GruesomeException(Exception):
51+ """CPU on fire. Or some other kind of failure, like."""
52+
53+
54 class TestExportTranslationsToBranch(TestCaseWithFactory):
55
56 layer = ZopelessAppServerLayer
57@@ -122,6 +128,23 @@
58 self.assertEqual(
59 None, re.search("INFO\s+Committed [0-9]+ file", stderr))
60
61+ def test_exportToBranches_handles_nonascii_exceptions(self):
62+ # There's an exception handler in _exportToBranches that must
63+ # cope well with non-ASCII exception strings.
64+ exporter = ExportTranslationsToBranch(test_args=[])
65+ exporter.logger = QuietFakeLogger()
66+ boom = u'\u2639'
67+ exporter._exportToBranch = FakeMethod(failure=GruesomeException(boom))
68+
69+ exporter._exportToBranches([self.factory.makeProductSeries()])
70+
71+ self.assertEqual(1, exporter._exportToBranch.call_count)
72+
73+ exporter.logger.output_file.seek(0)
74+ message = exporter.logger.output_file.read()
75+ self.assertTrue(message.startswith("ERROR"))
76+ self.assertTrue("GruesomeException" in message)
77+
78
79 class TestExportToStackedBranch(TestCaseWithFactory):
80 """Test workaround for bzr bug 375013."""
81
82=== modified file 'lib/lp/translations/scripts/translations_to_branch.py'
83--- lib/lp/translations/scripts/translations_to_branch.py 2010-01-21 00:46:48 +0000
84+++ lib/lp/translations/scripts/translations_to_branch.py 2010-03-09 04:39:30 +0000
85@@ -1,4 +1,4 @@
86-# Copyright 2009 Canonical Ltd. This software is licensed under the
87+# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
88 # GNU Affero General Public License version 3 (see the file LICENSE).
89
90 """Export translation snapshots to bzr branches where requested."""
91@@ -238,10 +238,7 @@
92 raise
93 except Exception, e:
94 items_failed += 1
95- message = unicode(e)
96- if message == u'':
97- message = e.__class__.__name__
98- self.logger.error("Failure: %s" % message)
99+ self.logger.error("Failure: %s" % repr(e))
100 if self.txn:
101 self.txn.abort()
102