/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branchbuilder.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007-2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the BranchBuilder class."""
 
18
 
 
19
from bzrlib import (
 
20
    branch as _mod_branch,
 
21
    revision as _mod_revision,
 
22
    tests,
 
23
    )
 
24
from bzrlib.branchbuilder import BranchBuilder
 
25
 
 
26
 
 
27
class TestBranchBuilder(tests.TestCaseWithMemoryTransport):
 
28
 
 
29
    def test_create(self):
 
30
        """Test the constructor api."""
 
31
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
32
        # we dont care if the branch has been built or not at this point.
 
33
 
 
34
    def test_get_branch(self):
 
35
        """get_branch returns the created branch."""
 
36
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
37
        branch = builder.get_branch()
 
38
        self.assertIsInstance(branch, _mod_branch.Branch)
 
39
        self.assertEqual(self.get_transport().clone('foo').base,
 
40
            branch.base)
 
41
        self.assertEqual(
 
42
            (0, _mod_revision.NULL_REVISION),
 
43
            branch.last_revision_info())
 
44
 
 
45
    def test_format(self):
 
46
        """Making a BranchBuilder with a format option sets the branch type."""
 
47
        builder = BranchBuilder(self.get_transport(), format='dirstate-tags')
 
48
        branch = builder.get_branch()
 
49
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
 
50
 
 
51
    def test_build_one_commit(self):
 
52
        """doing build_commit causes a commit to happen."""
 
53
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
54
        rev_id = builder.build_commit()
 
55
        branch = builder.get_branch()
 
56
        self.assertEqual((1, rev_id), branch.last_revision_info())
 
57
        self.assertEqual(
 
58
            'commit 1',
 
59
            branch.repository.get_revision(branch.last_revision()).message)
 
60
 
 
61
    def test_build_commit_timestamp(self):
 
62
        """You can set a date when committing."""
 
63
        builder = self.make_branch_builder('foo')
 
64
        rev_id = builder.build_commit(timestamp=1236043340)
 
65
        branch = builder.get_branch()
 
66
        self.assertEqual((1, rev_id), branch.last_revision_info())
 
67
        rev = branch.repository.get_revision(branch.last_revision())
 
68
        self.assertEqual(
 
69
            'commit 1',
 
70
            rev.message)
 
71
        self.assertEqual(
 
72
            1236043340,
 
73
            int(rev.timestamp))
 
74
 
 
75
    def test_build_two_commits(self):
 
76
        """The second commit has the right parents and message."""
 
77
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
78
        rev_id1 = builder.build_commit()
 
79
        rev_id2 = builder.build_commit()
 
80
        branch = builder.get_branch()
 
81
        self.assertEqual((2, rev_id2), branch.last_revision_info())
 
82
        self.assertEqual(
 
83
            'commit 2',
 
84
            branch.repository.get_revision(branch.last_revision()).message)
 
85
        self.assertEqual(
 
86
            [rev_id1],
 
87
            branch.repository.get_revision(branch.last_revision()).parent_ids)
 
88
 
 
89
    def test_build_commit_parent_ids(self):
 
90
        """build_commit() takes a parent_ids argument."""
 
91
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
92
        rev_id1 = builder.build_commit(
 
93
            parent_ids=["ghost"], allow_leftmost_as_ghost=True)
 
94
        rev_id2 = builder.build_commit(parent_ids=[])
 
95
        branch = builder.get_branch()
 
96
        self.assertEqual((1, rev_id2), branch.last_revision_info())
 
97
        self.assertEqual(
 
98
            ["ghost"],
 
99
            branch.repository.get_revision(rev_id1).parent_ids)
 
100
 
 
101
 
 
102
class TestBranchBuilderBuildSnapshot(tests.TestCaseWithMemoryTransport):
 
103
 
 
104
    def assertTreeShape(self, expected_shape, tree):
 
105
        """Check that the tree shape matches expectations."""
 
106
        tree.lock_read()
 
107
        try:
 
108
            entries = [(path, ie.file_id, ie.kind)
 
109
                       for path, ie in tree.iter_entries_by_dir()]
 
110
        finally:
 
111
            tree.unlock()
 
112
        self.assertEqual(expected_shape, entries)
 
113
 
 
114
    def build_a_rev(self):
 
115
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
116
        rev_id1 = builder.build_snapshot('A-id', None,
 
117
            [('add', ('', 'a-root-id', 'directory', None)),
 
118
             ('add', ('a', 'a-id', 'file', 'contents'))])
 
119
        self.assertEqual('A-id', rev_id1)
 
120
        return builder
 
121
 
 
122
    def test_add_one_file(self):
 
123
        builder = self.build_a_rev()
 
124
        branch = builder.get_branch()
 
125
        self.assertEqual((1, 'A-id'), branch.last_revision_info())
 
126
        rev_tree = branch.repository.revision_tree('A-id')
 
127
        rev_tree.lock_read()
 
128
        self.addCleanup(rev_tree.unlock)
 
129
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
130
                              (u'a', 'a-id', 'file')], rev_tree)
 
131
        self.assertEqual('contents', rev_tree.get_file_text('a-id'))
 
132
 
 
133
    def test_add_second_file(self):
 
134
        builder = self.build_a_rev()
 
135
        rev_id2 = builder.build_snapshot('B-id', None,
 
136
            [('add', ('b', 'b-id', 'file', 'content_b'))])
 
137
        self.assertEqual('B-id', rev_id2)
 
138
        branch = builder.get_branch()
 
139
        self.assertEqual((2, rev_id2), branch.last_revision_info())
 
140
        rev_tree = branch.repository.revision_tree(rev_id2)
 
141
        rev_tree.lock_read()
 
142
        self.addCleanup(rev_tree.unlock)
 
143
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
144
                              (u'a', 'a-id', 'file'),
 
145
                              (u'b', 'b-id', 'file')], rev_tree)
 
146
        self.assertEqual('content_b', rev_tree.get_file_text('b-id'))
 
147
 
 
148
    def test_add_empty_dir(self):
 
149
        builder = self.build_a_rev()
 
150
        rev_id2 = builder.build_snapshot('B-id', None,
 
151
            [('add', ('b', 'b-id', 'directory', None))])
 
152
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
 
153
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
154
                              (u'a', 'a-id', 'file'),
 
155
                              (u'b', 'b-id', 'directory'),
 
156
                             ], rev_tree)
 
157
 
 
158
    def test_commit_timestamp(self):
 
159
        builder = self.make_branch_builder('foo')
 
160
        rev_id = builder.build_snapshot(None, None,
 
161
            [('add', (u'', None, 'directory', None))],
 
162
            timestamp=1234567890)
 
163
        rev = builder.get_branch().repository.get_revision(rev_id)
 
164
        self.assertEqual(
 
165
            1234567890,
 
166
            int(rev.timestamp))
 
167
 
 
168
    def test_commit_message_default(self):
 
169
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
170
        rev_id = builder.build_snapshot(None, None,
 
171
            [('add', (u'', None, 'directory', None))])
 
172
        branch = builder.get_branch()
 
173
        rev = branch.repository.get_revision(rev_id)
 
174
        self.assertEqual(u'commit 1', rev.message)
 
175
 
 
176
    def test_commit_message_supplied(self):
 
177
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
178
        rev_id = builder.build_snapshot(None, None,
 
179
            [('add', (u'', None, 'directory', None))],
 
180
            message=u'Foo')
 
181
        branch = builder.get_branch()
 
182
        rev = branch.repository.get_revision(rev_id)
 
183
        self.assertEqual(u'Foo', rev.message)
 
184
 
 
185
    def test_commit_message_callback(self):
 
186
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
187
        rev_id = builder.build_snapshot(None, None,
 
188
            [('add', (u'', None, 'directory', None))],
 
189
            message_callback=lambda x:u'Foo')
 
190
        branch = builder.get_branch()
 
191
        rev = branch.repository.get_revision(rev_id)
 
192
        self.assertEqual(u'Foo', rev.message)
 
193
 
 
194
    def test_modify_file(self):
 
195
        builder = self.build_a_rev()
 
196
        rev_id2 = builder.build_snapshot('B-id', None,
 
197
            [('modify', ('a-id', 'new\ncontent\n'))])
 
198
        self.assertEqual('B-id', rev_id2)
 
199
        branch = builder.get_branch()
 
200
        rev_tree = branch.repository.revision_tree(rev_id2)
 
201
        rev_tree.lock_read()
 
202
        self.addCleanup(rev_tree.unlock)
 
203
        self.assertEqual('new\ncontent\n', rev_tree.get_file_text('a-id'))
 
204
 
 
205
    def test_delete_file(self):
 
206
        builder = self.build_a_rev()
 
207
        rev_id2 = builder.build_snapshot('B-id', None,
 
208
            [('unversion', 'a-id')])
 
209
        self.assertEqual('B-id', rev_id2)
 
210
        branch = builder.get_branch()
 
211
        rev_tree = branch.repository.revision_tree(rev_id2)
 
212
        rev_tree.lock_read()
 
213
        self.addCleanup(rev_tree.unlock)
 
214
        self.assertTreeShape([(u'', 'a-root-id', 'directory')], rev_tree)
 
215
 
 
216
    def test_delete_directory(self):
 
217
        builder = self.build_a_rev()
 
218
        rev_id2 = builder.build_snapshot('B-id', None,
 
219
            [('add', ('b', 'b-id', 'directory', None)),
 
220
             ('add', ('b/c', 'c-id', 'file', 'foo\n')),
 
221
             ('add', ('b/d', 'd-id', 'directory', None)),
 
222
             ('add', ('b/d/e', 'e-id', 'file', 'eff\n')),
 
223
            ])
 
224
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
 
225
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
226
                              (u'a', 'a-id', 'file'),
 
227
                              (u'b', 'b-id', 'directory'),
 
228
                              (u'b/c', 'c-id', 'file'),
 
229
                              (u'b/d', 'd-id', 'directory'),
 
230
                              (u'b/d/e', 'e-id', 'file')], rev_tree)
 
231
        # Removing a directory removes all child dirs
 
232
        builder.build_snapshot('C-id', None, [('unversion', 'b-id')])
 
233
        rev_tree = builder.get_branch().repository.revision_tree('C-id')
 
234
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
235
                              (u'a', 'a-id', 'file'),
 
236
                             ], rev_tree)
 
237
 
 
238
    def test_unknown_action(self):
 
239
        builder = self.build_a_rev()
 
240
        e = self.assertRaises(ValueError,
 
241
            builder.build_snapshot, 'B-id', None, [('weirdo', ('foo',))])
 
242
        self.assertEqual('Unknown build action: "weirdo"', str(e))
 
243
 
 
244
    def test_rename(self):
 
245
        builder = self.build_a_rev()
 
246
        builder.build_snapshot('B-id', None,
 
247
            [('rename', ('a', 'b'))])
 
248
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
 
249
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
250
                              (u'b', 'a-id', 'file')], rev_tree)
 
251
 
 
252
    def test_rename_into_subdir(self):
 
253
        builder = self.build_a_rev()
 
254
        builder.build_snapshot('B-id', None,
 
255
            [('add', ('dir', 'dir-id', 'directory', None)),
 
256
             ('rename', ('a', 'dir/a'))])
 
257
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
 
258
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
259
                              (u'dir', 'dir-id', 'directory'),
 
260
                              (u'dir/a', 'a-id', 'file')], rev_tree)
 
261
 
 
262
    def test_rename_out_of_unversioned_subdir(self):
 
263
        builder = self.build_a_rev()
 
264
        builder.build_snapshot('B-id', None,
 
265
            [('add', ('dir', 'dir-id', 'directory', None)),
 
266
             ('rename', ('a', 'dir/a'))])
 
267
        builder.build_snapshot('C-id', None,
 
268
            [('rename', ('dir/a', 'a')),
 
269
             ('unversion', 'dir-id')])
 
270
        rev_tree = builder.get_branch().repository.revision_tree('C-id')
 
271
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
272
                              (u'a', 'a-id', 'file')], rev_tree)
 
273
 
 
274
    def test_set_parent(self):
 
275
        builder = self.build_a_rev()
 
276
        builder.start_series()
 
277
        self.addCleanup(builder.finish_series)
 
278
        builder.build_snapshot('B-id', ['A-id'],
 
279
            [('modify', ('a-id', 'new\ncontent\n'))])
 
280
        builder.build_snapshot('C-id', ['A-id'],
 
281
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
 
282
        # We should now have a graph:
 
283
        #   A
 
284
        #   |\
 
285
        #   C B
 
286
        # And not A => B => C
 
287
        repo = builder.get_branch().repository
 
288
        self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',)},
 
289
                         repo.get_parent_map(['B-id', 'C-id']))
 
290
        b_tree = repo.revision_tree('B-id')
 
291
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
292
                              (u'a', 'a-id', 'file'),
 
293
                             ], b_tree)
 
294
        self.assertEqual('new\ncontent\n', b_tree.get_file_text('a-id'))
 
295
 
 
296
        # We should still be using the content from A in C, not from B
 
297
        c_tree = repo.revision_tree('C-id')
 
298
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
299
                              (u'a', 'a-id', 'file'),
 
300
                              (u'c', 'c-id', 'file'),
 
301
                             ], c_tree)
 
302
        self.assertEqual('contents', c_tree.get_file_text('a-id'))
 
303
        self.assertEqual('alt\ncontent\n', c_tree.get_file_text('c-id'))
 
304
 
 
305
    def test_set_merge_parent(self):
 
306
        builder = self.build_a_rev()
 
307
        builder.start_series()
 
308
        self.addCleanup(builder.finish_series)
 
309
        builder.build_snapshot('B-id', ['A-id'],
 
310
            [('add', ('b', 'b-id', 'file', 'b\ncontent\n'))])
 
311
        builder.build_snapshot('C-id', ['A-id'],
 
312
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
 
313
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
 
314
        repo = builder.get_branch().repository
 
315
        self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',),
 
316
                          'D-id': ('B-id', 'C-id')},
 
317
                         repo.get_parent_map(['B-id', 'C-id', 'D-id']))
 
318
        d_tree = repo.revision_tree('D-id')
 
319
        # Note: by default a merge node does *not* pull in the changes from the
 
320
        #       merged tree, you have to supply it yourself.
 
321
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
322
                              (u'a', 'a-id', 'file'),
 
323
                              (u'b', 'b-id', 'file'),
 
324
                             ], d_tree)
 
325
 
 
326
    def test_set_merge_parent_and_contents(self):
 
327
        builder = self.build_a_rev()
 
328
        builder.start_series()
 
329
        self.addCleanup(builder.finish_series)
 
330
        builder.build_snapshot('B-id', ['A-id'],
 
331
            [('add', ('b', 'b-id', 'file', 'b\ncontent\n'))])
 
332
        builder.build_snapshot('C-id', ['A-id'],
 
333
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
 
334
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
 
335
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
 
336
        repo = builder.get_branch().repository
 
337
        self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',),
 
338
                          'D-id': ('B-id', 'C-id')},
 
339
                         repo.get_parent_map(['B-id', 'C-id', 'D-id']))
 
340
        d_tree = repo.revision_tree('D-id')
 
341
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
 
342
                              (u'a', 'a-id', 'file'),
 
343
                              (u'b', 'b-id', 'file'),
 
344
                              (u'c', 'c-id', 'file'),
 
345
                             ], d_tree)
 
346
        # Because we copied the exact text into *this* tree, the 'c' file
 
347
        # should look like it was not modified in the merge
 
348
        self.assertEqual('C-id', d_tree.get_file_revision('c-id'))
 
349
 
 
350
    def test_set_parent_to_null(self):
 
351
        builder = self.build_a_rev()
 
352
        builder.start_series()
 
353
        self.addCleanup(builder.finish_series)
 
354
        builder.build_snapshot('B-id', [],
 
355
            [('add', ('', None, 'directory', None))])
 
356
        # We should now have a graph:
 
357
        #   A B
 
358
        # And not A => B
 
359
        repo = builder.get_branch().repository
 
360
        self.assertEqual({'A-id': (_mod_revision.NULL_REVISION,),
 
361
                          'B-id': (_mod_revision.NULL_REVISION,),},
 
362
                         repo.get_parent_map(['A-id', 'B-id']))
 
363
 
 
364
    
 
365
    def test_start_finish_series(self):
 
366
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
367
        builder.start_series()
 
368
        try:
 
369
            self.assertIsNot(None, builder._tree)
 
370
            self.assertEqual('w', builder._tree._lock_mode)
 
371
            self.assertTrue(builder._branch.is_locked())
 
372
        finally:
 
373
            builder.finish_series()
 
374
        self.assertIs(None, builder._tree)
 
375
        self.assertFalse(builder._branch.is_locked())
 
376
 
 
377
    def test_ghost_mainline_history(self):
 
378
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
379
        builder.start_series()
 
380
        try:
 
381
            builder.build_snapshot('tip', ['ghost'],
 
382
                [('add', ('', 'ROOT_ID', 'directory', ''))],
 
383
                allow_leftmost_as_ghost=True)
 
384
        finally:
 
385
            builder.finish_series()
 
386
        b = builder.get_branch()
 
387
        b.lock_read()
 
388
        self.addCleanup(b.unlock)
 
389
        self.assertEqual(('ghost',),
 
390
            b.repository.get_graph().get_parent_map(['tip'])['tip'])
 
391
 
 
392
    def test_unversion_root_add_new_root(self):
 
393
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
394
        builder.start_series()
 
395
        builder.build_snapshot('rev-1', None,
 
396
            [('add', ('', 'TREE_ROOT', 'directory', ''))])
 
397
        builder.build_snapshot('rev-2', None,
 
398
            [('unversion', 'TREE_ROOT'),
 
399
             ('add', ('', 'my-root', 'directory', ''))])
 
400
        builder.finish_series()
 
401
        rev_tree = builder.get_branch().repository.revision_tree('rev-2')
 
402
        self.assertTreeShape([(u'', 'my-root', 'directory')], rev_tree)
 
403
 
 
404
    def test_empty_flush(self):
 
405
        """A flush with no actions before it is a no-op."""
 
406
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
407
        builder.start_series()
 
408
        builder.build_snapshot('rev-1', None,
 
409
            [('add', ('', 'TREE_ROOT', 'directory', ''))])
 
410
        builder.build_snapshot('rev-2', None, [('flush', None)])
 
411
        builder.finish_series()
 
412
        rev_tree = builder.get_branch().repository.revision_tree('rev-2')
 
413
        self.assertTreeShape([(u'', 'TREE_ROOT', 'directory')], rev_tree)
 
414
 
 
415
    def test_kind_change(self):
 
416
        """It's possible to change the kind of an entry in a single snapshot
 
