~launchpad-pqm/launchpad/devel

7570.3.4 by Jeroen Vermeulen
Got test setup working.
1
= Checking messages against gettext =
2
3
Before accepting a translation message, Launchpad runs it through
4
gettext to check for certain errors.  For example, if the message is
5
marked as a C format string in the template, using the c-format flag,
6
the set of % conversion specifiers in the translation should be
7
compatible with those of the original English string in the template.
8
Other languages such as Python have similar format string capabilities
9
with corresponding flags.
10
11
But sometimes it is possible for invalid messages to make it into the
12
database.  It may be due to a bug in Launchpad, or it could be due to a
13
gettext update that notices incompatibilities that earlier versions
14
didn't.
15
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
16
17
== Test setup ==
18
19
Here we use an instrumented version of the script that counts messages
20
checked instead of real time.  This gets around the indeterminate commit
21
points that would otherwise be in the output.
22
23
    >>> from datetime import datetime
24
    >>> from pytz import timezone
25
26
    >>> from zope.security.proxy import removeSecurityProxy
7570.3.4 by Jeroen Vermeulen
Got test setup working.
27
28
    >>> from canonical.database.sqlbase import quote
8751.1.1 by Danilo Šegan
Store migration changes so far.
29
    >>> from lp.translations.scripts.gettext_check_messages import (
7570.3.4 by Jeroen Vermeulen
Got test setup working.
30
    ...     GettextCheckMessages)
12070.1.4 by Tim Penhey
Move FakeLogger and BufferLogger to lp.services.log.logging and delete the QuietFakeLogger.
31
    >>> from lp.services.log.logger import FakeLogger
10315.2.4 by Jeroen Vermeulen
Replace all "Fake" and "Mock" transaction managers I can find with one implementation.
32
    >>> from lp.testing.faketransaction import FakeTransaction
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
33
7570.3.4 by Jeroen Vermeulen
Got test setup working.
34
    >>> class InstrumentedGettextCheckMessages(GettextCheckMessages):
35
    ...     _commit_interval = 3
36
    ...     def _get_time(self):
37
    ...         return self._check_count
38
7570.3.9 by Jeroen Vermeulen
Document/test commit points as well.
39
    >>> def run_checker(options, commit_interval=None):
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
40
    ...     """Create and run an instrumented `GettextCheckMessages`."""
41
    ...     checker = InstrumentedGettextCheckMessages(
42
    ...         'gettext-check-messages-test', test_args=options)
43
    ...     checker.logger = FakeLogger()
10315.2.4 by Jeroen Vermeulen
Replace all "Fake" and "Mock" transaction managers I can find with one implementation.
44
    ...     checker.txn = FakeTransaction(log_calls=True)
7570.3.9 by Jeroen Vermeulen
Document/test commit points as well.
45
    ...     if commit_interval is not None:
46
    ...         checker._commit_interval = commit_interval
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
47
    ...     checker.main()
48
7570.3.4 by Jeroen Vermeulen
Got test setup working.
49
    >>> logout()
50
    >>> login('foo.bar@canonical.com')
51
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
52
    >>> UTC = timezone('UTC')
53
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
54
    >>> pofile = factory.makePOFile()
55
    >>> template = pofile.potemplate
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
56
57
A sample translatable message is flagged as containing a C-style format
58
string.  This means that any "%d" sequences and such are significant.
59
So gettext will check those in the translations for compatibility with
60
those in the original message.
61
7570.3.4 by Jeroen Vermeulen
Got test setup working.
62
    >>> potmsgset = factory.makePOTMsgSet(
7519.2.59 by Danilo Šegan
Fix up a number of failing tests.
63
    ...     potemplate=template, singular=u'%d n', sequence=1)
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
64
    >>> potmsgset.flagscomment = 'c-format'
65
    >>> potmsgset.flags
66
    [u'c-format']
67
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
68
The sample message has an upstream translation, and an Ubuntu
69
in Launchpad that differs from the upstream one.
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
70
7675.1006.1 by Henning Eggers
Fixed browser and doc tests.
71
    >>> ubuntu_message = factory.makeCurrentTranslationMessage(
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
72
    ...     pofile=pofile, potmsgset=potmsgset, translator=template.owner,
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
73
    ...     reviewer=template.owner, translations=[u'%d c'])
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
74
    >>> ubuntu_message = removeSecurityProxy(ubuntu_message)
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
75
7675.1006.1 by Henning Eggers
Fixed browser and doc tests.
76
    >>> upstream_message = factory.makeCurrentTranslationMessage(
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
77
    ...     pofile=pofile, potmsgset=potmsgset, translator=template.owner,
7675.1006.1 by Henning Eggers
Fixed browser and doc tests.
78
    ...     reviewer=template.owner, translations=[u'%d i'])
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
79
    >>> upstream_message = removeSecurityProxy(upstream_message)
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
80
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
81
    >>> upstream_message.is_current_ubuntu = False
82
    >>> ubuntu_message.is_current_upstream = False
83
    >>> upstream_message.is_current_upstream = True
84
    >>> ubuntu_message.is_current_ubuntu = True
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
85
86
87
== Basic operation ==
88
89
The gettext_check_message script goes through a given set of messages
90
and re-does the gettext check.  Which messages it checks is specified as
91
a plain SQL WHERE clause.
92
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
93
    >>> run_checker(['-vv', "-w id=%s" % quote(ubuntu_message.id)])
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
94
    DEBUG Checking messages matching:  id=...
