/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_fetch.py

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011, 2016 Canonical Ltd
 
1
# Copyright (C) 2005, 2007, 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from .. import (
 
17
import os
 
18
import re
 
19
import sys
 
20
 
 
21
import bzrlib
 
22
from bzrlib import (
 
23
    bzrdir,
18
24
    errors,
19
25
    osutils,
20
 
    revision as _mod_revision,
21
 
    )
22
 
from ..bzr import (
23
 
    bzrdir,
 
26
    merge,
 
27
    repository,
24
28
    versionedfile,
25
29
    )
26
 
from ..branch import Branch
27
 
from ..bzr import knitrepo
28
 
from . import TestCaseWithTransport
29
 
from .test_revision import make_branches
30
 
from ..upgrade import Convert
31
 
from ..workingtree import WorkingTree
 
30
from bzrlib.branch import Branch
 
31
from bzrlib.bzrdir import BzrDir
 
32
from bzrlib.repofmt import knitrepo
 
33
from bzrlib.tests import TestCaseWithTransport
 
34
from bzrlib.tests.test_revision import make_branches
 
35
from bzrlib.trace import mutter
 
36
from bzrlib.upgrade import Convert
 
37
from bzrlib.workingtree import WorkingTree
32
38
 
33
39
# These tests are a bit old; please instead add new tests into
34
40
# per_interrepository/ so they'll run on all relevant
38
44
def has_revision(branch, revision_id):
39
45
    return branch.repository.has_revision(revision_id)
40
46
 
41
 
 
42
 
def revision_history(branch):
43
 
    branch.lock_read()
44
 
    try:
45
 
        graph = branch.repository.get_graph()
46
 
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
47
 
                                                    [_mod_revision.NULL_REVISION]))
48
 
    finally:
49
 
        branch.unlock()
50
 
    history.reverse()
51
 
    return history
52
 
 
53
 
 
54
47
def fetch_steps(self, br_a, br_b, writable_a):
55
48
    """A foreign test method for testing fetch locally and remotely."""
56
49
 
57
50
    # TODO RBC 20060201 make this a repository test.
58
51
    repo_b = br_b.repository
59
 
    self.assertFalse(repo_b.has_revision(revision_history(br_a)[3]))
60
 
    self.assertTrue(repo_b.has_revision(revision_history(br_a)[2]))
61
 
    self.assertEqual(len(revision_history(br_b)), 7)
62
 
    br_b.fetch(br_a, revision_history(br_a)[2])
 
52
    self.assertFalse(repo_b.has_revision(br_a.revision_history()[3]))
 
53
    self.assertTrue(repo_b.has_revision(br_a.revision_history()[2]))
 
54
    self.assertEquals(len(br_b.revision_history()), 7)
 
55
    br_b.fetch(br_a, br_a.revision_history()[2])
63
56
    # branch.fetch is not supposed to alter the revision history
64
 
    self.assertEqual(len(revision_history(br_b)), 7)
65
 
    self.assertFalse(repo_b.has_revision(revision_history(br_a)[3]))
 
57
    self.assertEquals(len(br_b.revision_history()), 7)
 
58
    self.assertFalse(repo_b.has_revision(br_a.revision_history()[3]))
66
59
 
67
60
    # fetching the next revision up in sample data copies one revision
68
 
    br_b.fetch(br_a, revision_history(br_a)[3])
69
 
    self.assertTrue(repo_b.has_revision(revision_history(br_a)[3]))
70
 
    self.assertFalse(has_revision(br_a, revision_history(br_b)[6]))
71
 
    self.assertTrue(br_a.repository.has_revision(revision_history(br_b)[5]))
 
61
    br_b.fetch(br_a, br_a.revision_history()[3])
 
62
    self.assertTrue(repo_b.has_revision(br_a.revision_history()[3]))
 
63
    self.assertFalse(has_revision(br_a, br_b.revision_history()[6]))
 
64
    self.assertTrue(br_a.repository.has_revision(br_b.revision_history()[5]))
72
65
 
73
66
    # When a non-branch ancestor is missing, it should be unlisted...
