Merge lp:~james-w/udd/storm-unicode-fixes into lp:udd

Proposed by James Westby
Status: Merged
Merged at revision: 601
Proposed branch: lp:~james-w/udd/storm-unicode-fixes
Merge into: lp:udd
Prerequisite: lp:~james-w/udd/storm
Diff against target: 505 lines (+208/-29)
5 files modified
udd/icommon.py (+186/-21)
udd/scripts/mass_import.py (+6/-2)
udd/tests/test_commit_database.py (+1/-1)
udd/tests/test_revid_database.py (+1/-1)
udd/tests/test_status_database.py (+14/-4)
To merge this branch: bzr merge lp:~james-w/udd/storm-unicode-fixes
Reviewer Review Type Date Requested Status
Martin Packman Approve
Vincent Ladeuil Needs Information
John A Meinel Approve
James Westby Pending
Review via email: mp+113004@code.launchpad.net

This proposal supersedes a proposal from 2012-07-02.

Description of the change

Hi,

This fixes the issues that Max found where we weren't using unicode for
TEXT content, which meant the info was stored as blobs and problems
happened.

Thanks,

James

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 7/2/2012 12:03 PM, James Westby wrote:
> James Westby has proposed merging
> lp:~james-w/udd/storm-unicode-fixes into lp:udd with
> lp:~james-w/udd/storm as a prerequisite.
>
> Requested reviews: James Westby (james-w)
>
> For more details, see:
> https://code.launchpad.net/~james-w/udd/storm-unicode-fixes/+merge/113004
>
> Hi,
>
> This fixes the issues that Max found where we weren't using unicode
> for TEXT content, which meant the info was stored as blobs and
> problems happened.
>
> Thanks,
>
> James
>

This looks pretty good to me.

 review: approve
John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk/xc+EACgkQJdeBCYSNAAPAjACdFDMf3zAcN6xOdBjxMI530Rjk
FGUAn0GISTMu57DTZnjqS4YpYUpTuaNV
=B8FQ
-----END PGP SIGNATURE-----

review: Approve
Revision history for this message
Martin Packman (gz) wrote :

For background for this change see UDD list thread:
<https://lists.ubuntu.com/archives/ubuntu-distributed-devel/2012-April/001085.html>

I'd like to see here is documentation for why SHAs and testaments are being stored as text, and whether it's just to avoid rewriting existing data. From experience it doesn't actually matter much storing hashes as hex digest text rather than their raw form.

My main complaint is this branch and its prereq make it harder to tell whether a variable should be bytes or unicode, tending to just add casts in various places without documenting which methods expect what or sticking to one clear rule.

     def check(self, version, revid, suite, branch):
+ revid = unicode(revid)
         sha = self.get_testament_sha1(branch.repository, revid)

This is the kind of thing I mean. This change casts the arg to unicode, but before passing back to the bzr layer which expects bytes, so relies on bzrlib autocasting back. Only switching to unicode at db insert and retrieve would be less confusing.

=== modified file 'udd/tests/test_count_outstanding_jobs.py'

Test fix not related to unicode usage?

-import sqlite3
+from pysqlite2.dbapi2 import OperationalError

So UDD now depends on having external pysqlite2 package?

=== modified file 'udd/tests/test_mass_import.py'

Test fix not related to unicode usage?

review: Needs Information
Revision history for this message
Vincent Ladeuil (vila) wrote :

