/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: Andrew Bennetts
  • Date: 2008-09-08 12:59:00 UTC
  • mfrom: (3695 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3756.
  • Revision ID: andrew.bennetts@canonical.com-20080908125900-8ywtsr7jqyyatjz0
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    errors,
25
25
    merge,
26
26
    repository,
 
27
    versionedfile,
27
28
    )
28
29
from bzrlib.branch import Branch
29
30
from bzrlib.bzrdir import BzrDir
30
31
from bzrlib.repofmt import knitrepo
31
 
from bzrlib.symbol_versioning import (
32
 
    zero_ninetyone,
33
 
    )
34
32
from bzrlib.tests import TestCaseWithTransport
35
33
from bzrlib.tests.http_utils import TestCaseWithWebserver
36
34
from bzrlib.tests.test_revision import make_branches
149
147
        branch = self.make_branch('branch', format=knit2_format)
150
148
        branch.pull(tree.branch, stop_revision='rev1')
151
149
        repo = branch.repository
152
 
        root_knit = repo.weave_store.get_weave('tree-root',
153
 
                                                repo.get_transaction())
154
 
        # Make sure fetch retrieved only what we requested
155
 
        self.assertTrue('rev1' in root_knit)
156
 
        self.assertTrue('rev2' not in root_knit)
 
150
        repo.lock_read()
 
151
        try:
 
152
            # Make sure fetch retrieved only what we requested
 
153
            self.assertEqual({('tree-root', 'rev1'):()},
 
154
                repo.texts.get_parent_map(
 
155
                    [('tree-root', 'rev1'), ('tree-root', 'rev2')]))
 
156
        finally:
 
157
            repo.unlock()
157
158
        branch.pull(tree.branch)
158
 
        root_knit = repo.weave_store.get_weave('tree-root',
159
 
                                                repo.get_transaction())
160
159
        # Make sure that the next revision in the root knit was retrieved,
161
160
        # even though the text, name, parent_id, etc., were unchanged.
162
 
        self.assertTrue('rev2' in root_knit)
 
161
        repo.lock_read()
 
162
        try:
 
163
            # Make sure fetch retrieved only what we requested
 
164
            self.assertEqual({('tree-root', 'rev2'):(('tree-root', 'rev1'),)},
 
165
                repo.texts.get_parent_map([('tree-root', 'rev2')]))
 
166
        finally:
 
167
            repo.unlock()
163
168
 
164
169
    def test_fetch_incompatible(self):
165
170
        knit_tree = self.make_branch_and_tree('knit', format='knit')
166
171
        knit3_tree = self.make_branch_and_tree('knit3',
167
172
            format='dirstate-with-subtree')
168
173
        knit3_tree.commit('blah')
169
 
        self.assertRaises(errors.IncompatibleRepositories,
170
 
                          knit_tree.branch.fetch, knit3_tree.branch)
 
174
        e = self.assertRaises(errors.IncompatibleRepositories,
 
175
                              knit_tree.branch.fetch, knit3_tree.branch)
 
176
        self.assertContainsRe(str(e),
 
177
            r"(?m).*/knit.*\nis not compatible with\n.*/knit3/.*\n"
 
178
            r"different rich-root support")
171
179
 
172
180
 
173
181
class TestMergeFetch(TestCaseWithTransport):
285
293
        # unfortunately this log entry is branch format specific. We could 
286
294
        # factor out the 'what files does this format use' to a method on the 
287
295
        # repository, which would let us to this generically. RBC 20060419
 
296
        # RBC 20080408: Or perhaps we can assert that no files are fully read
 
297
        # twice?
288
298
        self.assertEqual(1, self._count_log_matches('/ce/id.kndx', http_logs))
289
299
        self.assertEqual(1, self._count_log_matches('/ce/id.knit', http_logs))
290
300
        self.assertEqual(1, self._count_log_matches('inventory.kndx', http_logs))
311
321
        self.log('\n'.join(http_logs))
312
322
        self.assertEqual(1, self._count_log_matches('branch-format', http_logs))
313
323
        self.assertEqual(1, self._count_log_matches('branch/format', http_logs))
314
 
        self.assertEqual(1, self._count_log_matches('repository/format', http_logs))
 
324
        self.assertEqual(1, self._count_log_matches('repository/format',
 
325
            http_logs))