74
67
    # as its not reference from the inventory weave.
76
69
    br_b4.fetch(br_b)
77
70
 
78
71
    writable_a.fetch(br_b)
79
 
    self.assertTrue(has_revision(br_a, revision_history(br_b)[3]))
80
 
    self.assertTrue(has_revision(br_a, revision_history(br_b)[4]))
 
72
    self.assertTrue(has_revision(br_a, br_b.revision_history()[3]))
 
73
    self.assertTrue(has_revision(br_a, br_b.revision_history()[4]))
81
74
 
82
75
    br_b2 = self.make_branch('br_b2')
83
76
    br_b2.fetch(br_b)
84
 
    self.assertTrue(has_revision(br_b2, revision_history(br_b)[4]))
85
 
    self.assertTrue(has_revision(br_b2, revision_history(br_a)[2]))
86
 
    self.assertFalse(has_revision(br_b2, revision_history(br_a)[3]))
 
77
    self.assertTrue(has_revision(br_b2, br_b.revision_history()[4]))
 
78
    self.assertTrue(has_revision(br_b2, br_a.revision_history()[2]))
 
79
    self.assertFalse(has_revision(br_b2, br_a.revision_history()[3]))
87
80
 
88
81
    br_a2 = self.make_branch('br_a2')
89
82
    br_a2.fetch(br_a)
90
 
    self.assertTrue(has_revision(br_a2, revision_history(br_b)[4]))
91
 
    self.assertTrue(has_revision(br_a2, revision_history(br_a)[3]))
92
 
    self.assertTrue(has_revision(br_a2, revision_history(br_a)[2]))
 
83
    self.assertTrue(has_revision(br_a2, br_b.revision_history()[4]))
 
84
    self.assertTrue(has_revision(br_a2, br_a.revision_history()[3]))
 
85
    self.assertTrue(has_revision(br_a2, br_a.revision_history()[2]))
93
86
 
94
87
    br_a3 = self.make_branch('br_a3')
95
88
    # pulling a branch with no revisions grabs nothing, regardless of
97
90
    br_a3.fetch(br_a2)
98
91
    for revno in range(4):
99
92
        self.assertFalse(
100
 
            br_a3.repository.has_revision(revision_history(br_a)[revno]))
101
 
    br_a3.fetch(br_a2, revision_history(br_a)[2])
 
93
            br_a3.repository.has_revision(br_a.revision_history()[revno]))
 
94
    br_a3.fetch(br_a2, br_a.revision_history()[2])
102
95
    # pull the 3 revisions introduced by a@u-0-3
103
 
    br_a3.fetch(br_a2, revision_history(br_a)[3])
 
96
    br_a3.fetch(br_a2, br_a.revision_history()[3])
104
97
    # NoSuchRevision should be raised if the branch is missing the revision
105
98
    # that was requested.
106
99
    self.assertRaises(errors.NoSuchRevision, br_a3.fetch, br_a2, 'pizza')
111
104
    # construct.  One way would be to uncommit and gc the revision, but not
112
105
    # every branch supports that.  -- mbp 20070814
113
106
 
114
 
    # TODO: test that fetch correctly does reweaving when needed. RBC 20051008
 
107
    #TODO: test that fetch correctly does reweaving when needed. RBC 20051008
115
108
    # Note that this means - updating the weave when ghosts are filled in to
116
109
    # add the right parents.
117
110
 
119
112
class TestFetch(TestCaseWithTransport):
120
113
 
121
114
    def test_fetch(self):
122
 
        # highest indices a: 5, b: 7
 
115
        #highest indices a: 5, b: 7
123
116
        br_a, br_b = make_branches(self, format='dirstate-tags')
124
117
        fetch_steps(self, br_a, br_b, br_a)
125
118
 
141
134
        # root revision to change for each commit, even though the content,
142
135
        # parent, name, and other attributes are unchanged.
143
136
        tree = self.make_branch_and_tree('tree', knit1_format)
144
 
        tree.set_root_id(b'tree-root')
145
 
        tree.commit('rev1', rev_id=b'rev1')
146
 
        tree.commit('rev2', rev_id=b'rev2')
 