417
        with a bit of help from the 'flush' action.
 
418
        """
 
419
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
420
        builder.start_series()
 
421
        builder.build_snapshot('A-id', None,
 
422
            [('add', (u'', 'a-root-id', 'directory', None)),
 
423
             ('add', (u'a', 'a-id', 'file', 'content\n'))])
 
424
        builder.build_snapshot('B-id', None,
 
425
            [('unversion', 'a-id'),
 
426
             ('flush', None),
 
427
             ('add', (u'a', 'a-id', 'directory', None))])
 
428
        builder.finish_series()
 
429
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
 
430
        self.assertTreeShape(
 
431
            [(u'', 'a-root-id', 'directory'), (u'a', 'a-id', 'directory')],
 
432
            rev_tree)
 
433
 
 
434
    def test_pivot_root(self):
 
435
        """It's possible (albeit awkward) to move an existing dir to the root
 
436
        in a single snapshot by using unversion then flush then add.
 
437
        """
 
438
        builder = BranchBuilder(self.get_transport().clone('foo'))
 
439
        builder.start_series()
 
440
        builder.build_snapshot('A-id', None,
 
441
            [('add', (u'', 'orig-root', 'directory', None)),
 
442
             ('add', (u'dir', 'dir-id', 'directory', None))])
 
443
        builder.build_snapshot('B-id', None,
 
444
            [('unversion', 'orig-root'),  # implicitly unversions all children
 
445
             ('flush', None),
 
446
             ('add', (u'', 'dir-id', 'directory', None))])
 
447
        builder.finish_series()
 
448
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
 
449
        self.assertTreeShape([(u'', 'dir-id', 'directory')], rev_tree)
 
450