95
    DEBUG Checking message ...
96
    DEBUG Commit point.
10315.2.4 by Jeroen Vermeulen
Replace all "Fake" and "Mock" transaction managers I can find with one implementation.
97
    COMMIT
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
98
    INFO Done.
99
    INFO Messages checked: 1
100
    INFO Validation errors: 0
101
    INFO Messages disabled: 0
102
    INFO Commit points: ...
7570.3.4 by Jeroen Vermeulen
Got test setup working.
103
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
104
105
== Detecting errors ==
106
107
If a translation fails to validate against its potmsgset, the script
108
detects the problem when it checks that message.
109
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
110
    >>> ubuntu_message.is_current_ubuntu
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
111
    True
112
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
113
    >>> ubuntu_message.translations = [u'%s c']
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
114
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
115
    >>> run_checker(["-w id=%s" % quote(ubuntu_message.id)])
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
116
    DEBUG Checking messages matching:  id=...
117
    DEBUG Checking message ...
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
118
    INFO ... (ubuntu): format specifications ... are not the same
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
119
    DEBUG Commit point.
120
    COMMIT
121
    DEBUG Commit point.
122
    COMMIT
123
    INFO Done.
124
    INFO Messages checked: 1
125
    INFO Validation errors: 1
126
    INFO Messages disabled: 1
127
    INFO Commit points: ...
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
128
129
The failed message is demoted to a mere suggestion.
130
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
131
    >>> ubuntu_message.is_current_ubuntu
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
132
    False
133
134
135
== Output ==
136
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
137
Besides Ubuntu messages, the script's output also distinguishes
138
upstream ones, and ones that are completely unused. The upstream message
11472.1.28 by Henning Eggers
Test was crippled.
139
happens to produce validation errors.
140
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
141
    >>> upstream_message.translations = [u'%s %s i']
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
142
143
In this example we'd like to see a nicely predictable ordering, so we
144
add a sort order using the -o option.
145
146
    >>> run_checker(['-w', 'potmsgset=%s' % quote(potmsgset), '-o',  'id'])
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
147
    DEBUG Checking messages matching:  potmsgset=...
148
    DEBUG Checking message ...
149
    INFO ... (unused): format specifications ... are not the same
150
    DEBUG Commit point.
151
    COMMIT
152
    DEBUG Checking message ...
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
153
    INFO ... (upstream): number of format specifications ... does not match...
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
154
    DEBUG Commit point.
155
    COMMIT
156
    INFO Done.
157
    INFO Messages checked: 2
158
    INFO Validation errors: 2
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
159
    INFO Messages disabled: 1
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
160
    INFO Commit points: 2
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
161
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
162
The script also notes when a message is shared between upstream and Ubuntu.
163
164
    >>> upstream_message.is_current_ubuntu = True
165
    >>> upstream_message.is_current_upstream = True
166
    >>> run_checker(["-w id=%s" % quote(upstream_message.id)])
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
167
    DEBUG ...
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
168
    INFO ... (ubuntu, upstream): number of format specifications ...
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
169
170
171
== Dry runs ==
172
173
The --dry-run option makes the script abort all its database changes.
174
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
175
    >>> ubuntu_message.is_current_ubuntu = True
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
176
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
177
    >>> run_checker(["-w id=%s" % quote(ubuntu_message.id), '--dry-run'])
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
178
    INFO Dry run.  Not making any changes.
179
    DEBUG Checking messages matching:  id=...
180
    DEBUG Checking message ...
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
181
    INFO ... (ubuntu): format specifications ... are not the same
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
182
    DEBUG Commit point.
183
    ABORT
184
    DEBUG Commit point.
185
    ABORT
186
    INFO Done.
187
    INFO Messages checked: 1
188
    INFO Validation errors: 1
189
    INFO Messages disabled: 1
190
    INFO Commit points: 2
7570.3.8 by Jeroen Vermeulen
Added lots of testing.
191
192
7570.3.9 by Jeroen Vermeulen
Document/test commit points as well.
193
== Commit points ==
194
195
To avoid long-running transactions and potential locks, the script
7570.3.10 by Jeroen Vermeulen
More explanation.
196
commits regularly.  Normally this happens every few seconds.  For the
197
purpose of this test we count messages checked.  If we set the commit
198
interval to 1, we get a commit after every message plus one at the end
199
to close things off neatly.
7570.3.9 by Jeroen Vermeulen
Document/test commit points as well.
200
201
    >>> run_checker(["-w potmsgset=%s" % quote(potmsgset)], commit_interval=1)
12070.1.41 by Tim Penhey
Changed my mind about the colon. Removed it.
202
    DEBUG Checking messages matching:  potmsgset=...
203
    DEBUG Checking message ...
204
    INFO ... (...): number of format specifications ...
205
    DEBUG Commit point.
206
    COMMIT
207
    DEBUG Checking message ...
208
    INFO ... (...): format specifications ... are not the same
209
    DEBUG Commit point.
210
    COMMIT
211
    DEBUG Commit point.
212
    COMMIT
213
    INFO Done.
214
    INFO Messages checked: 2
215
    INFO Validation errors: 2
216
    INFO Messages disabled: 0
217
    INFO Commit points: 3