137
        tree.set_root_id('tree-root')
 
138
        tree.commit('rev1', rev_id='rev1')
 
139
        tree.commit('rev2', rev_id='rev2')
147
140
 
148
141
        # Now we convert it to a knit2 repository so that it has a root knit
149
142
        Convert(tree.basedir, knit2_format)
150
143
        tree = WorkingTree.open(tree.basedir)
151
144
        branch = self.make_branch('branch', format=knit2_format)
152
 
        branch.pull(tree.branch, stop_revision=b'rev1')
 
145
        branch.pull(tree.branch, stop_revision='rev1')
153
146
        repo = branch.repository
154
147
        repo.lock_read()
155
148
        try:
156
149
            # Make sure fetch retrieved only what we requested
157
 
            self.assertEqual({(b'tree-root', b'rev1'): ()},
158
 
                             repo.texts.get_parent_map(
159
 
                [(b'tree-root', b'rev1'), (b'tree-root', b'rev2')]))
 
150
            self.assertEqual({('tree-root', 'rev1'):()},
 
151
                repo.texts.get_parent_map(
 
152
                    [('tree-root', 'rev1'), ('tree-root', 'rev2')]))
160
153
        finally:
161
154
            repo.unlock()
162
155
        branch.pull(tree.branch)
165
158
        repo.lock_read()
166
159
        try:
167
160
            # Make sure fetch retrieved only what we requested
168
 
            self.assertEqual({(b'tree-root', b'rev2'): ((b'tree-root', b'rev1'),)},
169
 
                             repo.texts.get_parent_map([(b'tree-root', b'rev2')]))
 
161
            self.assertEqual({('tree-root', 'rev2'):(('tree-root', 'rev1'),)},
 
162
                repo.texts.get_parent_map([('tree-root', 'rev2')]))
170
163
        finally:
171
164
            repo.unlock()
172
165
 
173
166
    def test_fetch_incompatible(self):
174
167
        knit_tree = self.make_branch_and_tree('knit', format='knit')
175
168
        knit3_tree = self.make_branch_and_tree('knit3',
176
 
                                               format='dirstate-with-subtree')
 
169
            format='dirstate-with-subtree')
177
170
        knit3_tree.commit('blah')
178
171
        e = self.assertRaises(errors.IncompatibleRepositories,
179
172
                              knit_tree.branch.fetch, knit3_tree.branch)
180
173
        self.assertContainsRe(str(e),
181
 
                              r"(?m).*/knit.*\nis not compatible with\n.*/knit3/.*\n"
182
 
                              r"different rich-root support")
 
174
            r"(?m).*/knit.*\nis not compatible with\n.*/knit3/.*\n"
 
175
            r"different rich-root support")
183
176
 
184
177
 
185
178
class TestMergeFetch(TestCaseWithTransport):
188
181
        """Merge brings across history from unrelated source"""
189
182
        wt1 = self.make_branch_and_tree('br1')
190
183
        br1 = wt1.branch
191
 
        wt1.commit(message='rev 1-1', rev_id=b'1-1')
192
 
        wt1.commit(message='rev 1-2', rev_id=b'1-2')
 
184
        wt1.commit(message='rev 1-1', rev_id='1-1')
 
185
        wt1.commit(message='rev 1-2', rev_id='1-2')
193
186
        wt2 = self.make_branch_and_tree('br2')
194
187
        br2 = wt2.branch
195
 
        wt2.commit(message='rev 2-1', rev_id=b'2-1')
196
 
        wt2.merge_from_branch(br1, from_revision=b'null:')
 
188
        wt2.commit(message='rev 2-1', rev_id='2-1')
 
189
        wt2.merge_from_branch(br1, from_revision='null:')
197
190
        self._check_revs_present(br2)
198
191
 
199
192
    def test_merge_fetches(self):
200
193
        """Merge brings across history from source"""
201
194
        wt1 = self.make_branch_and_tree('br1')
202
195
        br1 = wt1.branch
203
 
        wt1.commit(message='rev 1-1', rev_id=b'1-1')
204
 
        dir_2 = br1.controldir.sprout('br2')
 