15 FAILURES_TABLE_CREATE = '''create table if not exists %s
16 (package text constraint nonull NOT NULL,
17 - reason blob,
18 + reason text,

24 OLD_FAILURES_TABLE_CREATE = '''create table if not exists %s
25 (package text constraint nonull NOT NULL,
26 - reason blob,
27 + reason text,

34 RETRY_TABLE_CREATE = '''create table if not exists %s
35 - (signature blob constraint nonull NOT NULL,
36 + (signature text constraint nonull NOT NULL,

Don't the above changes requires some db migration ?

If not, can you explain why ?

Same remark as gz regarding pysqlite2: is that a new dependency ?

Also, why is it the only place you made this change when sqlite3 is used in
other places ?

review: Needs Information
Revision history for this message
James Westby (james-w) wrote :

On Mon, 02 Jul 2012 11:23:18 -0000, Martin Packman <email address hidden> wrote:
> I'd like to see here is documentation for why SHAs and testaments are
> being stored as text, and whether it's just to avoid rewriting
> existing data. From experience it doesn't actually matter much storing
> hashes as hex digest text rather than their raw form.

Yeah, it's because the db has them as TEXT. I agree that BLOB would make
more sense, but wanted to avoid a data transition.

> My main complaint is this branch and its prereq make it harder to tell
> whether a variable should be bytes or unicode, tending to just add
> casts in various places without documenting which methods expect what
> or sticking to one clear rule.

I agree that the docs could be better, I did have a rule (which
admittedly may not be all that clear):

  If it's text require unicode in the apis, if not then do it in the db
  layer.

> def check(self, version, revid, suite, branch):
> + revid = unicode(revid)
> sha = self.get_testament_sha1(branch.repository, revid)
>
> This is the kind of thing I mean. This change casts the arg to
> unicode, but before passing back to the bzr layer which expects bytes,
> so relies on bzrlib autocasting back. Only switching to unicode at db
> insert and retrieve would be less confusing.

Yeah, I should do the cast later when it hits the db, rather than before
bzrlib gets it.

> === modified file 'udd/tests/test_count_outstanding_jobs.py'
>
> Test fix not related to unicode usage?
>
> -import sqlite3
> +from pysqlite2.dbapi2 import OperationalError
>
> So UDD now depends on having external pysqlite2 package?

That's the error that storm raises. I mistakenly assumed it was the
built in version.

I'll change it to import sqlite from storm, so that it uses whichever
one storm has found.

> === modified file 'udd/tests/test_mass_import.py'
>
> Test fix not related to unicode usage?

Yep, I assume the test was added after the storm branch was reverted,
but didn't cause a test conflict. I can move it in to the earlier branch
if you like?

Thanks,

James

Revision history for this message
James Westby (james-w) wrote :

On Mon, 02 Jul 2012 16:12:20 -0000, Vincent Ladeuil <email address hidden> wrote:
> Review: Needs Information
>
> 15 FAILURES_TABLE_CREATE = '''create table if not exists %s
> 16 (package text constraint nonull NOT NULL,
> 17 - reason blob,
> 18 + reason text,
>
> 24 OLD_FAILURES_TABLE_CREATE = '''create table if not exists %s
> 25 (package text constraint nonull NOT NULL,
> 26 - reason blob,
> 27 + reason text,
>
> 34 RETRY_TABLE_CREATE = '''create table if not exists %s
> 35 - (signature blob constraint nonull NOT NULL,
> 36 + (signature text constraint nonull NOT NULL,
>
>
> Don't the above changes requires some db migration ?
>
> If not, can you explain why ?

Because as I understand it they are only there to use up characters in
sqlite. Defining the columns with those types didn't stop the data being
stored in another type, and didn't stop me from assuming that they
were correct and not fixing the things in this branch first time around.

They are purely for documentation (hence changing them to match what is
stored) but as such a db migration isn't really needed.

It's probably the case that the dbs on production will keep the wrong
schema, but I don't care enough about that when the point is to delete
them.

> Also, why is it the only place you made this change when sqlite3 is used in
> other places ?

It's the only one where the test failed, because it's storm that is
generating the error.

Thanks,

James

lp:~james-w/udd/storm-unicode-fixes updated
601. By James Westby

Import sqlite from storm so we are using the same one, thanks Max.

Revision history for this message
Martin Packman (gz) wrote :

> Yeah, it's because the db has them as TEXT. I agree that BLOB would make
> more sense, but wanted to avoid a data transition.

Great, a comment to that effect by the table creation should do.

> I agree that the docs could be better, I did have a rule (which
> admittedly may not be all that clear):
>
> If it's text require unicode in the apis, if not then do it in the db
> layer.

That rule makes sense, but there are currently some exceptions to it.

> Yeah, I should do the cast later when it hits the db, rather than before
> bzrlib gets it.

Right. Having outstanding_marks deliberately use the db form is a source of some of the pain here.

> That's the error that storm raises. I mistakenly assumed it was the
> built in version.
>
> I'll change it to import sqlite from storm, so that it uses whichever
> one storm has found.

Yup, we just want the import fallback logic in one place then to use the bound name from there. As storm has it, using that everywhere sounds good.

> Yep, I assume the test was added after the storm branch was reverted,
> but didn't cause a test conflict. I can move it in to the earlier branch
> if you like?

No need, just checking that was the case.

review: Approve
Revision history for this message
James Westby (james-w) wrote :

On Mon, 02 Jul 2012 17:07:23 -0000, Martin Packman <email address hidden> wrote:
> Great, a comment to that effect by the table creation should do.

Done.

> That rule makes sense, but there are currently some exceptions to it.

If you can point them out I'll see about fixing them.

> > Yeah, I should do the cast later when it hits the db, rather than before
> > bzrlib gets it.
>
> Right. Having outstanding_marks deliberately use the db form is a source of some of the pain here.

Yeah, it does make some things a bit odd. Running on postgres will allow
us to delete that code though, because it was a way to avoid sqlite
locking.

> Yup, we just want the import fallback logic in one place then to use the bound name from there. As storm has it, using that everywhere sounds good.

Done.

> > Yep, I assume the test was added after the storm branch was reverted,
> > but didn't cause a test conflict. I can move it in to the earlier branch
> > if you like?
>
> No need, just checking that was the case.

Ok.

Thanks,

James

lp:~james-w/udd/storm-unicode-fixes updated
602. By James Westby

Document some of the db methods.

603. By James Westby

Add a comment as to why revid and testament are TEXT. Thanks Martin.

604. By James Westby

Merged storm into storm-unicode-fixes.

605. By James Westby

Merged storm into storm-unicode-fixes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'udd/icommon.py'
2--- udd/icommon.py 2012-07-03 17:10:24 +0000
3+++ udd/icommon.py 2012-07-03 17:10:24 +0000
4@@ -42,7 +42,7 @@
5 # below. Some way to share the config is needed -- vila 2011-12-07
6 conf = iconfig.ImporterStack()
7
8-running_sentinel = "Apparently the supervisor died\n"
9+running_sentinel = u"Apparently the supervisor died\n"
10 no_lock_returncode = 139
11
12
13@@ -453,7 +453,7 @@
14 FAILURES_TABLE = "failures"
15 FAILURES_TABLE_CREATE = '''create table if not exists %s
16 (package text constraint nonull NOT NULL,
17- reason blob,
18+ reason text,
19 when_failed timestamp,
20 emailed integer default 0,
21 constraint isprimary PRIMARY KEY
22@@ -464,7 +464,7 @@
23 OLD_FAILURES_TABLE = "old_failures"
24 OLD_FAILURES_TABLE_CREATE = '''create table if not exists %s
25 (package text constraint nonull NOT NULL,
26- reason blob,
27+ reason text,
28 when_failed timestamp,
29 last_failed timestamp,
30 failure_count integer,
31@@ -499,7 +499,7 @@
32
33 RETRY_TABLE = "should_retry"
34 RETRY_TABLE_CREATE = '''create table if not exists %s
35- (signature blob constraint nonull NOT NULL,
36+ (signature text constraint nonull NOT NULL,
37 constraint isprimary PRIMARY KEY
38 (signature))''' % RETRY_TABLE
39 RETRY_TABLE_SELECT = '''select * from %s where signature=?''' % RETRY_TABLE
40@@ -545,6 +545,7 @@
41 self._add_job(c, row[0], self.JOB_TYPE_PRIORITY)
42
43 def add_jobs_for_interrupted(self):
44+ """Add all interrupted jobs to the queue."""
45 with Cursor(self.conn) as c:
46 rows = c.execute('select * from %s where reason=?'
47 % self.FAILURES_TABLE, (running_sentinel,))
48@@ -578,10 +579,31 @@
49 return ret
50
51 def start_package(self, package):
52+ """Note that the import of `package` is being started.
53+
54+ :param package: the package name that is being imported
55+ :type package: unicode
56+ :return: the id assigned to the job.
57+ :rtype: int
58+ """
59 with Cursor(self.conn) as c:
60 return self._start_package(c, package)
61
62 def finish_job(self, package, job_id, success, output, when=None):
63+ """Note that the import of `package` has finished
64+
65+ :param package: the package name that was imported
66+ :type package: unicode
67+ :param job_id: the id of the job
68+ :type job_id: int
69+ :param success: whether the job was successful
70+ :type success: boolean
71+ :param output: the output from the job
72+ :type output: unicode
73+ :param when: the datetime at which the job failed. The default
74+ is None which means that the current time should be used.
75+ :type when: datetime
76+ """
77 if when is None:
78 when = datetime.utcnow()
79 with Cursor(self.conn) as c:
80@@ -606,11 +628,25 @@
81 datetime.utcnow(), None, None))
82
83 def add_jobs(self, packages, job_type):
84+ """Add a set of packages to the queue.
85+
86+ :param packages: the package names to be added
87+ :type package: list(unicode)
88+ :param job_type: the type of the job, one of JOB_TYPE_NEW,
89+ JOB_TYPE_RETRY, JOB_TYPE_PRIORITY.
90+ :type job_type: int
91+ """
92 with Cursor(self.conn) as c:
93 for package in packages:
94 self._add_job(c, package, job_type)
95
96 def last_import_time(self):
97+ """Get the time that the last Launchpad import was done.
98+
99+ :return: the datetime at which the Launchpad import last
100+ ran successfully.
101+ :rtype: datetime
102+ """
103 with Cursor(self.conn) as c:
104 row = c.execute('select * from %s order by import desc'
105 % self.IMPORT_TABLE).get_one()
106@@ -619,6 +655,17 @@
107 return row
108
109 def add_import_jobs(self, packages, newest_published):
110+ """Add a set of jobs from the Launchpad import.
111+
112+ The time reported as `newest_published` will also be stored
113+ as the last time the import successfully ran.
114+
115+ :param packages: the list of packages to import
116+ :type packages: list(unicode)
117+ :param newest_published: the last publishing time seen for
118+ any of those packages.
119+ :type packages: datetime
120+ """
121 with Cursor(self.conn) as c:
122 for package in packages:
123 self._add_job(c, package, self.JOB_TYPE_NEW)
124@@ -626,6 +673,12 @@
125 (newest_published,))
126
127 def next_job(self):
128+ """Get the next job to run.
129+
130+ :return: the next job to run, as a tuple of (package_name, job_id).
131+ If either is None then there is no job to run currently.
132+ :rtype: (Maybe unicode, Maybe int)
133+ """
134 with Cursor(self.conn) as c:
135 job_id = 0
136 package = None
137@@ -648,6 +701,13 @@
138 return (job_id, package)
139
140 def failure_reason(self, package):
141+ """Get the reason (signature) why a package failed.
142+
143+ :param package: the package to get the reason for
144+ :type package: unicode
145+ :return: the failure reason, or None if the package hasn't failed.
146+ :rtype: unicode
147+ """
148 with Cursor(self.conn) as c:
149 row = c.execute(self.FAILURES_TABLE_FIND, (package,)).get_one()
150 if row is None:
151@@ -655,6 +715,13 @@
152 return row[1]
153
154 def failure_signature(self, raw_reason):
155+ """Construct a failure signature from the output of a run.
156+
157+ :param raw_reason: the output of the job that failed
158+ :type raw_reason: str
159+ :return: the failure signature
160+ :rtype: unicode
161+ """
162 trace = raw_reason.splitlines()
163 if len(trace) == 1:
164 if trace[0] == running_sentinel[:-1]: # Get rid of the final '\n'
165@@ -662,24 +729,24 @@
166 # sometimes, Python exceptions do not have file references
167 m = re.match('(\w+): ', trace[0])
168 if m:
169- return m.group(1)
170+ return unicode(m.group(1))
171 else:
172- return trace[0].strip()
173+ return unicode(trace[0].strip())
174 elif len(trace) < 3:
175- return " ".join(trace).strip()
176+ return u" ".join(trace).strip()
177
178 # If the failure reason is a traceback (which should always be the
179 # case, the running_sentinel check above taking care of the still
180 # running imports), we build the traceback signature and capture the
181 # exception type
182- sig = ''
183- exc_type = ''
184+ sig = u''
185+ exc_type = u''
186 exc_type_coming = False
187 file_line_seen = False
188 for l in trace:
189 if l.startswith(' File'):
190 # Keep the method/function name
191- sig += ':' + l.split()[-1]
192+ sig += u':' + unicode(l.split()[-1])
193 file_line_seen = True
194 elif file_line_seen:
195 # We've seen the 'File...' line, so we are now seeing the code
196@@ -704,11 +771,52 @@
197 return c.execute(self.RETRY_TABLE_SELECT, (sig,)).get_one()
198
199 def known_auto_retry(self, sig):
200- with Cursor(self.conn) as c:
201- return self._known_auto_retry(c, sig)
202+ """Is the signature marked for auto-retry?
203+
204+ :param sig: the signature to check
205+ :type sig: unicode
206+ :return: whether the failure should be auto-retried.
207+ :rtype: boolean
208+ """
209+ with Cursor(self.conn) as c:
210+ return self._known_auto_retry(c, sig) is not None
211+
212+ def _add_known_auto_retry(self, c, sig):
213+ row = self._known_auto_retry(c, sig)
214+ if not row:
215+ c.execute(self.RETRY_TABLE_INSERT, (sig,))
216+
217+ def add_known_auto_retry(self, sig):
218+ """Mark a signature as being one that should be automatically retried.
219+
220+ :param sig: the signature to check
221+ :type sig: unicode
222+ """
223+ with Cursor(self.conn) as c:
224+ return self._add_known_auto_retry(c, sig)
225
226 def retry(self, package, force=False, priority=False, auto=False,
227 all=False):
228+ """Retry a package.
229+
230+ :param package: the package to retry
231+ :type package: unicode
232+ :param force: whether to retry even if the package isn't marked as
233+ failed (default is False).
234+ :type force: boolean
235+ :param priority: whether the job should be retried with high
236+ priority (default is False).
237+ :type priority: boolean
238+ :param auto: whether to failures with that signature should
239+ be retried automatically in future (default is False).
240+ :type auto: boolean
241+ :param all: whether to retry all current failures with that
242+ signature (default is False).
243+ :type all: boolean
244+ :return: whether the job was actually retried (see force for
245+ why it might not be)
246+ :rtype: boolean
247+ """
248 with Cursor(self.conn) as c:
249 row = c.execute(self.FAILURES_TABLE_FIND, (package,)).get_one()
250 if row is None:
251@@ -724,9 +832,7 @@
252 sig = self.failure_signature(raw_reason)
253 self._retry(c, package, sig, row[2], priority=priority)
254 if auto and sig != None:
255- row = self._known_auto_retry(c, sig)
256- if row is None:
257- c.execute(self.RETRY_TABLE_INSERT, (sig,))
258+ self._add_known_auto_retry(c, sig)
259 if all and sig != None:
260 rows = c.execute('select * from %s'
261 % self.FAILURES_TABLE)
262@@ -765,7 +871,7 @@
263
264 def _attempt_retry(self, c, info):
265 row = self._known_auto_retry(c, info.signature)
266- if row is None:
267+ if row:
268 # A failure that is not auto-retried
269 return False
270 info.auto_retry = True
271@@ -954,6 +1060,9 @@
272
273 class RevidDatabase(object):
274
275+ # revid and testament are stored as TEXT when BLOB might more sense
276+ # for these bytestrings, because that's what the original code
277+ # stored them as, and keeping that avoids a data migration.
278 REVID_TABLE = "revids"
279 REVID_TABLE_CREATE = '''create table if not exists %s
280 (package text constraint nonull NOT NULL,
281@@ -1005,6 +1114,15 @@
282 % self.REVID_TABLE, (self.package,)))
283
284 def is_marked(self, version, suite):
285+ """Whether that version is marked in the suite.
286+
287+ :param version: the version to check
288+ :type version: changelog.Version
289+ :param suite: suite to check
290+ :type suite: unicode
291+ :return: Whether a mark is recorded for that pair.
292+ :rtype: boolean
293+ """
294 with Cursor(self.conn) as c:
295 rows = list(c.execute(self.REVID_TABLE_FIND % self.REVID_TABLE,
296 (unicode(version), self.package, suite)))
297@@ -1018,6 +1136,14 @@
298 return False
299
300 def last_marked_version(self, suite):
301+ """Get the last version to be marked.
302+
303+ :param suite: suite to check
304+ :type suite: unicode
305+ :return: the versionto be marked, or None if there are no marked
306+ versions in the suite.
307+ :rtype: Maybe str
308+ """
309 with Cursor(self.conn) as c:
310 versions = [a[0] for a in c.execute(self.REVID_TABLE_FIND_SUITE
311 % self.REVID_WORKING_TABLE,
312@@ -1033,6 +1159,19 @@
313 return None
314
315 def check(self, version, revid, suite, branch):
316+ """Check whether the (version, revid, suite) for a branch matches the db.
317+
318+ :param version: the version to check
319+ :type version: changelog.Version
320+ :param revid: the revid to check
321+ :type revid: str
322+ :param suite: suite to check
323+ :type suite: unicode
324+ :param branch: the branch to check
325+ :type branch: bzrlib.branch.Branch
326+ :return: whether the info matches the bd
327+ :rtype: boolean
328+ """
329 sha = self.get_testament_sha1(branch.repository, revid)
330 with Cursor(self.conn) as c:
331 rows = list(c.execute(self.REVID_TABLE_FIND % self.REVID_TABLE,
332@@ -1040,19 +1179,28 @@
333 rows += list(c.execute(self.REVID_TABLE_FIND % self.REVID_WORKING_TABLE,
334 (unicode(version), self.package, suite)))
335 if (version, suite) in self.outstanding_marks:
336- revid, tment = self.outstanding_marks[(unicode(version), suite)]
337- rows += (None, None, None, revid, tment)
338+ rev, tment = self.outstanding_marks[(unicode(version), suite)]
339+ rows += (None, None, None, rev, tment)
340 if len(rows) < 1:
341 return False
342 assert len(rows) < 2, "Multiple versions for a package/suite?"
343 row = rows[0]
344- if (revid, sha) != (row[3], row[4]):
345+ if (unicode(revid), unicode(sha)) != (row[3], row[4]):
346 assert False, ("%s != %s for %s %s in %s, something has changed"
347 % (unicode((revid, sha)), unicode((row[3], row[4])),
348 self.package, unicode(version), suite))
349 return True
350
351 def get_testament_sha1(self, repo, revid):
352+ """Get the sha1 of the testament for revid in repo.
353+
354+ :param repo: the repository to consult
355+ :type repo: bzrlib.repository.Repository
356+ :param revid: the revid to get the testament for
357+ :type revid: str
358+ :return: the sha1 of the testament
359+ :rtype: unicode
360+ """
361 op = cleanup.OperationWithCleanups(self._get_testament_sha1)
362 return op.run(repo, revid)
363
364@@ -1078,6 +1226,12 @@
365 self._commit(c)
366
367 def cleanup_last_run(self, cleanup_cb, push_cb):
368+ """Cleanup any leftovers from the last run.
369+
370+ :param cleanup_cb: a callable to call when the cleanup is done.
371+ :param push_cb: a callable to call if the db indicates that there
372+ was work-in-progress when the last run terminated.
373+ """
374 with Cursor(self.conn) as c:
375 rows = list(c.execute(self.REVID_TABLE_FIND_PACKAGE
376 % self.REVID_WORKING_TABLE, (self.package,)))
377@@ -1094,8 +1248,19 @@
378 c.execute(self.DELETE_WORKING, (self.package,))
379
380 def mark(self, version, revid, suite, branch):
381+ """Mark a (version, revision, suite) for a branch.
382+
383+ :param version: the version to mark.
384+ :type version: changelog.Version
385+ :param revid: the revision id
386+ :type revid: str
387+ :param suite: the suite to mark
388+ :type suite: unicode
389+ :param branch: the branh to mark
390+ :type branch: bzrlib.branch.Branch
391+ """
392 sha = self.get_testament_sha1(branch.repository, revid)
393- self.outstanding_marks[(unicode(version), suite)] = (revid, sha)
394+ self.outstanding_marks[(unicode(version), suite)] = (unicode(revid), unicode(sha))
395
396 def commit_outstanding(self):
397 with Cursor(self.conn) as c:
398@@ -1116,7 +1281,7 @@
399 rows = list(c.execute("select * from %s where package=?"
400 % self.SUFFIX_TABLE, (self.package,)))
401 if len(rows) < 1:
402- return ""
403+ return u""
404 return rows[0][1]
405
406
407
408=== modified file 'udd/scripts/mass_import.py'
409--- udd/scripts/mass_import.py 2012-07-03 17:10:24 +0000
410+++ udd/scripts/mass_import.py 2012-07-03 17:10:24 +0000
411@@ -161,6 +161,9 @@
412 # We mostly care about self.err which contains the traceback here
413 output = self.out + self.err
414 unicode_output = output.decode("utf-8", "replace")
415+ # Ecode to ascii with 'replace' as that's what the failure
416+ # signature code expects to get, even though we now deal
417+ # with the value as a unicode string throughout.
418 ascii_output = unicode_output.encode("ascii", "replace")
419 self.success = self.retcode == 0
420 if self.success:
421@@ -172,7 +175,8 @@
422 "Importing %s failed:\n%s" % (
423 self.package_name, ascii_output))
424 self.status_db.finish_job(
425- self.package_name, self.job_id, self.success, ascii_output)
426+ self.package_name, self.job_id, self.success,
427+ unicode(ascii_output))
428 if not self.success:
429 reason = self.status_db.failure_reason(self.package_name)
430 self.failure_sig = self.status_db.failure_signature(reason)
431@@ -334,7 +338,7 @@
432 # We can't blame launchpad downtimes for all failures, we rely on
433 # the ones declared in RETRY_TABLE (created when
434 # 'requeue_package.py --auto' is used)
435- if self.status_db.known_auto_retry(imp.failure_sig) is not None:
436+ if self.status_db.known_auto_retry(imp.failure_sig):
437 self.see_failure()
438 # We want to retry asap ('priority')
439 self.status_db.retry(package_name, priority=True)
440
441=== modified file 'udd/tests/test_commit_database.py'
442--- udd/tests/test_commit_database.py 2012-07-03 17:10:24 +0000
443+++ udd/tests/test_commit_database.py 2012-07-03 17:10:24 +0000
444@@ -8,7 +8,7 @@
445 def setUp(self):
446 super(TestCommitDb, self).setUp()
447 db_conn, db_type = idb.get_memory_db_connection()
448- self.db = icommon.CommitDatabase(db_conn, db_type, 'foo')
449+ self.db = icommon.CommitDatabase(db_conn, db_type, u'foo')
450
451 def test_has_commit(self):
452 self.assertEquals(False, self.db.has_commit_started())
453
454=== modified file 'udd/tests/test_revid_database.py'
455--- udd/tests/test_revid_database.py 2012-07-03 17:10:24 +0000
456+++ udd/tests/test_revid_database.py 2012-07-03 17:10:24 +0000
457@@ -28,7 +28,7 @@
458
459 def get_db(self):
460 db_conn, db_type = idb.get_memory_db_connection()
461- return icommon.RevidDatabase(db_conn, db_type, "pkg")
462+ return icommon.RevidDatabase(db_conn, db_type, u"pkg")
463
464 def check_rows(self, memory, working, saved):
465 self.assertEqual(memory, len(self.db._memory_rows()))
466
467=== modified file 'udd/tests/test_status_database.py'
468--- udd/tests/test_status_database.py 2012-07-03 17:10:24 +0000
469+++ udd/tests/test_status_database.py 2012-07-03 17:10:24 +0000
470@@ -112,13 +112,20 @@
471 class TestRetry(TestStatusDb):
472
473 def test_known_auto_retry_empty(self):
474- self.assertEquals(None, self.db.known_auto_retry('whatever'))
475+ self.assertEquals(False, self.db.known_auto_retry('whatever'))
476+
477+ def test_known_auto_retry_known(self):
478+ sig = u'whatever'
479+ self.db.add_known_auto_retry(sig)
480+ self.assertEquals(True, self.db.known_auto_retry(sig))
481+
482+ def test_known_auto_retry_unknown(self):
483+ self.db.add_known_auto_retry(u'something')
484+ self.assertEquals(False, self.db.known_auto_retry(u'something else'))
485
486 # FIXME: Need more tests for the following but they are too hard to test for
487 # now -- vila 20111020
488
489-# _known_auto_retry(self, c, sig):
490-# known_auto_retry(self, sig):
491 # retry(self, package, force=False, priority=False, auto=False,
492 # _retry(self, c, package, signature, timestamp, priority=False):
493 # _attempt_retry(self, c, info):
494@@ -127,7 +134,10 @@
495 class TestSignatures(TestStatusDb):
496
497 def assertSignature(self, expected, raw):
498- self.assertEquals(expected, self.db.failure_signature(raw))
499+ failure_signature = self.db.failure_signature(raw)
500+ self.assertEquals(expected, failure_signature)
501+ if failure_signature is not None:
502+ self.assertIsInstance(failure_signature, unicode)
503
504 def test_running_signature(self):
505 # Running imports use a special failure signature

Subscribers

People subscribed via source and target branches