Merge lp:~jameinel/bzr/2.5-remote-wt-tests-1046697 into lp:bzr/2.5

Proposed by John A Meinel
Status: Merged
Approved by: John A Meinel
Approved revision: no longer in the source branch.
Merged at revision: 6509
Proposed branch: lp:~jameinel/bzr/2.5-remote-wt-tests-1046697
Merge into: lp:bzr/2.5
Diff against target: 596 lines (+189/-76)
14 files modified
bzrlib/remote.py (+15/-6)
bzrlib/smart/repository.py (+12/-9)
bzrlib/tests/per_tree/__init__.py (+18/-4)
bzrlib/tests/per_workingtree/__init__.py (+39/-6)
bzrlib/tests/per_workingtree/test_commit.py (+3/-2)
bzrlib/tests/per_workingtree/test_executable.py (+1/-2)
bzrlib/tests/per_workingtree/test_parents.py (+5/-3)
bzrlib/tests/per_workingtree/test_remove.py (+1/-1)
bzrlib/tests/per_workingtree/test_smart_add.py (+3/-0)
bzrlib/tests/per_workingtree/test_views.py (+2/-2)
bzrlib/tests/per_workingtree/test_workingtree.py (+24/-29)
bzrlib/tests/test_selftest.py (+39/-9)
bzrlib/workingtree_4.py (+19/-3)
doc/en/release-notes/bzr-2.5.txt (+8/-0)
To merge this branch: bzr merge lp:~jameinel/bzr/2.5-remote-wt-tests-1046697
Reviewer Review Type Date Requested Status
Richard Wilbur Approve
Review via email: mp+123061@code.launchpad.net

Commit message

Add per_workingtree test scenario for a lightweight checkout of a RemoteRepository (bug #1046697) and cleanup all associated fallout.

Description of the change

This branch aggregates most of the branches I proposed today.
It adds a test permutation of a lightweight WT6 checkout of a remote repository.
That resulted in a fair number of tests failing for various reasons.

1) RemoteBranch.initialize not preserving the Repository. bzrdir.sprout() creates the repo, fetches into it, and then passes the locked repo to the branch. The branch then wants to write_lock itself to initialize, but it can't write lock an already locked repository (and we don't want it to). RemoteBranch was using ._vfs_initialize() when the target was local, but wasn't passing down the repository.

2) RemoteBranch.peek_lock_mode() wasn't implemented. This is trivial to implement, so I just did so.

3) Repository.record_stream() was not always finalizing its progress bar. It takes out a progress bar in a generator. However, the generator is often run in sync with some other stepper, which means it isn't always run to completion. I just put it into a try/finally so if the generator gets garbage collected, we pop off the nested progress bar. This only works in python ? (2.5 maybe?) but I've been testing it with python2.6 which I'm pretty sure is our min requirement for newer bzr.