196
        wt1.commit(message='rev 1-1', rev_id='1-1')
 
197
        dir_2 = br1.bzrdir.sprout('br2')
205
198
        br2 = dir_2.open_branch()
206
 
        wt1.commit(message='rev 1-2', rev_id=b'1-2')
 
199
        wt1.commit(message='rev 1-2', rev_id='1-2')
207
200
        wt2 = dir_2.open_workingtree()
208
 
        wt2.commit(message='rev 2-1', rev_id=b'2-1')
 
201
        wt2.commit(message='rev 2-1', rev_id='2-1')
209
202
        wt2.merge_from_branch(br1)
210
203
        self._check_revs_present(br2)
211
204
 
212
205
    def _check_revs_present(self, br2):
213
 
        for rev_id in [b'1-1', b'1-2', b'2-1']:
 
206
        for rev_id in '1-1', '1-2', '2-1':
214
207
            self.assertTrue(br2.repository.has_revision(rev_id))
215
208
            rev = br2.repository.get_revision(rev_id)
216
209
            self.assertEqual(rev.revision_id, rev_id)
223
216
        super(TestMergeFileHistory, self).setUp()
224
217
        wt1 = self.make_branch_and_tree('br1')
225
218
        br1 = wt1.branch
226
 
        self.build_tree_contents([('br1/file', b'original contents\n')])
227
 
        wt1.add('file', b'this-file-id')
228
 
        wt1.commit(message='rev 1-1', rev_id=b'1-1')
229
 
        dir_2 = br1.controldir.sprout('br2')
 
219
        self.build_tree_contents([('br1/file', 'original contents\n')])
 
220
        wt1.add('file', 'this-file-id')
 
221
        wt1.commit(message='rev 1-1', rev_id='1-1')
 
222
        dir_2 = br1.bzrdir.sprout('br2')
230
223
        br2 = dir_2.open_branch()
231
224
        wt2 = dir_2.open_workingtree()
232
 
        self.build_tree_contents([('br1/file', b'original from 1\n')])
233
 
        wt1.commit(message='rev 1-2', rev_id=b'1-2')
234
 
        self.build_tree_contents([('br1/file', b'agreement\n')])
235
 
        wt1.commit(message='rev 1-3', rev_id=b'1-3')
236
 
        self.build_tree_contents([('br2/file', b'contents in 2\n')])
237
 
        wt2.commit(message='rev 2-1', rev_id=b'2-1')
238
 
        self.build_tree_contents([('br2/file', b'agreement\n')])
239
 
        wt2.commit(message='rev 2-2', rev_id=b'2-2')
 
225
        self.build_tree_contents([('br1/file', 'original from 1\n')])
 
226
        wt1.commit(message='rev 1-2', rev_id='1-2')
 
227
        self.build_tree_contents([('br1/file', 'agreement\n')])
 
228
        wt1.commit(message='rev 1-3', rev_id='1-3')
 
229
        self.build_tree_contents([('br2/file', 'contents in 2\n')])
 
230
        wt2.commit(message='rev 2-1', rev_id='2-1')
 
231
        self.build_tree_contents([('br2/file', 'agreement\n')])
 
232
        wt2.commit(message='rev 2-2', rev_id='2-2')
240
233
 
241
234
    def test_merge_fetches_file_history(self):
242
235
        """Merge brings across file histories"""
245
238
        wt2 = WorkingTree.open('br2').merge_from_branch(br1)
246
239
        br2.lock_read()
247
240
        self.addCleanup(br2.unlock)
248
 
        for rev_id, text in [(b'1-2', b'original from 1\n'),
249
 
                             (b'1-3', b'agreement\n'),
250
 
                             (b'2-1', b'contents in 2\n'),
251
 
                             (b'2-2', b'agreement\n')]:
 
241
        for rev_id, text in [('1-2', 'original from 1\n'),
 
242
                             ('1-3', 'agreement\n'),
 
243
                             ('2-1', 'contents in 2\n'),
 
244
                             ('2-2', 'agreement\n')]:
252
245
            self.assertEqualDiff(
253
246
                br2.repository.revision_tree(
254
 
                    rev_id).get_file_text('file'), text)
 
247
                    rev_id).get_file_text('this-file-id'), text)
255
248
 
256
249
 
257
250
class TestKnitToPackFetch(TestCaseWithTransport):
275
268
        tree = self.make_branch_and_tree('source', format='dirstate')
276
269
        target = self.make_repository('target', format='pack-0.92')
277
270
        self.build_tree(['source/file'])
278
 
        tree.set_root_id(b'root-id')
279
 
        tree.add('file', b'file-id')
280
 
        tree.commit('one', rev_id=b'rev-one')
 
271
        tree.set_root_id('root-id')
 
272
        tree.add('file', 'file-id')
 
273
        tree.commit('one', rev_id='rev-one')
281
274
        source = tree.branch.repository
282
275
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
283
 
            source.texts)
 
276
                        source.texts)
284
277
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
285
 
            source.signatures)
 
278
                        source.signatures)
286
279
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
287
 
            source.revisions)
 
280
                        source.revisions)
288
281
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
289
 
            source.inventories)
 
282
                        source.inventories)
290
283
        # precondition
291
284
        self.assertTrue(target._format._fetch_uses_deltas)
292
 
        target.fetch(source, revision_id=b'rev-one')
293
 
        self.assertEqual(('get_record_stream', [(b'file-id', b'rev-one')],
 
285
        target.fetch(source, revision_id='rev-one')
 
286
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
294
287
                          target._format._fetch_order, False),
295
288
                         self.find_get_record_stream(source.texts.calls))
296
 
        self.assertEqual(('get_record_stream', [(b'rev-one',)],
297
 
                          target._format._fetch_order, False),
298
 
                         self.find_get_record_stream(source.inventories.calls, 2))
299
 
        self.assertEqual(('get_record_stream', [(b'rev-one',)],
 
289
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
290
          target._format._fetch_order, False),
 
291
          self.find_get_record_stream(source.inventories.calls, 2))
 
292
        self.assertEqual(('get_record_stream', [('rev-one',)],
300
293
                          target._format._fetch_order, False),
301
294
                         self.find_get_record_stream(source.revisions.calls))
302
295
        # XXX: Signatures is special, and slightly broken. The
307
300
        # So we know there will be extra calls, but the *last* one is the one
308
301
        # we care about.
309
302
        signature_calls = source.signatures.calls[-1:]
310
 
        self.assertEqual(('get_record_stream', [(b'rev-one',)],
 
303
        self.assertEqual(('get_record_stream', [('rev-one',)],
311
304
                          target._format._fetch_order, False),
312
305
                         self.find_get_record_stream(signature_calls))
313
306
 
315
308
        tree = self.make_branch_and_tree('source', format='dirstate')
316
309
        target = self.make_repository('target', format='pack-0.92')
317
310
        self.build_tree(['source/file'])
318
 
        tree.set_root_id(b'root-id')
319
 
        tree.add('file', b'file-id')
320
 
        tree.commit('one', rev_id=b'rev-one')
 
311
        tree.set_root_id('root-id')
 
312
        tree.add('file', 'file-id')
 
313
        tree.commit('one', rev_id='rev-one')
321
314
        source = tree.branch.repository
322
315
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
323
 
            source.texts)
 
316
                        source.texts)
324
317
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
325
 
            source.signatures)
 
318
                        source.signatures)
326
319
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
327
 
            source.revisions)
 
320
                        source.revisions)
328
321
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
329
 
            source.inventories)
 
322
                        source.inventories)
330
323
        # XXX: This won't work in general, but for the dirstate format it does.
331
324
        self.overrideAttr(target._format, '_fetch_uses_deltas', False)
332
 
        target.fetch(source, revision_id=b'rev-one')
333
 
        self.assertEqual(('get_record_stream', [(b'file-id', b'rev-one')],
 
325
        target.fetch(source, revision_id='rev-one')
 
326
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
334
327
                          target._format._fetch_order, True),
335
328
                         self.find_get_record_stream(source.texts.calls))
