/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/per_interrepository/test_fetch.py

  • Committer: Jonathan Lange
  • Date: 2009-12-09 09:20:42 UTC
  • mfrom: (4881 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4907.
  • Revision ID: jml@canonical.com-20091209092042-s2zgqcf8f39yzxpj
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
import sys
19
19
 
20
 
import bzrlib
21
20
from bzrlib import (
22
21
    errors,
23
22
    inventory,
28
27
from bzrlib.errors import (
29
28
    NoSuchRevision,
30
29
    )
 
30
from bzrlib.graph import (
 
31
    SearchResult,
 
32
    )
31
33
from bzrlib.revision import (
32
34
    NULL_REVISION,
33
35
    Revision,
35
37
from bzrlib.tests import (
36
38
    TestNotApplicable,
37
39
    )
38
 
from bzrlib.tests.interrepository_implementations import (
 
40
from bzrlib.tests.per_interrepository import (
39
41
    TestCaseWithInterRepository,
40
42
    )
41
 
from bzrlib.tests.interrepository_implementations.test_interrepository import (
 
43
from bzrlib.tests.per_interrepository.test_interrepository import (
42
44
    check_repo_format_for_funky_id_on_win32
43
45
    )
44
46
 
45
47
 
 
48
 
46
49
class TestInterRepository(TestCaseWithInterRepository):
47
50
 
 
51
    def disable_commit_write_group_paranoia(self, repo):
 
52
        pack_coll = getattr(repo, '_pack_collection', None)
 
53
        if pack_coll is not None:
 
54
            # Monkey-patch the pack collection instance to allow storing
 
55
            # incomplete revisions.
 
56
            pack_coll._check_new_inventories = lambda: []
 
57
 
48
58
    def test_fetch(self):
49
59
        tree_a = self.make_branch_and_tree('a')
50
60
        self.build_tree(['a/foo'])
124
134
            to_repo.texts.get_record_stream([('foo', revid)],
125
135
            'unordered', True).next().get_bytes_as('fulltext'))
126
136
 
 
137
    def test_fetch_from_stacked_smart(self):
 
138
        self.setup_smart_server_with_call_log()
 
139
        self.test_fetch_from_stacked()
 
140
 
 
141
    def test_fetch_from_stacked_smart_old(self):
 
142
        self.setup_smart_server_with_call_log()
 
143
        self.disable_verb('Repository.get_stream_1.19')
 
144
        self.test_fetch_from_stacked()
 
145
 
 
146
    def test_fetch_from_stacked(self):
 
147
        """Fetch from a stacked branch succeeds."""
 
148
        if not self.repository_format.supports_external_lookups:
 
149
            raise TestNotApplicable("Need stacking support in the source.")
 
150
        builder = self.make_branch_builder('full-branch')
 
151
        builder.start_series()
 
152
        builder.build_snapshot('first', None, [
 
153
            ('add', ('', 'root-id', 'directory', '')),
 
154
            ('add', ('file', 'file-id', 'file', 'content\n'))])
 
155
        builder.build_snapshot('second', ['first'], [
 
156
            ('modify', ('file-id', 'second content\n'))])
 
157
        builder.build_snapshot('third', ['second'], [
 
158
            ('modify', ('file-id', 'third content\n'))])
 
159
        builder.finish_series()
 
160
        branch = builder.get_branch()
 
161
        repo = self.make_repository('stacking-base')
 
162
        trunk = repo.bzrdir.create_branch()
 
163
        trunk.repository.fetch(branch.repository, 'second')
 
164
        repo = self.make_repository('stacked')
 
165
        stacked_branch = repo.bzrdir.create_branch()
 
166
        stacked_branch.set_stacked_on_url(trunk.base)
 
167
        stacked_branch.repository.fetch(branch.repository, 'third')
 
168
        target = self.make_to_repository('target')
 
169
        target.fetch(stacked_branch.repository, 'third')
 
170
        target.lock_read()
 
171
        self.addCleanup(target.unlock)
 
172
        all_revs = set(['first', 'second', 'third'])
 
173
        self.assertEqual(all_revs, set(target.get_parent_map(all_revs)))
 
174
 
 
175
    def test_fetch_parent_inventories_at_stacking_boundary_smart(self):
 
176
        self.setup_smart_server_with_call_log()
 
177
        self.test_fetch_parent_inventories_at_stacking_boundary()
 
178
 
 
179
    def test_fetch_parent_inventories_at_stacking_boundary_smart_old(self):
 
180
        self.setup_smart_server_with_call_log()
 
181
        self.disable_verb('Repository.insert_stream_1.19')
 
182
        self.test_fetch_parent_inventories_at_stacking_boundary()
 
183
 
127
184
    def test_fetch_parent_inventories_at_stacking_boundary(self):
128
185
        """Fetch to a stacked branch copies inventories for parents of
129
186
        revisions at the stacking boundary.
132
189
        altered by all revisions it contains, which means that it needs both
133
190
        the inventory for any revision it has, and the inventories of all that
134
191
        revision's parents.
 
192
 
 
193
        However, we should also skip any revisions which are ghosts in the
 
194
        parents.
135
195
        """
136
 
        to_repo = self.make_to_repository('to')
137
 
        if not to_repo._format.supports_external_lookups:
 
196
        if not self.repository_format_to.supports_external_lookups:
138
197
            raise TestNotApplicable("Need stacking support in the target.")
139
198
        builder = self.make_branch_builder('branch')
140
199
        builder.start_series()
141
200
        builder.build_snapshot('base', None, [
142
 
            ('add', ('', 'root-id', 'directory', ''))])
143
 
        builder.build_snapshot('left', ['base'], [])
144
 
        builder.build_snapshot('right', ['base'], [])
145
 
        builder.build_snapshot('merge', ['left', 'right'], [])
 
201
            ('add', ('', 'root-id', 'directory', '')),
 
202
            ('add', ('file', 'file-id', 'file', 'content\n'))])
 
203
        builder.build_snapshot('left', ['base'], [
 
204
            ('modify', ('file-id', 'left content\n'))])
 
205
        builder.build_snapshot('right', ['base'], [
 
206
            ('modify', ('file-id', 'right content\n'))])
 
207
        builder.build_snapshot('merge', ['left', 'right'], [
 
208
            ('modify', ('file-id', 'left and right content\n'))])
146
209
        builder.finish_series()
147
210
        branch = builder.get_branch()
148
211
        repo = self.make_to_repository('trunk')
161
224
        self.assertEqual(
162
225
            set([('left',), ('right',), ('merge',)]),
163
226
            unstacked_repo.inventories.keys())
 
227
        # And the basis inventories have been copied correctly
 
228
        trunk.lock_read()
 
229
        self.addCleanup(trunk.unlock)
 
230
        left_tree, right_tree = trunk.repository.revision_trees(
 
231
            ['left', 'right'])
 
232
        stacked_branch.lock_read()
 
233
        self.addCleanup(stacked_branch.unlock)
 
234
        (stacked_left_tree,
 
235
         stacked_right_tree) = stacked_branch.repository.revision_trees(
 
236
            ['left', 'right'])
 
237
        self.assertEqual(left_tree.inventory, stacked_left_tree.inventory)
 
238
        self.assertEqual(right_tree.inventory, stacked_right_tree.inventory)
 
239
 
 
240
        # Finally, it's not enough to see that the basis inventories are
 
241
        # present.  The texts introduced in merge (and only those) should be
 
242
        # present, and also generating a stream should succeed without blowing
 
243
        # up.
 
244
        self.assertTrue(unstacked_repo.has_revision('merge'))
 
245
        expected_texts = set([('file-id', 'merge')])
 
246
        if stacked_branch.repository.texts.get_parent_map([('root-id',
 
247
            'merge')]):
 
248
            # If a (root-id,merge) text exists, it should be in the stacked
 
249
            # repo.
 
250
            expected_texts.add(('root-id', 'merge'))
 
251
        self.assertEqual(expected_texts, unstacked_repo.texts.keys())
 
252
        self.assertCanStreamRevision(unstacked_repo, 'merge')
 
253
 
 
254
    def assertCanStreamRevision(self, repo, revision_id):
 
255
        exclude_keys = set(repo.all_revision_ids()) - set([revision_id])
 
256
        search = SearchResult([revision_id], exclude_keys, 1, [revision_id])
 
257
        source = repo._get_source(repo._format)
 
258
        for substream_kind, substream in source.get_stream(search):
 
259
            # Consume the substream
 
260
            list(substream)
 
261
 
 
262
    def test_fetch_across_stacking_boundary_ignores_ghost(self):
 
263
        if not self.repository_format_to.supports_external_lookups:
 
264
            raise TestNotApplicable("Need stacking support in the target.")
 
265
        to_repo = self.make_to_repository('to')
 
266
        builder = self.make_branch_builder('branch')
 
267
        builder.start_series()
 
268
        builder.build_snapshot('base', None, [
 
269
            ('add', ('', 'root-id', 'directory', '')),
 
270
            ('add', ('file', 'file-id', 'file', 'content\n'))])
 
271
        builder.build_snapshot('second', ['base'], [
 
272
            ('modify', ('file-id', 'second content\n'))])
 
273
        builder.build_snapshot('third', ['second', 'ghost'], [
 
274
            ('modify', ('file-id', 'third content\n'))])
 
275
        builder.finish_series()
 
276
        branch = builder.get_branch()
 
277
        repo = self.make_to_repository('trunk')
 
278
        trunk = repo.bzrdir.create_branch()
 
279
        trunk.repository.fetch(branch.repository, 'second')
 
280
        repo = self.make_to_repository('stacked')
 
281
        stacked_branch = repo.bzrdir.create_branch()
 
282
        stacked_branch.set_stacked_on_url(trunk.base)
 
283
        stacked_branch.repository.fetch(branch.repository, 'third')
 
284
        unstacked_repo = stacked_branch.bzrdir.open_repository()
 
285
        unstacked_repo.lock_read()
 
286
        self.addCleanup(unstacked_repo.unlock)
 
287
        self.assertFalse(unstacked_repo.has_revision('second'))
 
288
        self.assertFalse(unstacked_repo.has_revision('ghost'))
 
289
        self.assertEqual(
 
290
            set([('second',), ('third',)]),
 
291
            unstacked_repo.inventories.keys())
 
292
        # And the basis inventories have been copied correctly
 
293
        trunk.lock_read()
 
294
        self.addCleanup(trunk.unlock)
 
295
        second_tree = trunk.repository.revision_tree('second')
 
296
        stacked_branch.lock_read()
 
297
        self.addCleanup(stacked_branch.unlock)
 
298
        stacked_second_tree = stacked_branch.repository.revision_tree('second')
 
299
        self.assertEqual(second_tree.inventory, stacked_second_tree.inventory)
 
300
        # Finally, it's not enough to see that the basis inventories are
 
301
        # present.  The texts introduced in merge (and only those) should be
 
302
        # present, and also generating a stream should succeed without blowing
 
303
        # up.
 
304
        self.assertTrue(unstacked_repo.has_revision('third'))
 
305
        expected_texts = set([('file-id', 'third')])
 
306
        if stacked_branch.repository.texts.get_parent_map([('root-id',
 
307
            'third')]):
 
308
            # If a (root-id,third) text exists, it should be in the stacked
 
309
            # repo.
 
310
            expected_texts.add(('root-id', 'third'))
 
311
        self.assertEqual(expected_texts, unstacked_repo.texts.keys())
 
312
        self.assertCanStreamRevision(unstacked_repo, 'third')
 
313
 
 
314
    def test_fetch_from_stacked_to_stacked_copies_parent_inventories(self):
 
315
        """Fetch from a stacked branch copies inventories for parents of
 
316
        revisions at the stacking boundary.
 
317
 
 
318
        Specifically, fetch will copy the parent inventories from the
 
319
        source for which the corresponding revisions are not present.  This
 
320
        will happen even when the source repository has no fallbacks configured
 
321
        (as is the case during upgrade).
 
322
        """
 
323
        if not self.repository_format.supports_external_lookups:
 
324
            raise TestNotApplicable("Need stacking support in the source.")
 
325
        if not self.repository_format_to.supports_external_lookups:
 
326
            raise TestNotApplicable("Need stacking support in the target.")
 
327
        builder = self.make_branch_builder('branch')
 
328
        builder.start_series()
 
329
        builder.build_snapshot('base', None, [
 
330
            ('add', ('', 'root-id', 'directory', '')),
 
331
            ('add', ('file', 'file-id', 'file', 'content\n'))])
 
332
        builder.build_snapshot('left', ['base'], [
 
333
            ('modify', ('file-id', 'left content\n'))])
 
334
        builder.build_snapshot('right', ['base'], [
 
335
            ('modify', ('file-id', 'right content\n'))])
 
336
        builder.build_snapshot('merge', ['left', 'right'], [
 
337
            ('modify', ('file-id', 'left and right content\n'))])
 
338
        builder.finish_series()
 
339
        branch = builder.get_branch()
 
340
        repo = self.make_repository('old-trunk')
 
341
        # Make a pair of equivalent trunk repos in the from and to formats.
 
342
        old_trunk = repo.bzrdir.create_branch()
 
343
        old_trunk.repository.fetch(branch.repository, 'left')
 
344
        old_trunk.repository.fetch(branch.repository, 'right')
 
345
        repo = self.make_to_repository('new-trunk')
 
346
        new_trunk = repo.bzrdir.create_branch()
 
347
        new_trunk.repository.fetch(branch.repository, 'left')
 
348
        new_trunk.repository.fetch(branch.repository, 'right')
 
349
        # Make the source; a repo stacked on old_trunk contained just the data
 
350
        # for 'merge'.
 
351
        repo = self.make_repository('old-stacked')
 
352
        old_stacked_branch = repo.bzrdir.create_branch()
 
353
        old_stacked_branch.set_stacked_on_url(old_trunk.base)
 
354
        old_stacked_branch.repository.fetch(branch.repository, 'merge')
 
355
        # Make the target, a repo stacked on new_trunk.
 
356
        repo = self.make_to_repository('new-stacked')
 
357
        new_stacked_branch = repo.bzrdir.create_branch()
 
358
        new_stacked_branch.set_stacked_on_url(new_trunk.base)
 
359
        old_unstacked_repo = old_stacked_branch.bzrdir.open_repository()
 
360
        new_unstacked_repo = new_stacked_branch.bzrdir.open_repository()
 
361
        # Reopen the source and target repos without any fallbacks, and fetch
 
362
        # 'merge'.
 
363
        new_unstacked_repo.fetch(old_unstacked_repo, 'merge')
 
364
        # Now check the results.  new_unstacked_repo should contain all the
 
365
        # data necessary to stream 'merge' (i.e. the parent inventories).
 
366
        new_unstacked_repo.lock_read()
 
367
        self.addCleanup(new_unstacked_repo.unlock)
 
368
        self.assertFalse(new_unstacked_repo.has_revision('left'))
 
369
        self.assertFalse(new_unstacked_repo.has_revision('right'))
 
370
        self.assertEqual(
 
371
            set([('left',), ('right',), ('merge',)]),
 
372
            new_unstacked_repo.inventories.keys())
 
373
        # And the basis inventories have been copied correctly
 
374
        new_trunk.lock_read()
 
375
        self.addCleanup(new_trunk.unlock)
 
376
        left_tree, right_tree = new_trunk.repository.revision_trees(
 
377
            ['left', 'right'])
 
378
        new_stacked_branch.lock_read()
 
379
        self.addCleanup(new_stacked_branch.unlock)
 
380
        (stacked_left_tree,
 
381
         stacked_right_tree) = new_stacked_branch.repository.revision_trees(
 
382
            ['left', 'right'])
 
383
        self.assertEqual(left_tree.inventory, stacked_left_tree.inventory)
 
384
        self.assertEqual(right_tree.inventory, stacked_right_tree.inventory)
 
385
        # Finally, it's not enough to see that the basis inventories are
 
386
        # present.  The texts introduced in merge (and only those) should be
 
387
        # present, and also generating a stream should succeed without blowing
 
388
        # up.
 
389
        self.assertTrue(new_unstacked_repo.has_revision('merge'))
 
390
        expected_texts = set([('file-id', 'merge')])
 
391
        if new_stacked_branch.repository.texts.get_parent_map([('root-id',
 
392
            'merge')]):
 
393
            # If a (root-id,merge) text exists, it should be in the stacked
 
394
            # repo.
 
395
            expected_texts.add(('root-id', 'merge'))
 
396
        self.assertEqual(expected_texts, new_unstacked_repo.texts.keys())
 
397
        self.assertCanStreamRevision(new_unstacked_repo, 'merge')
164
398
 
165
399
    def test_fetch_missing_basis_text(self):
166
400
        """If fetching a delta, we should die if a basis is not present."""
177
411
        to_repo.lock_write()
178
412
        try:
179
413
            to_repo.start_write_group()
180
 
            inv = tree.branch.repository.get_inventory('rev-one')
181
 
            to_repo.add_inventory('rev-one', inv, [])
182
 
            rev = tree.branch.repository.get_revision('rev-one')
183
 
            to_repo.add_revision('rev-one', rev, inv=inv)
184
 
            to_repo.commit_write_group()
 
414
            try:
 
415
                inv = tree.branch.repository.get_inventory('rev-one')
 
416
                to_repo.add_inventory('rev-one', inv, [])
 
417
                rev = tree.branch.repository.get_revision('rev-one')
 
418
                to_repo.add_revision('rev-one', rev, inv=inv)
 
419
                self.disable_commit_write_group_paranoia(to_repo)
 
420
                to_repo.commit_write_group()
 
421
            except:
 
422
                to_repo.abort_write_group(suppress_errors=True)
 
423
                raise
185
424
        finally:
186
425
            to_repo.unlock()
187
426
 
236
475
        source_tree.add(['id'], ['id'])
237
476
        source_tree.commit('a', rev_id='a')
238
477
        # now we manually insert a revision with an inventory referencing
239
 
        # 'id' at revision 'b', but we do not insert revision b.
 
478
        # file 'id' at revision 'b', but we do not insert revision b.
240
479
        # this should ensure that the new versions of files are being checked
241
480
        # for during pull operations
242
481
        inv = source.get_inventory('a')
254
493
                       revision_id='b')
255
494
        rev.parent_ids = ['a']
256
495
        source.add_revision('b', rev)
 
496
        self.disable_commit_write_group_paranoia(source)
257
497
        source.commit_write_group()
258
498
        self.assertRaises(errors.RevisionNotPresent, target.fetch, source)
259
499
        self.assertFalse(target.has_revision('b'))
276
516
        to_repo = self.make_to_repository('to')
277
517
        to_repo.fetch(from_tree.branch.repository)
278
518
        recorded_inv_sha1 = to_repo.get_inventory_sha1('foo-id')
279
 
        xml = to_repo.get_inventory_xml('foo-id')
280
 
        computed_inv_sha1 = osutils.sha_string(xml)
 
519
        to_repo.lock_read()
 
520
        self.addCleanup(to_repo.unlock)
 
521
        stream = to_repo.inventories.get_record_stream([('foo-id',)],
 
522
                                                       'unordered', True)
 
523
        bytes = stream.next().get_bytes_as('fulltext')
 
524
        computed_inv_sha1 = osutils.sha_string(bytes)
281
525
        self.assertEqual(computed_inv_sha1, recorded_inv_sha1)
282
526
 
283
527