~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.

Show diffs side-by-side

added added

removed removed

Lines of Context:
167
167
                          control.transport.get,
168
168
                          'ancestry.weave')
169
169
 
170
 
    def test_exposed_versioned_files_are_marked_dirty(self):
171
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
172
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
173
 
        repo.lock_write()
174
 
        inv = repo.get_inventory_weave()
175
 
        repo.unlock()
176
 
        self.assertRaises(errors.OutSideTransaction,
177
 
            inv.add_lines, 'foo', [], [])
178
 
 
179
170
    def test_supports_external_lookups(self):
180
171
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
181
172
        repo = weaverepo.RepositoryFormat6().initialize(control)
205
196
                             'w\n'
206
197
                             'W\n',
207
198
                             t.get('inventory.weave').read())
 
199
        # Creating a file with id Foo:Bar results in a non-escaped file name on
 
200
        # disk.
 
201
        control.create_branch()
 
202
        tree = control.create_workingtree()
 
203
        tree.add(['foo'], ['Foo:Bar'], ['file'])
 
204
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
 
205
        tree.commit('first post', rev_id='first')
 
206
        self.assertEqualDiff(
 
207
            '# bzr weave file v5\n'
 
208
            'i\n'
 
209
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
 
210
            'n first\n'
 
211
            '\n'
 
212
            'w\n'
 
213
            '{ 0\n'
 
214
            '. content\n'
 
215
            '}\n'
 
216
            'W\n',
 
217
            t.get('weaves/74/Foo%3ABar.weave').read())
208
218
 
209
219
    def test_shared_disk_layout(self):
210
220
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
285
295
                             'W\n',
286
296
                             t.get('inventory.weave').read())
287
297
 
288
 
    def test_exposed_versioned_files_are_marked_dirty(self):
289
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
290
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
291
 
        repo.lock_write()
292
 
        inv = repo.get_inventory_weave()
293
 
        repo.unlock()
294
 
        self.assertRaises(errors.OutSideTransaction,
295
 
            inv.add_lines, 'foo', [], [])
296
 
 
297
298
    def test_supports_external_lookups(self):
298
299
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
299
300
        repo = weaverepo.RepositoryFormat7().initialize(control)
321
322
        # self.assertEqualDiff('', t.get('lock').read())
322
323
        self.assertTrue(S_ISDIR(t.stat('knits').st_mode))
323
324
        self.check_knits(t)
 
325
        # Check per-file knits.
 
326
        branch = control.create_branch()
 
327
        tree = control.create_workingtree()
 
328
        tree.add(['foo'], ['Nasty-IdC:'], ['file'])
 
329
        tree.put_file_bytes_non_atomic('Nasty-IdC:', '')
 
330
        tree.commit('1st post', rev_id='foo')
 
331
        self.assertHasKnit(t, 'knits/e8/%254easty-%2549d%2543%253a',
 
332
            '\nfoo fulltext 0 81  :')
324
333
 
325
 
    def assertHasKnit(self, t, knit_name):
 
334
    def assertHasKnit(self, t, knit_name, extra_content=''):
326
335
        """Assert that knit_name exists on t."""