336
 
        self.assertEqual(('get_record_stream', [(b'rev-one',)],
337
 
                          target._format._fetch_order, True),
338
 
                         self.find_get_record_stream(source.inventories.calls, 2))
339
 
        self.assertEqual(('get_record_stream', [(b'rev-one',)],
 
329
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
330
            target._format._fetch_order, True),
 
331
            self.find_get_record_stream(source.inventories.calls, 2))
 
332
        self.assertEqual(('get_record_stream', [('rev-one',)],
340
333
                          target._format._fetch_order, True),
341
334
                         self.find_get_record_stream(source.revisions.calls))
342
335
        # XXX: Signatures is special, and slightly broken. The
347
340
        # So we know there will be extra calls, but the *last* one is the one
348
341
        # we care about.
349
342
        signature_calls = source.signatures.calls[-1:]
350
 
        self.assertEqual(('get_record_stream', [(b'rev-one',)],
 
343
        self.assertEqual(('get_record_stream', [('rev-one',)],
351
344
                          target._format._fetch_order, True),
352
345
                         self.find_get_record_stream(signature_calls))
353
346
 
360
353
        tree = self.make_branch_and_tree('source', format='dirstate')
361
354
        target = self.make_repository('target', format='pack-0.92')
362
355
        self.build_tree(['source/file'])
363
 
        tree.set_root_id(b'root-id')
364
 
        tree.add('file', b'file-id')
365
 
        tree.commit('one', rev_id=b'rev-one')
 
356
        tree.set_root_id('root-id')
 
357
        tree.add('file', 'file-id')
 
358
        tree.commit('one', rev_id='rev-one')
366
359
        # Hack the KVF for revisions so that it "accidentally" allows a delta
367
360
        tree.branch.repository.revisions._max_delta_chain = 200
368
 
        tree.commit('two', rev_id=b'rev-two')
 
361
        tree.commit('two', rev_id='rev-two')
369
362
        source = tree.branch.repository
370
363
        # Ensure that we stored a delta
371
364
        source.lock_read()
372
365
        self.addCleanup(source.unlock)
373
 
        record = next(source.revisions.get_record_stream([(b'rev-two',)],
374
 
                                                         'unordered', False))
 
366
        record = source.revisions.get_record_stream([('rev-two',)],
 
367
            'unordered', False).next()
375
368
        self.assertEqual('knit-delta-gz', record.storage_kind)
376
 
        target.fetch(tree.branch.repository, revision_id=b'rev-two')
 
369
        target.fetch(tree.branch.repository, revision_id='rev-two')
377
370
        # The record should get expanded back to a fulltext
378
371
        target.lock_read()
379
372
        self.addCleanup(target.unlock)
380
 
        record = next(target.revisions.get_record_stream([(b'rev-two',)],
381
 
                                                         'unordered', False))
 
373
        record = target.revisions.get_record_stream([('rev-two',)],
 
374
            'unordered', False).next()
382
375
        self.assertEqual('knit-ft-gz', record.storage_kind)
383
376
 
384
377
    def test_fetch_with_fallback_and_merge(self):
402
395
        # random ids because otherwise the inventory fulltext compresses too
403
396
        # well and the deltas get bigger.
404
397
        to_add = [
405
 
            ('add', ('', b'TREE_ROOT', 'directory', None))]
406
 
        for i in range(10):
 
398
            ('add', ('', 'TREE_ROOT', 'directory', None))]
 
399
        for i in xrange(10):
407
400
            fname = 'file%03d' % (i,)
408
 
            fileid = ('%s-%s' %
409
 
                      (fname, osutils.rand_chars(64))).encode('ascii')
410
 
            to_add.append(('add', (fname, fileid, 'file', b'content\n')))
411
 
        builder.build_snapshot(None, to_add, revision_id=b'A')
412
 
        builder.build_snapshot([b'A'], [], revision_id=b'B')
413
 
        builder.build_snapshot([b'A'], [], revision_id=b'C')
414
 
        builder.build_snapshot([b'C'], [], revision_id=b'D')
415
 
        builder.build_snapshot([b'D'], [], revision_id=b'E')
416
 
        builder.build_snapshot([b'E', b'B'], [], revision_id=b'F')
 
401
            fileid = '%s-%s' % (fname, osutils.rand_chars(64))
 
402
            to_add.append(('add', (fname, fileid, 'file', 'content\n')))
 
403
        builder.build_snapshot('A', None, to_add)
 
404
        builder.build_snapshot('B', ['A'], [])
 
405
        builder.build_snapshot('C', ['A'], [])
 
406
        builder.build_snapshot('D', ['C'], [])
 
407
        builder.build_snapshot('E', ['D'], [])
 
408
        builder.build_snapshot('F', ['E', 'B'], [])
417
409
        builder.finish_series()
418
410
        source_branch = builder.get_branch()
419
 
        source_branch.controldir.sprout('base', revision_id=b'B')
 
411
        source_branch.bzrdir.sprout('base', revision_id='B')
420
412
        target_branch = self.make_branch('target', format='1.6')
421
413
        target_branch.set_stacked_on_url('../base')
422
414
        source = source_branch.repository
423
415
        source.lock_read()
424
416
        self.addCleanup(source.unlock)
425
417
        source.inventories = versionedfile.OrderingVersionedFilesDecorator(
426
 
            source.inventories,
427
 
            key_priority={(b'E',): 1, (b'D',): 2, (b'C',): 4,
428
 
                          (b'F',): 3})
 
418
                        source.inventories,
 
419
                        key_priority={('E',): 1, ('D',): 2, ('C',): 4,
 
420
                                      ('F',): 3})