315
326
        self.assertTrue(1 >= self._count_log_matches('revision-history',
316
327
                                                     http_logs))
317
328
        self.assertTrue(1 >= self._count_log_matches('last-revision',
318
329
                                                     http_logs))
319
330
        self.assertEqual(4, len(http_logs))
 
331
 
 
332
 
 
333
class TestKnitToPackFetch(TestCaseWithTransport):
 
334
 
 
335
    def find_get_record_stream(self, calls):
 
336
        """In a list of calls, find 'get_record_stream' calls.
 
337
 
 
338
        This also ensures that there is only one get_record_stream call.
 
339
        """
 
340
        get_record_call = None
 
341
        for call in calls:
 
342
            if call[0] == 'get_record_stream':
 
343
                self.assertIs(None, get_record_call,
 
344
                              "there should only be one call to"
 
345
                              " get_record_stream")
 
346
                get_record_call = call
 
347
        self.assertIsNot(None, get_record_call,
 
348
                         "there should be exactly one call to "
 
349
                         " get_record_stream")
 
350
        return get_record_call
 
351
 
 
352
    def test_fetch_with_deltas_no_delta_closure(self):
 
353
        tree = self.make_branch_and_tree('source', format='dirstate')
 
354
        target = self.make_repository('target', format='pack-0.92')
 
355
        self.build_tree(['source/file'])
 
356
        tree.set_root_id('root-id')
 
357
        tree.add('file', 'file-id')
 
358
        tree.commit('one', rev_id='rev-one')
 
359
        source = tree.branch.repository
 
360
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
 
361
                        source.texts)
 
362
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
 
363
                        source.signatures)
 
364
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
 
365
                        source.revisions)
 
366
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
 
367
                        source.inventories)
 
368
        # precondition
 
369
        self.assertTrue(target._fetch_uses_deltas)
 
370
        target.fetch(source, revision_id='rev-one')
 
371
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
 
372
                          target._fetch_order, False),
 
373
                         self.find_get_record_stream(source.texts.calls))
 
374
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
375
                          target._fetch_order, False),
 
376
                         self.find_get_record_stream(source.inventories.calls))
 
377
        # Because of bugs in the old fetch code, revisions could accidentally
 
378
        # have deltas present in knits. However, it was never intended, so we
 
379
        # always for include_delta_closure=True, to make sure we get fulltexts.
 
380
        # bug #261339
 
381
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
382
                          target._fetch_order, True),
 
383
                         self.find_get_record_stream(source.revisions.calls))
 
384
        # XXX: Signatures is special, and slightly broken. The
 
385
        # standard item_keys_introduced_by actually does a lookup for every
 
386
        # signature to see if it exists, rather than waiting to do them all at
 
387
        # once at the end. The fetch code then does an all-at-once and just
 
388
        # allows for some of them to be missing.
 
389
        # So we know there will be extra calls, but the *last* one is the one
 
390
        # we care about.
 
391
        signature_calls = source.signatures.calls[-1:]
 
392
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
393
                          target._fetch_order, True),
 
394
                         self.find_get_record_stream(signature_calls))
 
395
 
 
396
    def test_fetch_no_deltas_with_delta_closure(self):
 
397
        tree = self.make_branch_and_tree('source', format='dirstate')
 
398
        target = self.make_repository('target', format='pack-0.92')
 
399
        self.build_tree(['source/file'])
 
400
        tree.set_root_id('root-id')
 
401
        tree.add('file', 'file-id')
 
402
        tree.commit('one', rev_id='rev-one')
 
403
        source = tree.branch.repository
 
404
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
 
405
                        source.texts)
 
406
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
 
407
                        source.signatures)
 
408
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
 
409
                        source.revisions)
 
410
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
 
411
                        source.inventories)
 
412
        target._fetch_uses_deltas = False
 
413
        target.fetch(source, revision_id='rev-one')
 
414
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
 
415
                          target._fetch_order, True),
 
416
                         self.find_get_record_stream(source.texts.calls))
 
417
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
418
                          target._fetch_order, True),
 
419
                         self.find_get_record_stream(source.inventories.calls))
 
420
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
421
                          target._fetch_order, True),
 
422
                         self.find_get_record_stream(source.revisions.calls))
 
423
        # XXX: Signatures is special, and slightly broken. The
 
