Merge lp:~abentley/launchpad/no-review-diff into lp:launchpad

Proposed by Aaron Bentley
Status: Merged
Approved by: Edwin Grubbs
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~abentley/launchpad/no-review-diff
Merge into: lp:launchpad
Diff against target: 302 lines (+35/-84)
6 files modified
lib/lp/code/browser/tests/test_branchmergeproposal.py (+10/-9)
lib/lp/code/doc/branch-merge-proposal-notifications.txt (+4/-8)
lib/lp/code/model/branchmergeproposaljob.py (+2/-29)
lib/lp/code/model/tests/test_branchmergeproposals.py (+5/-27)
lib/lp/code/scripts/tests/test_mp_creationjob.py (+3/-2)
lib/lp/code/stories/branches/xx-branch-merge-proposals.txt (+11/-9)
To merge this branch: bzr merge lp:~abentley/launchpad/no-review-diff
Reviewer Review Type Date Requested Status
Edwin Grubbs (community) code Approve
Review via email: mp+16900@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

= Summary =
Review diffs are supplanted by preview diffs, so stop generating them.

== Proposed fix ==
This patch changes MergeProposalCreatedJob to stop generating review diffs, while still generating preview diffs.

== Pre-implementation notes ==
Pre-implementation was with thumper.

== Implementation details ==
The APIs related to review and preview diffs are somewhat different, so
some changes were necessary, such as using unicode rather than string revision ids. Also, BranchMergeProposal.preview_diff is not normally writable, so the security proxy must be removed for some tests.

== Tests ==
bin/test -vt branch-merge -t branchmerge -t test_mpcreationjobs

== Demo and Q/A ==
Not applicable; no user-visible changes.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/code/model/tests/test_branchmergeproposals.py
  lib/lp/code/browser/tests/test_branchmergeproposal.py
  lib/lp/code/scripts/tests/test_mp_creationjob.py
  lib/lp/code/stories/branches/xx-branch-merge-proposals.txt
  lib/lp/code/model/branchmergeproposaljob.py
  lib/lp/code/doc/branch-merge-proposal-notifications.txt

== Pylint notices ==

lib/lp/code/model/branchmergeproposaljob.py
    21: [F0401] Unable to import 'lazr.delegates' (No module named delegates)
    22: [F0401] Unable to import 'lazr.enum' (No module named enum)

Revision history for this message
Edwin Grubbs (edwin-grubbs) wrote :

Hi Aaron,

This branch looks good. I would just like the two docstrings changed as discussed on IRC.

merge-conditional

-Edwin

IRC Log:

[11:02 AM] <EdwinGrubbs> abentley the docstring for test_preview_diff_text_with_no_diff() says that the review_diff should be None when there is no context.preview_diff. Is that right? I don't really understand the difference between a review diff and a preview diff or whether all the objects treat them as separate.
[11:03 AM] <abentley> EdwinGrubbs: The confusion between review diffs and preview diffs was one of the reasons we got rid of review diffs. A review diff shows the changes the branch author made. A preview diff shows what would happen if you merged that branch.
[11:04 AM] <abentley> EdwinGrubbs: The review_diff field on the view class now actually refers to the preview diff, so the docstring is accurate.
[11:05 AM] <EdwinGrubbs> abentley: is that first docstring in the diff correct, or should "review_diff" be "preview_diff". In the test you are checking view.preview_diff_text.
[11:06 AM] <abentley> EdwinGrubbs: I think review_diff should be preview_diff_text.
[11:06 AM] <EdwinGrubbs> abentley: The docstring for test_preview_diff_utf8 doesn't make any sense.
[11:07 AM] <abentley> EdwinGrubbs: It means that if the bytes are utf-8-encoded, they should be decoded to unicode as utf-8.
[11:08 AM] <EdwinGrubbs> abentley: can you clarify that in the docstring?
[11:08 AM] Activating Flood Protection
[11:08 AM] Deactivating Flood Protection
[11:08 AM] <abentley> EdwinGrubbs: "A preview_diff in utf-8 should be decoded as utf-8" ?
[11:13 AM] <EdwinGrubbs> abentley: yes, but there is no reason to say utf-8 twice, can you say "decoded into a unicode object"?
[11:14 AM] <abentley> EdwinGrubbs: The reason to say it twice is because it should not be decoded using a different encoding.
[11:14 AM] <abentley> e.g. "A preview_diff in utf-8 should be decoded as utf-8, not utf-16"
[11:15 AM] <EdwinGrubbs> abentley: ok, that makes sense, since that's what you are really trying to test.
[11:18 AM] <EdwinGrubbs> abentley: in xx-branch-merge-proposals.txt, a tag with id='review-diff' is retrieved. Is that just a case where the UI hasn't yet been updated to match the name of the attribute that is now used?
[11:19 AM] <abentley> EdwinGrubbs: Yes.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2009-12-10 20:04:49 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-01-07 13:40:34 +0000
@@ -488,28 +488,26 @@
488 {'review_id': review.id})488 {'review_id': review.id})
489489
490 def test_preview_diff_text_with_no_diff(self):490 def test_preview_diff_text_with_no_diff(self):
491 """review_diff should be None when there is no context.review_diff."""491 """preview_diff_text should be None if context has no preview_diff."""
492 view = create_initialized_view(self.bmp, '+index')492 view = create_initialized_view(self.bmp, '+index')
493 self.assertIs(None, view.preview_diff_text)493 self.assertIs(None, view.preview_diff_text)
494494
495 def test_review_diff_utf8(self):495 def test_preview_diff_utf8(self):
496 """A review_diff in utf-8 should be converted to utf-8."""496 """A preview_diff in utf-8 should decoded as utf-8."""
497 text = ''.join(unichr(x) for x in range(255))497 text = ''.join(unichr(x) for x in range(255))
498 diff_bytes = ''.join(unified_diff('', text)).encode('utf-8')498 diff_bytes = ''.join(unified_diff('', text)).encode('utf-8')
499 diff = StaticDiff.acquireFromText('x', 'y', diff_bytes)499 self.setPreviewDiff(diff_bytes)
500 transaction.commit()500 transaction.commit()
501 self.bmp.review_diff = diff
502 view = create_initialized_view(self.bmp, '+index')501 view = create_initialized_view(self.bmp, '+index')
503 self.assertEqual(diff_bytes.decode('utf-8'),502 self.assertEqual(diff_bytes.decode('utf-8'),
504 view.preview_diff_text)503 view.preview_diff_text)
505504
506 def test_review_diff_all_chars(self):505 def test_preview_diff_all_chars(self):
507 """review_diff should work on diffs containing all possible bytes."""506 """preview_diff should work on diffs containing all possible bytes."""
508 text = ''.join(chr(x) for x in range(255))507 text = ''.join(chr(x) for x in range(255))
509 diff_bytes = ''.join(unified_diff('', text))508 diff_bytes = ''.join(unified_diff('', text))
510 diff = StaticDiff.acquireFromText('x', 'y', diff_bytes)509 self.setPreviewDiff(diff_bytes)
511 transaction.commit()510 transaction.commit()
512 self.bmp.review_diff = diff
513 view = create_initialized_view(self.bmp, '+index')511 view = create_initialized_view(self.bmp, '+index')
514 self.assertEqual(diff_bytes.decode('windows-1252', 'replace'),512 self.assertEqual(diff_bytes.decode('windows-1252', 'replace'),
515 view.preview_diff_text)513 view.preview_diff_text)
@@ -523,6 +521,9 @@
523 def addBothDiffs(self):521 def addBothDiffs(self):
524 self.addReviewDiff()522 self.addReviewDiff()
525 preview_diff_bytes = ''.join(unified_diff('', 'preview'))523 preview_diff_bytes = ''.join(unified_diff('', 'preview'))
524 return self.setPreviewDiff(preview_diff_bytes)
525
526 def setPreviewDiff(self, preview_diff_bytes):
526 preview_diff = PreviewDiff.create(527 preview_diff = PreviewDiff.create(
527 preview_diff_bytes, u'a', u'b', None, u'')528 preview_diff_bytes, u'a', u'b', None, u'')
528 removeSecurityProxy(self.bmp).preview_diff = preview_diff529 removeSecurityProxy(self.bmp).preview_diff = preview_diff
529530
=== modified file 'lib/lp/code/doc/branch-merge-proposal-notifications.txt'
--- lib/lp/code/doc/branch-merge-proposal-notifications.txt 2009-09-16 13:47:41 +0000
+++ lib/lp/code/doc/branch-merge-proposal-notifications.txt 2010-01-07 13:40:34 +0000
@@ -16,14 +16,11 @@
16 ... CodeReviewNotificationLevel)16 ... CodeReviewNotificationLevel)
17 >>> from lp.code.interfaces.branchmergeproposal import (17 >>> from lp.code.interfaces.branchmergeproposal import (
18 ... IMergeProposalCreatedJobSource)18 ... IMergeProposalCreatedJobSource)
19 >>> from lp.code.interfaces.diff import IStaticDiffSource
20 >>> from lp.code.model.diff import PreviewDiff19 >>> from lp.code.model.diff import PreviewDiff
21 >>> from lp.testing.mail_helpers import pop_notifications20 >>> from lp.testing.mail_helpers import pop_notifications
22 >>> import transaction21 >>> import transaction
23 >>> login('test@canonical.com')22 >>> login('test@canonical.com')
24 >>> diff_bytes = ''.join(unified_diff('', 'c'))23 >>> diff_bytes = ''.join(unified_diff('', 'c'))
25 >>> review_diff = getUtility(IStaticDiffSource).acquireFromText(
26 ... 'a', 'b', diff_bytes)
27 >>> preview_diff = PreviewDiff.create(diff_bytes, u'a', u'b', None, None)24 >>> preview_diff = PreviewDiff.create(diff_bytes, u'a', u'b', None, None)
28 >>> # Make Librarian happy.25 >>> # Make Librarian happy.
29 >>> transaction.commit()26 >>> transaction.commit()
@@ -104,10 +101,10 @@
104 ... displayname="Eric", email="eric@example.com")101 ... displayname="Eric", email="eric@example.com")
105 >>> # To avoid needing to access branches, pre-populate diffs.102 >>> # To avoid needing to access branches, pre-populate diffs.
106 >>> bmp = source_branch.addLandingTarget(103 >>> bmp = source_branch.addLandingTarget(
107 ... registrant, target_branch, review_diff=review_diff)104 ... registrant, target_branch)
108 >>> removeSecurityProxy(bmp).preview_diff = preview_diff105 >>> removeSecurityProxy(bmp).preview_diff = preview_diff
109 >>> [job,] = list(getUtility(IMergeProposalCreatedJobSource).iterReady())106 >>> [job,] = list(getUtility(IMergeProposalCreatedJobSource).iterReady())
110 >>> _unused_diff = job.run(_create_preview=False)107 >>> job.run(_create_preview=False)
111 >>> notifications = pop_notifications(108 >>> notifications = pop_notifications(
112 ... sort_key=lambda n: n.get('X-Envelope-To'))109 ... sort_key=lambda n: n.get('X-Envelope-To'))
113110
@@ -156,11 +153,10 @@
156 >>> bmp.deleteProposal()153 >>> bmp.deleteProposal()
157 >>> bmp = source_branch.addLandingTarget(154 >>> bmp = source_branch.addLandingTarget(
158 ... registrant, target_branch,155 ... registrant, target_branch,
159 ... initial_comment=initial_comment, review_requests=reviewers,156 ... initial_comment=initial_comment, review_requests=reviewers)
160 ... review_diff=review_diff)
161 >>> removeSecurityProxy(bmp).preview_diff = preview_diff157 >>> removeSecurityProxy(bmp).preview_diff = preview_diff
162 >>> [job,] = list(getUtility(IMergeProposalCreatedJobSource).iterReady())158 >>> [job,] = list(getUtility(IMergeProposalCreatedJobSource).iterReady())
163 >>> _unused_diff = job.run(_create_preview=False)159 >>> job.run(_create_preview=False)
164 >>> notifications = pop_notifications(160 >>> notifications = pop_notifications(
165 ... sort_key=lambda n: n.get('X-Envelope-To'))161 ... sort_key=lambda n: n.get('X-Envelope-To'))
166 >>> for notification in notifications:162 >>> for notification in notifications:
167163
=== modified file 'lib/lp/code/model/branchmergeproposaljob.py'
--- lib/lp/code/model/branchmergeproposaljob.py 2009-12-10 18:20:09 +0000
+++ lib/lp/code/model/branchmergeproposaljob.py 2010-01-07 13:40:34 +0000
@@ -15,7 +15,7 @@
15 ]15 ]
1616
17import contextlib17import contextlib
18from email.Utils import parseaddr18from email.utils import parseaddr
19import transaction19import transaction
2020
21from lazr.delegates import delegates21from lazr.delegates import delegates
@@ -45,7 +45,7 @@
45 )45 )
46from lp.code.mail.branchmergeproposal import BMPMailer46from lp.code.mail.branchmergeproposal import BMPMailer
47from lp.code.model.branchmergeproposal import BranchMergeProposal47from lp.code.model.branchmergeproposal import BranchMergeProposal
48from lp.code.model.diff import PreviewDiff, StaticDiff48from lp.code.model.diff import PreviewDiff
49from lp.codehosting.vfs import get_multi_server, get_scanner_server49from lp.codehosting.vfs import get_multi_server, get_scanner_server
50from lp.services.job.model.job import Job50from lp.services.job.model.job import Job
51from lp.services.job.interfaces.job import IRunnableJob51from lp.services.job.interfaces.job import IRunnableJob
@@ -223,41 +223,14 @@
223 def run(self, _create_preview=True):223 def run(self, _create_preview=True):
224 """See `IMergeProposalCreatedJob`."""224 """See `IMergeProposalCreatedJob`."""
225 # _create_preview can be set False for testing purposes.225 # _create_preview can be set False for testing purposes.
226 diff_created = False
227 if self.branch_merge_proposal.review_diff is None:
228 self.branch_merge_proposal.review_diff = self._makeReviewDiff()
229 diff_created = True
230 if _create_preview:226 if _create_preview:
231 preview_diff = PreviewDiff.fromBranchMergeProposal(227 preview_diff = PreviewDiff.fromBranchMergeProposal(
232 self.branch_merge_proposal)228 self.branch_merge_proposal)
233 self.branch_merge_proposal.preview_diff = preview_diff229 self.branch_merge_proposal.preview_diff = preview_diff
234 diff_created = True
235 if diff_created:
236 transaction.commit()230 transaction.commit()
237 mailer = BMPMailer.forCreation(231 mailer = BMPMailer.forCreation(
238 self.branch_merge_proposal, self.branch_merge_proposal.registrant)232 self.branch_merge_proposal, self.branch_merge_proposal.registrant)
239 mailer.sendAll()233 mailer.sendAll()
240 return self.branch_merge_proposal.review_diff
241
242 def _makeReviewDiff(self):
243 """Return a StaticDiff to be used as a review diff."""
244 cleanups = []
245 def get_branch(branch):
246 bzr_branch = branch.getBzrBranch()
247 bzr_branch.lock_read()
248 cleanups.append(bzr_branch.unlock)
249 return bzr_branch
250 try:
251 bzr_source = get_branch(self.branch_merge_proposal.source_branch)
252 bzr_target = get_branch(self.branch_merge_proposal.target_branch)
253 lca, source_revision = self._findRevisions(
254 bzr_source, bzr_target)
255 diff = StaticDiff.acquire(
256 lca, source_revision, bzr_source.repository)
257 finally:
258 for cleanup in reversed(cleanups):
259 cleanup()
260 return diff
261234
262 @staticmethod235 @staticmethod
263 def _findRevisions(bzr_source, bzr_target):236 def _findRevisions(bzr_source, bzr_target):
264237
=== modified file 'lib/lp/code/model/tests/test_branchmergeproposals.py'
--- lib/lp/code/model/tests/test_branchmergeproposals.py 2009-12-18 15:02:34 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposals.py 2010-01-07 13:40:34 +0000
@@ -48,7 +48,6 @@
48 MergeProposalCreatedJob, UpdatePreviewDiffJob)48 MergeProposalCreatedJob, UpdatePreviewDiffJob)
49from lp.code.model.branchmergeproposal import (49from lp.code.model.branchmergeproposal import (
50 BranchMergeProposal, BranchMergeProposalGetter, is_valid_transition)50 BranchMergeProposal, BranchMergeProposalGetter, is_valid_transition)
51from lp.code.model.diff import StaticDiff
52from lp.code.model.tests.test_diff import DiffTestCase51from lp.code.model.tests.test_diff import DiffTestCase
53from lp.registry.interfaces.person import IPersonSet52from lp.registry.interfaces.person import IPersonSet
54from lp.registry.interfaces.product import IProductSet53from lp.registry.interfaces.product import IProductSet
@@ -1292,50 +1291,29 @@
1292 job = MergeProposalCreatedJob.create(bmp)1291 job = MergeProposalCreatedJob.create(bmp)
1293 transaction.commit()1292 transaction.commit()
1294 self.layer.switchDbUser(config.mpcreationjobs.dbuser)1293 self.layer.switchDbUser(config.mpcreationjobs.dbuser)
1295 diff = job.run()1294 job.run()
1296 self.assertIsNot(None, diff)1295 self.assertIs(None, bmp.review_diff)
1297 self.assertEqual(diff, bmp.review_diff)
1298 self.assertIsNot(None, bmp.preview_diff)1296 self.assertIsNot(None, bmp.preview_diff)
1299 transaction.commit()1297 transaction.commit()
1300 self.checkDiff(diff)
1301 self.checkDiff(bmp.preview_diff)1298 self.checkDiff(bmp.preview_diff)
13021299
1303 def checkDiff(self, diff):1300 def checkDiff(self, diff):
1304 self.assertNotIn('+bar', diff.diff.text)1301 self.assertNotIn('+bar', diff.diff.text)
1305 self.assertIn('+qux', diff.diff.text)1302 self.assertIn('+qux', diff.diff.text)
13061303
1307 def createProposalWithEmptyBranches(self, review_diff=None):1304 def createProposalWithEmptyBranches(self):
1308 target_branch, tree = self.create_branch_and_tree()1305 target_branch, tree = self.create_branch_and_tree()
1309 tree.commit('test')1306 tree.commit('test')
1310 source_branch = self.factory.makeProductBranch(1307 source_branch = self.factory.makeProductBranch(
1311 product=target_branch.product)1308 product=target_branch.product)
1312 self.createBzrBranch(source_branch, tree.branch)1309 self.createBzrBranch(source_branch, tree.branch)
1313 return self.factory.makeBranchMergeProposal(1310 return self.factory.makeBranchMergeProposal(
1314 source_branch=source_branch, target_branch=target_branch,1311 source_branch=source_branch, target_branch=target_branch)
1315 review_diff=review_diff)
1316
1317 def test_run_skips_diff_if_present(self):
1318 """The review diff is only generated if not already assigned."""
1319 # We want to make sure that we don't try to do anything with the
1320 # bzr branch if there's already a diff. So here, we create a
1321 # database branch that has no bzr branch.
1322 self.useBzrBranches()
1323 bmp = self.createProposalWithEmptyBranches()
1324 job = MergeProposalCreatedJob.create(bmp)
1325 diff_bytes = ''.join(unified_diff('', 'foo'))
1326 review_diff = StaticDiff.acquireFromText('rev1', 'rev2', diff_bytes)
1327 transaction.commit()
1328 removeSecurityProxy(bmp).review_diff = review_diff
1329 job.run()
1330 self.assertEqual(review_diff, bmp.review_diff)
13311312
1332 def test_run_sends_email(self):1313 def test_run_sends_email(self):
1333 """MergeProposalCreationJob.run sends an email."""1314 """MergeProposalCreationJob.run sends an email."""
1334 self.useBzrBranches()1315 self.useBzrBranches()
1335 diff_bytes = ''.join(unified_diff('', 'foo'))1316 bmp = self.createProposalWithEmptyBranches()
1336 review_diff = StaticDiff.acquireFromText('rev1', 'rev2', diff_bytes)
1337 transaction.commit()
1338 bmp = self.createProposalWithEmptyBranches(review_diff)
1339 job = MergeProposalCreatedJob.create(bmp)1317 job = MergeProposalCreatedJob.create(bmp)
1340 self.assertEqual([], pop_notifications())1318 self.assertEqual([], pop_notifications())
1341 job.run()1319 job.run()
13421320
=== modified file 'lib/lp/code/scripts/tests/test_mp_creationjob.py'
--- lib/lp/code/scripts/tests/test_mp_creationjob.py 2009-10-17 14:06:03 +0000
+++ lib/lp/code/scripts/tests/test_mp_creationjob.py 2010-01-07 13:40:34 +0000
@@ -38,7 +38,7 @@
38 source_branch=source, target_branch=target,38 source_branch=source, target_branch=target,
39 registrant=source.owner)39 registrant=source.owner)
40 job = MergeProposalCreatedJob.create(bmp)40 job = MergeProposalCreatedJob.create(bmp)
41 self.assertIs(None, bmp.review_diff)41 self.assertIs(None, bmp.preview_diff)
42 transaction.commit()42 transaction.commit()
43 retcode, stdout, stderr = run_script(43 retcode, stdout, stderr = run_script(
44 'cronscripts/mpcreationjobs.py', [])44 'cronscripts/mpcreationjobs.py', [])
@@ -47,7 +47,8 @@
47 self.assertEqual(47 self.assertEqual(
48 'INFO creating lockfile\n'48 'INFO creating lockfile\n'
49 'INFO Ran 1 MergeProposalCreatedJobs.\n', stderr)49 'INFO Ran 1 MergeProposalCreatedJobs.\n', stderr)
50 self.assertIsNot(None, bmp.review_diff)50 self.assertIs(None, bmp.review_diff)
51 self.assertIsNot(None, bmp.preview_diff)
5152
52 def test_mpcreationjobs_records_oops(self):53 def test_mpcreationjobs_records_oops(self):
53 """Ensure mpcreationjobs logs an oops if the job fails."""54 """Ensure mpcreationjobs logs an oops if the job fails."""
5455
=== modified file 'lib/lp/code/stories/branches/xx-branch-merge-proposals.txt'
--- lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-11-27 01:29:10 +0000
+++ lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2010-01-07 13:40:34 +0000
@@ -587,20 +587,21 @@
587 NotFound: ...587 NotFound: ...
588588
589589
590Displaying a review diff590Displaying a preview diff
591------------------------591-------------------------
592592
593Create merge proposal with a review diff, and go to its index page.593Create merge proposal with a preview diff, and go to its index page.
594594
595 >>> login('admin@canonical.com')595 >>> login('admin@canonical.com')
596 >>> from lp.code.model.diff import StaticDiff596 >>> from zope.security.proxy import removeSecurityProxy
597 >>> from lp.code.model.diff import PreviewDiff
597 >>> from difflib import unified_diff598 >>> from difflib import unified_diff
598 >>> diff_text = ''.join(599 >>> diff_text = ''.join(
599 ... unified_diff('', ['Fake Diff' + u'\u1010'.encode('utf-8')]))600 ... unified_diff('', ['Fake Diff' + u'\u1010'.encode('utf-8')]))
600 >>> review_diff = StaticDiff.acquireFromText(601 >>> preview_diff = PreviewDiff.create(diff_text, u'a', u'b', None, u'')
601 ... 'a', 'b', diff_text)
602 >>> transaction.commit()602 >>> transaction.commit()
603 >>> bmp = factory.makeBranchMergeProposal(review_diff=review_diff)603 >>> bmp = factory.makeBranchMergeProposal()
604 >>> removeSecurityProxy(bmp).preview_diff = preview_diff
604 >>> url = canonical_url(bmp)605 >>> url = canonical_url(bmp)
605 >>> logout()606 >>> logout()
606 >>> def get_review_diff():607 >>> def get_review_diff():
@@ -613,7 +614,7 @@
613614
614If no diff is present, nothing is shown.615If no diff is present, nothing is shown.
615 >>> login('admin@canonical.com')616 >>> login('admin@canonical.com')
616 >>> bmp.review_diff = None617 >>> removeSecurityProxy(bmp).preview_diff = None
617 >>> logout()618 >>> logout()
618 >>> print get_review_diff()619 >>> print get_review_diff()
619 None620 None
@@ -621,7 +622,8 @@
621If the review diff is empty, then we say it is empty.622If the review diff is empty, then we say it is empty.
622623
623 >>> login('admin@canonical.com')624 >>> login('admin@canonical.com')
624 >>> bmp.review_diff = StaticDiff.acquireFromText('c', 'd', '')625 >>> removeSecurityProxy(bmp).preview_diff = PreviewDiff.create(
626 ... '', u'c', u'd', None, u'')
625 >>> logout()627 >>> logout()
626 >>> print extract_text(get_review_diff())628 >>> print extract_text(get_review_diff())
627 Preview Diff629 Preview Diff