429
421
        # Ensure that the content is yielded in the proper order, and given as
430
422
        # the expected kinds
431
423
        records = [(record.key, record.storage_kind)
432
424
                   for record in source.inventories.get_record_stream(
433
 
            [(b'D',), (b'C',), (b'E',), (b'F',)], 'unordered', False)]
434
 
        self.assertEqual([((b'E',), 'knit-delta-gz'), ((b'D',), 'knit-delta-gz'),
435
 
                          ((b'F',), 'knit-delta-gz'), ((b'C',), 'knit-delta-gz')],
436
 
                         records)
 
425
                        [('D',), ('C',), ('E',), ('F',)], 'unordered', False)]
 
426
        self.assertEqual([(('E',), 'knit-delta-gz'), (('D',), 'knit-delta-gz'),
 
427
                          (('F',), 'knit-delta-gz'), (('C',), 'knit-delta-gz')],
 
428
                          records)
437
429
 
438
430
        target_branch.lock_write()
439
431
        self.addCleanup(target_branch.unlock)
440
432
        target = target_branch.repository
441
 
        target.fetch(source, revision_id=b'F')
 
433
        target.fetch(source, revision_id='F')
442
434
        # 'C' should be expanded to a fulltext, but D and E should still be
443
435
        # deltas
444
436
        stream = target.inventories.get_record_stream(
445
 
            [(b'C',), (b'D',), (b'E',), (b'F',)],
 
437
            [('C',), ('D',), ('E',), ('F',)],
446
438
            'unordered', False)
447
439
        kinds = dict((record.key, record.storage_kind) for record in stream)