424
        # standard item_keys_introduced_by actually does a lookup for every
 
425
        # signature to see if it exists, rather than waiting to do them all at
 
426
        # once at the end. The fetch code then does an all-at-once and just
 
427
        # allows for some of them to be missing.
 
428
        # So we know there will be extra calls, but the *last* one is the one
 
429
        # we care about.
 
430
        signature_calls = source.signatures.calls[-1:]
 
431
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
432
                          target._fetch_order, True),
 
433
                         self.find_get_record_stream(signature_calls))
 
434
 
 
435
 
 
436
class Test1To2Fetch(TestCaseWithTransport):
 
437
    """Tests for Model1To2 failure modes"""
 
438
 
 
439
    def make_tree_and_repo(self):
 
440
        self.tree = self.make_branch_and_tree('tree', format='pack-0.92')
 
441
        self.repo = self.make_repository('rich-repo', format='rich-root-pack')
 
442
        self.repo.lock_write()
 
443
        self.addCleanup(self.repo.unlock)
 
444
 
 
445
    def do_fetch_order_test(self, first, second):
 
446
        """Test that fetch works no matter what the set order of revision is.
 
447
 
 
448
        This test depends on the order of items in a set, which is
 
449
        implementation-dependant, so we test A, B and then B, A.
 
450
        """
 
451
        self.make_tree_and_repo()
 
452
        self.tree.commit('Commit 1', rev_id=first)
 
453
        self.tree.commit('Commit 2', rev_id=second)
 
454
        self.repo.fetch(self.tree.branch.repository, second)
 
455
 
 
456
    def test_fetch_order_AB(self):
 
457
        """See do_fetch_order_test"""
 
458
        self.do_fetch_order_test('A', 'B')
 
459
 
 
460
    def test_fetch_order_BA(self):
 
461
        """See do_fetch_order_test"""
 
462
        self.do_fetch_order_test('B', 'A')
 
463
 
 
464
    def get_parents(self, file_id, revision_id):
 
465
        self.repo.lock_read()
 
466
        try:
 
467
            parent_map = self.repo.texts.get_parent_map([(file_id, revision_id)])
 
468
            return parent_map[(file_id, revision_id)]
 
469
        finally:
 
470
            self.repo.unlock()
 
471
 
 
472
    def test_fetch_ghosts(self):
 
473
        self.make_tree_and_repo()
 
474
        self.tree.commit('first commit', rev_id='left-parent')
 
475
        self.tree.add_parent_tree_id('ghost-parent')
 
476
        fork = self.tree.bzrdir.sprout('fork', 'null:').open_workingtree()
 
477
        fork.commit('not a ghost', rev_id='not-ghost-parent')
 
478
        self.tree.branch.repository.fetch(fork.branch.repository,
 
479
                                     'not-ghost-parent')
 
480
        self.tree.add_parent_tree_id('not-ghost-parent')
 
481
        self.tree.commit('second commit', rev_id='second-id')
 
482
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
483
        root_id = self.tree.get_root_id()
 
484
        self.assertEqual(
 
485
            ((root_id, 'left-parent'), (root_id, 'ghost-parent'),
 
486
             (root_id, 'not-ghost-parent')),
 
487
            self.get_parents(root_id, 'second-id'))
 
488
 
 
489
    def make_two_commits(self, change_root, fetch_twice):
 
490
        self.make_tree_and_repo()
 
491
        self.tree.commit('first commit', rev_id='first-id')
 
492
        if change_root:
 
493
            self.tree.set_root_id('unique-id')
 
494
        self.tree.commit('second commit', rev_id='second-id')
 
495
        if fetch_twice:
 
496
            self.repo.fetch(self.tree.branch.repository, 'first-id')
 
497
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
498
 
 
499
    def test_fetch_changed_root(self):
 
500
        self.make_two_commits(change_root=True, fetch_twice=False)
 
501
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
 
502
 
 
503
    def test_two_fetch_changed_root(self):
 
504
        self.make_two_commits(change_root=True, fetch_twice=True)
 
505
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
 
506
 
 
507
    def test_two_fetches(self):
 
508
        self.make_two_commits(change_root=False, fetch_twice=True)
 
509
        self.assertEqual((('TREE_ROOT', 'first-id'),),
 
510
            self.get_parents('TREE_ROOT', 'second-id'))