4) Lots of test suite fixups. Quite a few tests
 a) assumed that WT.branch was in the same location as WT
 b) assumed that make_branch().bzrdir.create_workingtree() would work. It doesn't when the Branch created is on a remote location, and you want a local workingtree.
 c) WorkingTreeFormat6._matchingbzrdir did *not* create a WorkingTreeFormat6 tree. It would create a Format4 tree because it just inherited the attribute from there. This adds a _get_matchingbzrdir attribute that returns the right thing. (the symptom here is that stuff like views and filters would check self.workingtree_format.supports_views but then self.bzrdir_format.make_workingtree wouldn't actually create a WT that supported views.)

I only ran the per_workingtree tests, but that should be enough since that is the only new permutations that were added.

To post a comment you must log in.
Revision history for this message
Richard Wilbur (richard-wilbur) wrote :

Lots of good fixes for working trees and tests. This looks like good stuff for the baseline. +1

Interesting behaviour from .iter_files_bytes() in get_file_text(): yielding empty results until the last result which contains the full contents of the file.

Nice cleanup on the progress bars.

review: Approve
Revision history for this message
John A Meinel (jameinel) wrote :

sent to pqm by email

Revision history for this message
John A Meinel (jameinel) wrote :

sent to pqm by email

Revision history for this message
John A Meinel (jameinel) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/remote.py'
2--- bzrlib/remote.py 2012-01-28 00:56:56 +0000
3+++ bzrlib/remote.py 2012-09-07 10:36:18 +0000
4@@ -3129,7 +3129,8 @@
5 return a_bzrdir.open_branch(name=name,
6 ignore_fallbacks=ignore_fallbacks)
7
8- def _vfs_initialize(self, a_bzrdir, name, append_revisions_only):
9+ def _vfs_initialize(self, a_bzrdir, name, append_revisions_only,
10+ repository=None):
11 # Initialisation when using a local bzrdir object, or a non-vfs init
12 # method is not available on the server.
13 # self._custom_format is always set - the start of initialize ensures
14@@ -3137,11 +3138,13 @@
15 if isinstance(a_bzrdir, RemoteBzrDir):
16 a_bzrdir._ensure_real()
17 result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
18- name=name, append_revisions_only=append_revisions_only)
19+ name=name, append_revisions_only=append_revisions_only,
20+ repository=repository)
21 else:
22 # We assume the bzrdir is parameterised; it may not be.
23 result = self._custom_format.initialize(a_bzrdir, name=name,
24- append_revisions_only=append_revisions_only)
25+ append_revisions_only=append_revisions_only,
26+ repository=repository)
27 if (isinstance(a_bzrdir, RemoteBzrDir) and
28 not isinstance(result, RemoteBranch)):
29 result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
30@@ -3164,11 +3167,13 @@
31 # Being asked to create on a non RemoteBzrDir:
32 if not isinstance(a_bzrdir, RemoteBzrDir):
33 return self._vfs_initialize(a_bzrdir, name=name,
34- append_revisions_only=append_revisions_only)
35+ append_revisions_only=append_revisions_only,
36+ repository=repository)
37 medium = a_bzrdir._client._medium
38 if medium._is_remote_before((1, 13)):
39 return self._vfs_initialize(a_bzrdir, name=name,
40- append_revisions_only=append_revisions_only)
41+ append_revisions_only=append_revisions_only,
42+ repository=repository)
43 # Creating on a remote bzr dir.
44 # 2) try direct creation via RPC
45 path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
46@@ -3182,7 +3187,8 @@
47 # Fallback - use vfs methods
48 medium._remember_remote_is_before((1, 13))
49 return self._vfs_initialize(a_bzrdir, name=name,
50- append_revisions_only=append_revisions_only)
51+ append_revisions_only=append_revisions_only,
52+ repository=repository)
53 if response[0] != 'ok':
54 raise errors.UnexpectedSmartServerResponse(response)
55 # Turn the response into a RemoteRepository object.
56@@ -3867,6 +3873,9 @@
57 target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
58 _override_hook_source_branch=self)
59
60+ def peek_lock_mode(self):
61+ return self._lock_mode
62+
63 def is_locked(self):
64 return self._lock_count >= 1
65
66
67=== modified file 'bzrlib/smart/repository.py'
68--- bzrlib/smart/repository.py 2011-12-19 13:23:58 +0000
69+++ bzrlib/smart/repository.py 2012-09-07 10:36:18 +0000
70@@ -736,15 +736,18 @@
71 self.seed_state()
72 pb = ui.ui_factory.nested_progress_bar()
73 rc = self._record_counter
74- # Make and consume sub generators, one per substream type:
75- while self.first_bytes is not None:
76- substream = NetworkRecordStream(self.iter_substream_bytes())
77- # after substream is fully consumed, self.current_type is set to
78- # the next type, and self.first_bytes is set to the matching bytes.
79- yield self.current_type, wrap_and_count(pb, rc, substream)
80- if rc:
81- pb.update('Done', rc.max, rc.max)
82- pb.finished()
83+ try:
84+ # Make and consume sub generators, one per substream type:
85+ while self.first_bytes is not None:
86+ substream = NetworkRecordStream(self.iter_substream_bytes())
87+ # after substream is fully consumed, self.current_type is set
88+ # to the next type, and self.first_bytes is set to the matching
89+ # bytes.
90+ yield self.current_type, wrap_and_count(pb, rc, substream)
91+ finally:
92+ if rc:
93+ pb.update('Done', rc.max, rc.max)
94+ pb.finished()
95
96 def seed_state(self):
97 """Prepare the _ByteStreamDecoder to decode from the pack stream."""
98
99=== modified file 'bzrlib/tests/per_tree/__init__.py'
100--- bzrlib/tests/per_tree/__init__.py 2011-06-14 01:26:41 +0000
101+++ bzrlib/tests/per_tree/__init__.py 2012-09-07 10:36:18 +0000
102@@ -29,6 +29,7 @@
103 errors,
104 tests,
105 transform,
106+ transport,
107 )
108 from bzrlib.tests.per_controldir.test_controldir import TestCaseWithControlDir
109 from bzrlib.tests.per_workingtree import (
110@@ -99,11 +100,24 @@
111 class TestCaseWithTree(TestCaseWithControlDir):
112
113 def make_branch_and_tree(self, relpath):
114- made_control = self.make_bzrdir(relpath, format=
115- self.workingtree_format._matchingbzrdir)
116+ bzrdir_format = self.workingtree_format.get_controldir_for_branch()
117+ made_control = self.make_bzrdir(relpath, format=bzrdir_format)
118 made_control.create_repository()
119- made_control.create_branch()
120- return self.workingtree_format.initialize(made_control)
121+ b = made_control.create_branch()
122+ if getattr(self, 'repo_is_remote', False):
123+ # If the repo is remote, then we just create a local lightweight
124+ # checkout
125+ # XXX: This duplicates a lot of Branch.create_checkout, but we know
126+ # we want a) lightweight, and b) a specific WT format. We also
127+ # know that nothing should already exist, etc.
128+ t = transport.get_transport(relpath)
129+ t.ensure_base()
130+ wt_dir = bzrdir_format.initialize_on_transport(t)
131+ branch_ref = wt_dir.set_branch_reference(b)
132+ wt = wt_dir.create_workingtree(None, from_branch=branch_ref)
133+ else:
134+ wt = self.workingtree_format.initialize(made_control)
135+ return wt
136
137 def workingtree_to_test_tree(self, tree):
138 return self._workingtree_to_test_tree(self, tree)
139
140=== modified file 'bzrlib/tests/per_workingtree/__init__.py'
141--- bzrlib/tests/per_workingtree/__init__.py 2011-09-23 12:32:30 +0000
142+++ bzrlib/tests/per_workingtree/__init__.py 2012-09-07 10:36:18 +0000
143@@ -25,18 +25,37 @@
144 from bzrlib import (
145 branchbuilder,
146 tests,
147+ transport,
148 workingtree,
149 )
150-from bzrlib.tests import per_controldir
151-
152-
153-def make_scenarios(transport_server, transport_readonly_server, formats):
154+from bzrlib.transport import memory
155+from bzrlib.tests import (
156+ per_controldir,
157+ test_server,
158+ )
159+
160+
161+def make_scenarios(transport_server, transport_readonly_server, formats,
162+ remote_server=None, remote_readonly_server=None,
163+ remote_backing_server=None):
164 result = []
165 for workingtree_format in formats:
166 result.append((workingtree_format.__class__.__name__,
167 make_scenario(transport_server,
168 transport_readonly_server,
169 workingtree_format)))
170+ default_wt_format = workingtree.format_registry.get_default()
171+ if remote_server is None:
172+ remote_server = test_server.SmartTCPServer_for_testing
173+ if remote_readonly_server is None:
174+ remote_readonly_server = test_server.ReadonlySmartTCPServer_for_testing
175+ if remote_backing_server is None:
176+ remote_backing_server = memory.MemoryServer
177+ scenario = make_scenario(remote_server, remote_readonly_server,
178+ default_wt_format)
179+ scenario['repo_is_remote'] = True;
180+ scenario['vfs_transport_factory'] = remote_backing_server
181+ result.append((default_wt_format.__class__.__name__ + ',remote', scenario))
182 return result
183
184
185@@ -71,8 +90,22 @@
186 def make_branch_and_tree(self, relpath, format=None):
187 made_control = self.make_bzrdir(relpath, format=format)
188 made_control.create_repository()
189- made_control.create_branch()
190- return self.workingtree_format.initialize(made_control)
191+ b = made_control.create_branch()
192+ if getattr(self, 'repo_is_remote', False):
193+ # If the repo is remote, then we just create a local lightweight
194+ # checkout
195+ # XXX: This duplicates a lot of Branch.create_checkout, but we know
196+ # we want a) lightweight, and b) a specific WT format. We also
197+ # know that nothing should already exist, etc.
198+ t = transport.get_transport(relpath)
199+ t.ensure_base()
200+ bzrdir_format = self.workingtree_format.get_controldir_for_branch()
201+ wt_dir = bzrdir_format.initialize_on_transport(t)
202+ branch_ref = wt_dir.set_branch_reference(b)
203+ wt = wt_dir.create_workingtree(None, from_branch=branch_ref)
204+ else:
205+ wt = self.workingtree_format.initialize(made_control)
206+ return wt
207
208 def make_branch_builder(self, relpath, format=None):
209 if format is None:
210
211=== modified file 'bzrlib/tests/per_workingtree/test_commit.py'
212--- bzrlib/tests/per_workingtree/test_commit.py 2012-01-25 21:13:15 +0000
213+++ bzrlib/tests/per_workingtree/test_commit.py 2012-09-07 10:36:18 +0000
214@@ -26,6 +26,7 @@
215 osutils,
216 revision as _mod_revision,
217 tests,
218+ transport as _mod_transport,
219 ui,
220 )
221 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
222@@ -316,7 +317,7 @@
223 wt.lock_write()
224 self.build_tree(['a', 'b/', 'b/c', 'd'])
225 wt.add(['a', 'b', 'b/c', 'd'], ['a-id', 'b-id', 'c-id', 'd-id'])
226- this_dir = self.get_transport()
227+ this_dir = wt.bzrdir.root_transport
228 this_dir.delete_tree('b')
229 this_dir.delete('d')
230 # now we have a tree with a through d in the inventory, but only
231@@ -352,7 +353,7 @@
232 wt.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
233 wt.commit('first')
234 wt.remove('b/c')
235- this_dir = self.get_transport()
236+ this_dir = wt.bzrdir.root_transport
237 this_dir.delete_tree('b')
238 wt.lock_write()
239 wt.commit('commit deleted rename')
240
241=== modified file 'bzrlib/tests/per_workingtree/test_executable.py'
242--- bzrlib/tests/per_workingtree/test_executable.py 2011-12-19 16:59:14 +0000
243+++ bzrlib/tests/per_workingtree/test_executable.py 2012-09-07 10:36:18 +0000
244@@ -71,8 +71,7 @@
245 self.wt.commit('adding a,b', rev_id='r1')
246 # Now make sure that 'bzr branch' also preserves the
247 # executable bit
248- # TODO: Maybe this should be a blackbox test
249- dir2 = self.wt.branch.bzrdir.clone('b2', revision_id='r1')
250+ dir2 = self.wt.branch.bzrdir.sprout('b2', revision_id='r1')
251 wt2 = dir2.open_workingtree()
252 self.assertEqual(['r1'], wt2.get_parent_ids())
253 self.assertEqual('r1', wt2.branch.last_revision())
254
255=== modified file 'bzrlib/tests/per_workingtree/test_parents.py'
256--- bzrlib/tests/per_workingtree/test_parents.py 2011-06-14 01:26:41 +0000
257+++ bzrlib/tests/per_workingtree/test_parents.py 2012-09-07 10:36:18 +0000
258@@ -21,9 +21,7 @@
259
260 from bzrlib import (
261 errors,
262- osutils,
263 revision as _mod_revision,
264- tests,
265 )
266 from bzrlib.inventory import (
267 Inventory,
268@@ -475,7 +473,11 @@
269 # large hammer, this is a particularly sensitive area of code, so the
270 # extra assurance is well worth it.
271 tree._validate()
272- osutils.rmtree('tree')
273+ # If tree.branch is remote
274+ if tree.user_url != tree.branch.user_url:
275+ # We have a lightweight checkout, delete both locations
276+ tree.branch.bzrdir.root_transport.delete_tree('.')
277+ tree.bzrdir.root_transport.delete_tree('.')
278
279 def test_no_parents_just_root(self):
280 """Test doing an empty commit - no parent, set a root only."""
281
282=== modified file 'bzrlib/tests/per_workingtree/test_remove.py'
283--- bzrlib/tests/per_workingtree/test_remove.py 2011-05-13 12:51:05 +0000
284+++ bzrlib/tests/per_workingtree/test_remove.py 2012-09-07 10:36:18 +0000
285@@ -173,7 +173,7 @@
286 """Removing a absent directory succeeds without corruption (#150438)."""
287 paths = ['a/', 'a/b']
288 tree = self.get_committed_tree(paths)
289- self.get_transport('.').delete_tree('a')
290+ tree.bzrdir.root_transport.delete_tree('a')
291 tree.remove(['a'])
292 self.assertRemovedAndDeleted('b')
293 tree._validate()
294
295=== modified file 'bzrlib/tests/per_workingtree/test_smart_add.py'
296--- bzrlib/tests/per_workingtree/test_smart_add.py 2011-09-06 09:51:45 +0000
297+++ bzrlib/tests/per_workingtree/test_smart_add.py 2012-09-07 10:36:18 +0000
298@@ -135,6 +135,9 @@
299
300 self.build_tree(build_paths)
301 wt = self.make_branch_and_tree('.')
302+ if wt.user_url != wt.branch.user_url:
303+ # Lightweight checkout, make sure we have a repo location.
304+ wt.branch.bzrdir.root_transport.mkdir('original')
305 child_tree = self.make_branch_and_tree('original/child')
306 wt.smart_add((".",))
307 for path in paths:
308
309=== modified file 'bzrlib/tests/per_workingtree/test_views.py'
310--- bzrlib/tests/per_workingtree/test_views.py 2009-07-10 07:14:02 +0000
311+++ bzrlib/tests/per_workingtree/test_views.py 2012-09-07 10:36:18 +0000
312@@ -22,7 +22,7 @@
313
314
315 from bzrlib import views, errors
316-from bzrlib.tests import TestSkipped
317+from bzrlib.tests import TestNotApplicable, TestSkipped
318 from bzrlib.workingtree import WorkingTree
319
320 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
321@@ -39,7 +39,7 @@
322 raise TestSkipped("format %s doesn't declare whether it "
323 "supports views, assuming not" % fmt)
324 if not f():
325- raise TestSkipped("format %s doesn't support views" % fmt)
326+ raise TestNotApplicable("format %s doesn't support views" % fmt)
327 TestCaseWithWorkingTree.setUp(self)
328
329 def test_views_initially_empty(self):
330
331=== modified file 'bzrlib/tests/per_workingtree/test_workingtree.py'
332--- bzrlib/tests/per_workingtree/test_workingtree.py 2012-01-25 21:13:15 +0000
333+++ bzrlib/tests/per_workingtree/test_workingtree.py 2012-09-07 10:36:18 +0000
334@@ -57,10 +57,20 @@
335
336 class TestWorkingTree(TestCaseWithWorkingTree):
337
338+ def requireBranchReference(self):
339+ test_branch = self.make_branch('test-branch')
340+ try:
341+ # if there is a working tree now, this is not supported.
342+ test_branch.bzrdir.open_workingtree()
343+ raise TestNotApplicable("only on trees that can be separate"
344+ " from their branch.")
345+ except (errors.NoWorkingTree, errors.NotLocalUrl):
346+ pass
347+
348 def test_branch_builder(self):
349 # Just a smoke test that we get a branch at the specified relpath
350 builder = self.make_branch_builder('foobar')
351- br = branch.Branch.open('foobar')
352+ br = branch.Branch.open(self.get_url('foobar'))
353
354 def test_list_files(self):
355 tree = self.make_branch_and_tree('.')
356@@ -122,8 +132,10 @@
357 result[0][:4])
358
359 def test_open_containing(self):
360- branch = self.make_branch_and_tree('.').branch
361- local_base = urlutils.local_path_from_url(branch.base)
362+ local_wt = self.make_branch_and_tree('.')
363+ local_url = local_wt.bzrdir.root_transport.base
364+ local_base = urlutils.local_path_from_url(local_url)
365+ del local_wt
366
367 # Empty opens '.'
368 wt, relpath = WorkingTree.open_containing()
369@@ -161,6 +173,7 @@
370
371 def test_lock_locks_branch(self):
372 tree = self.make_branch_and_tree('.')
373+ self.assertEqual(None, tree.branch.peek_lock_mode())
374 tree.lock_read()
375 self.assertEqual('r', tree.branch.peek_lock_mode())
376 tree.unlock()
377@@ -362,14 +375,8 @@
378 # that formats where initialising a branch does not initialise a
379 # tree - and thus have separable entities - support skewing the
380 # two things.
381- branch = self.make_branch('tree')
382- try:
383- # if there is a working tree now, this is not supported.
384- branch.bzrdir.open_workingtree()
385- return
386- except errors.NoWorkingTree:
387- pass
388- wt = branch.bzrdir.create_workingtree()
389+ self.requireBranchReference()
390+ wt = self.make_branch_and_tree('tree')
391 wt.commit('A', allow_pointless=True, rev_id='A')
392 wt.set_last_revision(None)
393 self.assertEqual([], wt.get_parent_ids())
394@@ -478,19 +485,13 @@
395 # that formats where initialising a branch does not initialise a
396 # tree - and thus have separable entities - support skewing the
397 # two things.
398- main_branch = self.make_branch('tree')
399- try:
400- # if there is a working tree now, this is not supported.
401- main_branch.bzrdir.open_workingtree()
402- return
403- except errors.NoWorkingTree:
404- pass
405- wt = main_branch.bzrdir.create_workingtree()
406+ self.requireBranchReference()
407+ wt = self.make_branch_and_tree('tree')
408 # create an out of date working tree by making a checkout in this
409 # current format
410 self.build_tree(['checkout/', 'tree/file'])
411 checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
412- checkout.set_branch_reference(main_branch)
413+ checkout.set_branch_reference(wt.branch)
414 old_tree = self.workingtree_format.initialize(checkout)
415 # now commit to 'tree'
416 wt.add('file')
417@@ -545,19 +546,13 @@
418 # that formats where initialising a branch does not initialise a
419 # tree - and thus have separable entities - support skewing the
420 # two things.
421- main_branch = self.make_branch('tree')
422- try:
423- # if there is a working tree now, this is not supported.
424- main_branch.bzrdir.open_workingtree()
425- return
426- except errors.NoWorkingTree:
427- pass
428- wt = main_branch.bzrdir.create_workingtree()
429+ self.requireBranchReference()
430+ wt = self.make_branch_and_tree('tree')
431 # create an out of date working tree by making a checkout in this
432 # current format
433 self.build_tree(['checkout/', 'tree/file'])
434 checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
435- checkout.set_branch_reference(main_branch)
436+ checkout.set_branch_reference(wt.branch)
437 old_tree = self.workingtree_format.initialize(checkout)
438 # now commit to 'tree'
439 wt.add('file')
440
441=== modified file 'bzrlib/tests/test_selftest.py'
442--- bzrlib/tests/test_selftest.py 2011-11-08 17:07:23 +0000
443+++ bzrlib/tests/test_selftest.py 2012-09-07 10:36:18 +0000
444@@ -334,8 +334,11 @@
445 server1 = "a"
446 server2 = "b"
447 formats = [workingtree_4.WorkingTreeFormat4(),
448- workingtree_3.WorkingTreeFormat3(),]
449- scenarios = make_scenarios(server1, server2, formats)
450+ workingtree_3.WorkingTreeFormat3(),
451+ workingtree_4.WorkingTreeFormat6()]
452+ scenarios = make_scenarios(server1, server2, formats,
453+ remote_server='c', remote_readonly_server='d',
454+ remote_backing_server='e')
455 self.assertEqual([
456 ('WorkingTreeFormat4',
457 {'bzrdir_format': formats[0]._matchingbzrdir,
458@@ -346,19 +349,33 @@
459 {'bzrdir_format': formats[1]._matchingbzrdir,
460 'transport_readonly_server': 'b',
461 'transport_server': 'a',
462- 'workingtree_format': formats[1]})],
463- scenarios)
464+ 'workingtree_format': formats[1]}),
465+ ('WorkingTreeFormat6',
466+ {'bzrdir_format': formats[2]._matchingbzrdir,
467+ 'transport_readonly_server': 'b',
468+ 'transport_server': 'a',
469+ 'workingtree_format': formats[2]}),
470+ ('WorkingTreeFormat6,remote',
471+ {'bzrdir_format': formats[2]._matchingbzrdir,
472+ 'repo_is_remote': True,
473+ 'transport_readonly_server': 'd',
474+ 'transport_server': 'c',
475+ 'vfs_transport_factory': 'e',
476+ 'workingtree_format': formats[2]}),
477+ ], scenarios)
478
479
480 class TestTreeScenarios(tests.TestCase):
481
482 def test_scenarios(self):
483 # the tree implementation scenario generator is meant to setup one
484- # instance for each working tree format, and one additional instance
485+ # instance for each working tree format, one additional instance
486 # that will use the default wt format, but create a revision tree for
487- # the tests. this means that the wt ones should have the
488- # workingtree_to_test_tree attribute set to 'return_parameter' and the
489- # revision one set to revision_tree_from_workingtree.
490+ # the tests, and one more that uses the default wt format as a
491+ # lightweight checkout of a remote repository. This means that the wt
492+ # ones should have the workingtree_to_test_tree attribute set to
493+ # 'return_parameter' and the revision one set to
494+ # revision_tree_from_workingtree.
495
496 from bzrlib.tests.per_tree import (
497 _dirstate_tree_from_workingtree,
498@@ -370,13 +387,17 @@
499 )
500 server1 = "a"
501 server2 = "b"
502+ smart_server = test_server.SmartTCPServer_for_testing
503+ smart_readonly_server = test_server.ReadonlySmartTCPServer_for_testing
504+ mem_server = memory.MemoryServer
505 formats = [workingtree_4.WorkingTreeFormat4(),
506 workingtree_3.WorkingTreeFormat3(),]
507 scenarios = make_scenarios(server1, server2, formats)
508- self.assertEqual(7, len(scenarios))
509+ self.assertEqual(8, len(scenarios))
510 default_wt_format = workingtree.format_registry.get_default()
511 wt4_format = workingtree_4.WorkingTreeFormat4()
512 wt5_format = workingtree_4.WorkingTreeFormat5()
513+ wt6_format = workingtree_4.WorkingTreeFormat6()
514 expected_scenarios = [
515 ('WorkingTreeFormat4',
516 {'bzrdir_format': formats[0]._matchingbzrdir,
517@@ -392,6 +413,15 @@
518 'workingtree_format': formats[1],
519 '_workingtree_to_test_tree': return_parameter,
520 }),
521+ ('WorkingTreeFormat6,remote',
522+ {'bzrdir_format': wt6_format._matchingbzrdir,
523+ 'repo_is_remote': True,
524+ 'transport_readonly_server': smart_readonly_server,
525+ 'transport_server': smart_server,
526+ 'vfs_transport_factory': mem_server,
527+ 'workingtree_format': wt6_format,
528+ '_workingtree_to_test_tree': return_parameter,
529+ }),
530 ('RevisionTree',
531 {'_workingtree_to_test_tree': revision_tree_from_workingtree,
532 'bzrdir_format': default_wt_format._matchingbzrdir,
533
534=== modified file 'bzrlib/workingtree_4.py'
535--- bzrlib/workingtree_4.py 2012-01-06 14:09:04 +0000
536+++ bzrlib/workingtree_4.py 2012-09-07 10:36:18 +0000
537@@ -1,4 +1,4 @@
538-# Copyright (C) 2007-2011 Canonical Ltd
539+# Copyright (C) 2007-2012 Canonical Ltd
540 #
541 # This program is free software; you can redistribute it and/or modify
542 # it under the terms of the GNU General Public License as published by
543@@ -1677,6 +1677,12 @@
544 def supports_views(self):
545 return True
546
547+ def _get_matchingbzrdir(self):
548+ """Overrideable method to get a bzrdir for testing."""
549+ # We use 'development-subtree' instead of '2a', because we have a
550+ # few tests that want to test tree references
551+ return bzrdir.format_registry.make_bzrdir('development-subtree')
552+
553
554 class DirStateRevisionTree(InventoryTree):
555 """A revision tree pulling the inventory from a dirstate.
556@@ -1882,8 +1888,18 @@
557 return self.inventory[file_id].text_size
558
559 def get_file_text(self, file_id, path=None):
560- _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
561- return ''.join(content)
562+ content = None
563+ for _, content_iter in self.iter_files_bytes([(file_id, None)]):
564+ if content is not None:
565+ raise AssertionError('iter_files_bytes returned'
566+ ' too many entries')
567+ # For each entry returned by iter_files_bytes, we must consume the
568+ # content_iter before we step the files iterator.
569+ content = ''.join(content_iter)
570+ if content is None:
571+ raise AssertionError('iter_files_bytes did not return'
572+ ' the requested data')
573+ return content
574
575 def get_reference_revision(self, file_id, path=None):
576 return self.inventory[file_id].reference_revision
577
578=== modified file 'doc/en/release-notes/bzr-2.5.txt'
579--- doc/en/release-notes/bzr-2.5.txt 2012-08-01 08:51:57 +0000
580+++ doc/en/release-notes/bzr-2.5.txt 2012-09-07 10:36:18 +0000
581@@ -35,8 +35,16 @@
582 * ``bzr config`` properly handles aliases and references in the
583 ``--directory`` parameter (Vincent Ladeuil, Wouter van Heyst, #947049)
584
585+* Lightweight checkouts of remote repositories had a bug with how they
586+ extracted texts from the repository. (Just an ordering constraint on how
587+ they consumed the stream.) (John Arbash Meinel, #1046284)
588+
589 * Revert use of --no-tty when gpg signing commits. (Jelmer Vernooij, #1014570)
590
591+* Some small bug fixes wrt lightweight checkouts and remote repositories.
592+ A test permutation was added that runs all working tree tests against a
593+ lightweight checkout. (John Arbash Meinel, #1046697)
594+
595 Documentation
596 *************
597

Subscribers

People subscribed via source and target branches