448
 
        self.assertEqual({(b'C',): 'knit-ft-gz', (b'D',): 'knit-delta-gz',
449
 
                          (b'E',): 'knit-delta-gz', (b'F',): 'knit-delta-gz'},
 
440
        self.assertEqual({('C',): 'knit-ft-gz', ('D',): 'knit-delta-gz',
 
441
                          ('E',): 'knit-delta-gz', ('F',): 'knit-delta-gz'},
450
442
                         kinds)
451
443
 
452
444
 
472
464
 
473
465
    def test_fetch_order_AB(self):
474
466
        """See do_fetch_order_test"""
475
 
        self.do_fetch_order_test(b'A', b'B')
 
467
        self.do_fetch_order_test('A', 'B')
476
468
 
477
469
    def test_fetch_order_BA(self):
478
470
        """See do_fetch_order_test"""
479
 
        self.do_fetch_order_test(b'B', b'A')
 
471
        self.do_fetch_order_test('B', 'A')
480
472
 
481
473
    def get_parents(self, file_id, revision_id):
482
474
        self.repo.lock_read()
483
475
        try:
484
 
            parent_map = self.repo.texts.get_parent_map(
485
 
                [(file_id, revision_id)])
 
476
            parent_map = self.repo.texts.get_parent_map([(file_id, revision_id)])
486
477
            return parent_map[(file_id, revision_id)]
487
478
        finally:
488
479
            self.repo.unlock()
489
480
 
490
481
    def test_fetch_ghosts(self):
491
482
        self.make_tree_and_repo()
492
 
        self.tree.commit('first commit', rev_id=b'left-parent')
493
 
        self.tree.add_parent_tree_id(b'ghost-parent')
494
 
        fork = self.tree.controldir.sprout('fork', b'null:').open_workingtree()
495
 
        fork.commit('not a ghost', rev_id=b'not-ghost-parent')
 
483
        self.tree.commit('first commit', rev_id='left-parent')
 
484
        self.tree.add_parent_tree_id('ghost-parent')
 
485
        fork = self.tree.bzrdir.sprout('fork', 'null:').open_workingtree()
 
486
        fork.commit('not a ghost', rev_id='not-ghost-parent')
496
487
        self.tree.branch.repository.fetch(fork.branch.repository,
497
 
                                          b'not-ghost-parent')
498
 
        self.tree.add_parent_tree_id(b'not-ghost-parent')
499
 
        self.tree.commit('second commit', rev_id=b'second-id')
500
 
        self.repo.fetch(self.tree.branch.repository, b'second-id')
501
 
        root_id = self.tree.path2id('')
 
488
                                     'not-ghost-parent')
 
489
        self.tree.add_parent_tree_id('not-ghost-parent')
 
490
        self.tree.commit('second commit', rev_id='second-id')
 
491
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
492
        root_id = self.tree.get_root_id()
502
493
        self.assertEqual(
503
 
            ((root_id, b'left-parent'), (root_id, b'not-ghost-parent')),
504
 
            self.get_parents(root_id, b'second-id'))
 
494
            ((root_id, 'left-parent'), (root_id, 'not-ghost-parent')),
 
495
            self.get_parents(root_id, 'second-id'))
505
496
 
506
497
    def make_two_commits(self, change_root, fetch_twice):
507
498
        self.make_tree_and_repo()
508
 
        self.tree.commit('first commit', rev_id=b'first-id')
 
499
        self.tree.commit('first commit', rev_id='first-id')
509
500
        if change_root:
510
 
            self.tree.set_root_id(b'unique-id')
511
 
        self.tree.commit('second commit', rev_id=b'second-id')
 
501
            self.tree.set_root_id('unique-id')
 
502
        self.tree.commit('second commit', rev_id='second-id')
512
503
        if fetch_twice:
513
 
            self.repo.fetch(self.tree.branch.repository, b'first-id')
514
 
        self.repo.fetch(self.tree.branch.repository, b'second-id')
 
504
            self.repo.fetch(self.tree.branch.repository, 'first-id')
 
505
        self.repo.fetch(self.tree.branch.repository, 'second-id')
515
506
 
516
507
    def test_fetch_changed_root(self):
517
508
        self.make_two_commits(change_root=True, fetch_twice=False)
518
 
        self.assertEqual((), self.get_parents(b'unique-id', b'second-id'))
 
509
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
519
510
 
520
511
    def test_two_fetch_changed_root(self):
521
512
        self.make_two_commits(change_root=True, fetch_twice=True)
522
 
        self.assertEqual((), self.get_parents(b'unique-id', b'second-id'))
 
513
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
523
514
 
524
515
    def test_two_fetches(self):
525
516
        self.make_two_commits(change_root=False, fetch_twice=True)
526
 
        self.assertEqual(((b'TREE_ROOT', b'first-id'),),
527
 
                         self.get_parents(b'TREE_ROOT', b'second-id'))
 
517
        self.assertEqual((('TREE_ROOT', 'first-id'),),
 
518
            self.get_parents('TREE_ROOT', 'second-id'))