327
 
        self.assertEqualDiff('# bzr knit index 8\n',
 
336
        self.assertEqualDiff('# bzr knit index 8\n' + extra_content,
328
337
                             t.get(knit_name + '.kndx').read())
329
 
        # no default content
330
 
        self.assertTrue(t.has(knit_name + '.knit'))
331
338
 
332
339
    def check_knits(self, t):
333
340
        """check knit content for a repository."""
377
384
        self.assertTrue(S_ISDIR(t.stat('knits').st_mode))
378
385
        self.check_knits(t)
379
386
 
380
 
    def test_exposed_versioned_files_are_marked_dirty(self):
381
 
        format = bzrdir.BzrDirMetaFormat1()
382
 
        format.repository_format = knitrepo.RepositoryFormatKnit1()
383
 
        repo = self.make_repository('.', format=format)
384
 
        repo.lock_write()
385
 
        inv = repo.get_inventory_weave()
386
 
        repo.unlock()
387
 
        self.assertRaises(errors.OutSideTransaction,
388
 
            inv.add_lines, 'foo', [], [])
389
 
 
390
387
    def test_deserialise_sets_root_revision(self):
391
388
        """We must have a inventory.root.revision
392
389
 
420
417
        self.assertFalse(repo._format.supports_external_lookups)
421
418
 
422
419
 
423
 
class KnitRepositoryStreamTests(test_knit.KnitTests):
424
 
    """Tests for knitrepo._get_stream_as_bytes."""
425
 
 
426
 
    def test_get_stream_as_bytes(self):
427
 
        # Make a simple knit
428
 
        k1 = self.make_test_knit()
429
 
        k1.add_lines('text-a', [], test_knit.split_lines(test_knit.TEXT_1))
430
 
        
431
 
        # Serialise it, check the output.
432
 
        bytes = knitrepo._get_stream_as_bytes(k1, ['text-a'])
433
 
        data = bencode.bdecode(bytes)
434
 
        format, record = data
435
 
        self.assertEqual('knit-plain', format)
436
 
        self.assertEqual(['text-a', ['fulltext'], []], record[:3])
437
 
        self.assertRecordContentEqual(k1, 'text-a', record[3])
438
 
 
439
 
    def test_get_stream_as_bytes_all(self):
440
 
        """Get a serialised data stream for all the records in a knit.
441
 
 
442
 
        Much like test_get_stream_all, except for get_stream_as_bytes.
443
 
        """
444
 
        k1 = self.make_test_knit()
445
 
        # Insert the same data as BasicKnitTests.test_knit_join, as they seem
446
 
        # to cover a range of cases (no parents, one parent, multiple parents).
447
 
        test_data = [
448
 
            ('text-a', [], test_knit.TEXT_1),
449
 
            ('text-b', ['text-a'], test_knit.TEXT_1),
450
 
            ('text-c', [], test_knit.TEXT_1),
451
 
            ('text-d', ['text-c'], test_knit.TEXT_1),
452
 
            ('text-m', ['text-b', 'text-d'], test_knit.TEXT_1),
453
 
           ]
454
 
        # This test is actually a bit strict as the order in which they're
455
 
        # returned is not defined.  This matches the current (deterministic)
456
 
        # behaviour.
457
 
        expected_data_list = [
458
 
            # version, options, parents
459
 
            ('text-a', ['fulltext'], []),
460
 
            ('text-b', ['line-delta'], ['text-a']),
461
 
            ('text-m', ['line-delta'], ['text-b', 'text-d']),
462
 
            ('text-c', ['fulltext'], []),
463
 
            ('text-d', ['line-delta'], ['text-c']),
464
 
            ]
465
 
        for version_id, parents, lines in test_data:
466
 
            k1.add_lines(version_id, parents, test_knit.split_lines(lines))
467
 
 
468
 
        bytes = knitrepo._get_stream_as_bytes(
469
 
            k1, ['text-a', 'text-b', 'text-m', 'text-c', 'text-d', ])
470
 
 
471
 
        data = bencode.bdecode(bytes)
472
 
        format = data.pop(0)
473
 
        self.assertEqual('knit-plain', format)
474
 
 
475
 
        for expected, actual in zip(expected_data_list, data):
476
 
            expected_version = expected[0]
477
 
            expected_options = expected[1]
478
 
            expected_parents = expected[2]
479
 
            version, options, parents, bytes = actual
480
 
            self.assertEqual(expected_version, version)
481
 
            self.assertEqual(expected_options, options)
482
 
            self.assertEqual(expected_parents, parents)
483
 
            self.assertRecordContentEqual(k1, version, bytes)
484
 
 
485
 
 
486
420
class DummyRepository(object):
487
421
    """A dummy repository for testing."""
488
422
 
593
527
                                                        repo_b).__class__)
594
528
 
595
529
 
596
 
class TestInterRemoteToOther(TestCaseWithTransport):
597
 
 
598
 
    def make_remote_repository(self, path, backing_format=None):
599
 
        """Make a RemoteRepository object backed by a real repository that will
600
 
        be created at the given path."""
601
 
        self.make_repository(path, format=backing_format)
602
 
        smart_server = server.SmartTCPServer_for_testing()
603
 
        smart_server.setUp()
604
 
        remote_transport = get_transport(smart_server.get_url()).clone(path)
605
 
        self.addCleanup(smart_server.tearDown)
606
 
        remote_bzrdir = bzrdir.BzrDir.open_from_transport(remote_transport)
607
 
        remote_repo = remote_bzrdir.open_repository()
608
 
        return remote_repo
609
 
 
610
 
    def test_is_compatible_same_format(self):
611
 
        """InterRemoteToOther is compatible with a remote repository and a
612
 
        second repository that have the same format."""
613
 
        local_repo = self.make_repository('local')
614
 
        remote_repo = self.make_remote_repository('remote')
615
 
        is_compatible = repository.InterRemoteToOther.is_compatible
616
 
        self.assertTrue(
617
 
            is_compatible(remote_repo, local_repo),
618
 
            "InterRemoteToOther(%r, %r) is false" % (remote_repo, local_repo))
619
 
          
620
 
    def test_is_incompatible_different_format(self):
621
 
        local_repo = self.make_repository('local', 'dirstate')
622
 
        remote_repo = self.make_remote_repository('a', 'dirstate-with-subtree')
623
 
        is_compatible = repository.InterRemoteToOther.is_compatible
624
 
        self.assertFalse(
625
 
            is_compatible(remote_repo, local_repo),
626
 
            "InterRemoteToOther(%r, %r) is true" % (local_repo, remote_repo))
627
 
 
628
 
    def test_is_incompatible_different_format_both_remote(self):
629
 
        remote_repo_a = self.make_remote_repository(
630
 
            'a', 'dirstate-with-subtree')
631
 
        remote_repo_b = self.make_remote_repository('b', 'dirstate')
632
 
        is_compatible = repository.InterRemoteToOther.is_compatible
633
 
        self.assertFalse(
634
 
            is_compatible(remote_repo_a, remote_repo_b),
635
 
            "InterRemoteToOther(%r, %r) is true"
636
 
            % (remote_repo_a, remote_repo_b))
637
 
 
638
 
 
639
530
class TestRepositoryConverter(TestCaseWithTransport):
640
531
 
641
532
    def test_convert_empty(self):
670
561
        tree = self.make_branch_and_tree('.', format)
671
562
        tree.commit("Dull commit", rev_id="dull")
672
563
        revision_tree = tree.branch.repository.revision_tree('dull')
673
 
        self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
674
 
            revision_tree.inventory.root.file_id)
 
564
        revision_tree.lock_read()
 
565
        try:
 
566
            self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
 
567
                revision_tree.inventory.root.file_id)
 
568
        finally:
 
569
            revision_tree.unlock()
675
570
        format = bzrdir.BzrDirMetaFormat1()
676
571
        format.repository_format = knitrepo.RepositoryFormatKnit3()
677
572
        upgrade.Convert('.', format)
678
573
        tree = workingtree.WorkingTree.open('.')
679
574
        revision_tree = tree.branch.repository.revision_tree('dull')
680
 
        revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
 
575
        revision_tree.lock_read()
 
576
        try:
 
577
            revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
 
578
        finally:
 
579
            revision_tree.unlock()
681
580
        tree.commit("Another dull commit", rev_id='dull2')
682
581
        revision_tree = tree.branch.repository.revision_tree('dull2')
 
582
        revision_tree.lock_read()
 
583
        self.addCleanup(revision_tree.unlock)
683
584
        self.assertEqual('dull', revision_tree.inventory.root.revision)
684
585
 
685
 
    def test_exposed_versioned_files_are_marked_dirty(self):
686
 
        format = bzrdir.BzrDirMetaFormat1()
687
 
        format.repository_format = knitrepo.RepositoryFormatKnit3()
688
 
        repo = self.make_repository('.', format=format)
689
 
        repo.lock_write()
690
 
        inv = repo.get_inventory_weave()
691
 
        repo.unlock()
692
 
        self.assertRaises(errors.OutSideTransaction,
693
 
            inv.add_lines, 'foo', [], [])
694
 
 
695
586
    def test_supports_external_lookups(self):
696
587
        format = bzrdir.BzrDirMetaFormat1()
697
588
        format.repository_format = knitrepo.RepositoryFormatKnit3()
769
660
        entry.revision = revision
770
661
        entry.text_size = 0
771
662
        inv.add(entry)
772
 
        vf = repo.weave_store.get_weave_or_empty(file_id,
773
 
                                                 repo.get_transaction())
774
 
        vf.add_lines(revision, parents, ['line\n'])
 
663
        text_key = (file_id, revision)
 
664
        parent_keys = [(file_id, parent) for parent in parents]
 
665
        repo.texts.add_lines(text_key, parent_keys, ['line\n'])
775
666
 
776
667
    def test_insert_from_broken_repo(self):
777
668
        """Inserting a data stream from a broken repository won't silently
779
670
        """
780
671
        broken_repo = self.make_broken_repository()
781
672
        empty_repo = self.make_repository('empty-repo')
782
 
        search = graph.SearchResult(set(['rev1a', 'rev2', 'rev3']),
783
 
            set(), 3, ['rev1a', 'rev2', 'rev3'])
784
 
        broken_repo.lock_read()
785
 
        self.addCleanup(broken_repo.unlock)
786
 
        stream = broken_repo.get_data_stream_for_search(search)
787
 
        empty_repo.lock_write()
788
 
        self.addCleanup(empty_repo.unlock)
789
 
        empty_repo.start_write_group()
790
 
        try:
791
 
            self.assertRaises(
792
 
                errors.KnitCorrupt, empty_repo.insert_data_stream, stream)
793
 
        finally:
794
 
            empty_repo.abort_write_group()
 
673
        self.assertRaises(errors.RevisionNotPresent, empty_repo.fetch, broken_repo)
795
674
 
796
675
 
797
676
class TestKnitPackNoSubtrees(TestCaseWithTransport):
816
695
            "Bazaar pack repository format 1 (needs bzr 0.92)\n",
817
696
                             t.get('format').read())
818
697
 
819
 
    def assertHasKndx(self, t, knit_name):
820
 
        """Assert that knit_name exists on t."""
821
 
        self.assertEqualDiff('# bzr knit index 8\n',
822
 
                             t.get(knit_name + '.kndx').read())
823
 
 
824
698
    def assertHasNoKndx(self, t, knit_name):
825
699
        """Assert that knit_name has no index on t."""
826
700
        self.assertFalse(t.has(knit_name + '.kndx'))
990
864
 
991
865
    def _add_text(self, repo, fileid):
992
866
        """Add a text to the repository within a write group."""
993
 
        vf =repo.weave_store.get_weave(fileid, repo.get_transaction())
994
 
        vf.add_lines('samplerev+' + fileid, [], [])
 
867
        repo.texts.add_lines((fileid, 'samplerev+'+fileid), [], [])
995
868
 
996
869
    def test_concurrent_writers_merge_new_packs(self):
997
870
        format = self.get_format()
1168
1041
            inv.root.revision = revision_id
1169
1042
            root_id = inv.root.file_id
1170
1043
            sha1 = repo.add_inventory(revision_id, inv, [])
1171
 
            vf = repo.weave_store.get_weave_or_empty(root_id,
1172
 
                repo.get_transaction())
1173
 
            vf.add_lines(revision_id, [], [])
 
1044
            repo.texts.add_lines((root_id, revision_id), [], [])
1174
1045
            rev = bzrlib.revision.Revision(timestamp=0,
1175
1046
                                           timezone=None,
1176
1047
                                           committer="Foo Bar <foo@example.com>",
1191
1062
        inv = missing_ghost.get_inventory('tip')
1192
1063
        self.assertRaises(errors.NoSuchRevision,
1193
1064
            missing_ghost.get_revision, 'ghost')
1194
 
        self.assertRaises(errors.RevisionNotPresent,
 
1065
        self.assertRaises(errors.NoSuchRevision,
1195
1066
            missing_ghost.get_inventory, 'ghost')
1196
1067
 
1197
1068
    def test_supports_external_lookups(self):