/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 breezy/tests/test_knit.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-30 22:17:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6642.
  • Revision ID: jelmer@jelmer.uk-20170530221731-k3djl8mbldt2gmoi
Fix doc generation with sphinx.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
16
16
 
17
17
"""Tests for Knit data structure"""
18
18
 
19
 
from cStringIO import StringIO
20
 
import difflib
21
19
import gzip
22
20
import sys
23
21
 
24
 
from bzrlib import (
 
22
from .. import (
25
23
    errors,
26
 
    generate_ids,
27
24
    knit,
28
25
    multiparent,
29
26
    osutils,
30
27
    pack,
31
28
    tests,
 
29
    transport,
32
30
    )
33
 
from bzrlib.errors import (
34
 
    RevisionAlreadyPresent,
 
31
from ..errors import (
35
32
    KnitHeaderError,
36
 
    RevisionNotPresent,
37
33
    NoSuchFile,
38
34
    )
39
 
from bzrlib.index import *
40
 
from bzrlib.knit import (
 
35
from ..index import *
 
36
from ..knit import (
41
37
    AnnotatedKnitContent,
42
38
    KnitContent,
43
 
    KnitSequenceMatcher,
44
39
    KnitVersionedFiles,
45
40
    PlainKnitContent,
46
41
    _VFContentMapGenerator,
47
 
    _DirectPackAccess,
48
42
    _KndxIndex,
49
43
    _KnitGraphIndex,
50
44
    _KnitKeyAccess,
51
45
    make_file_factory,
52
46
    )
53
 
from bzrlib.repofmt import pack_repo
54
 
from bzrlib.tests import (
55
 
    Feature,
56
 
    KnownFailure,
 
47
from ..patiencediff import PatienceSequenceMatcher
 
48
from ..repofmt import (
 
49
    knitpack_repo,
 
50
    pack_repo,
 
51
    )
 
52
from ..sixish import (
 
53
    BytesIO,
 
54
    )
 
55
from . import (
57
56
    TestCase,
58
57
    TestCaseWithMemoryTransport,
59
58
    TestCaseWithTransport,
60
59
    TestNotApplicable,
61
60
    )
62
 
from bzrlib.transport import get_transport
63
 
from bzrlib.transport.memory import MemoryTransport
64
 
from bzrlib.tuned_gzip import GzipFile
65
 
from bzrlib.versionedfile import (
 
61
from ..versionedfile import (
66
62
    AbsentContentFactory,
67
63
    ConstantMapper,
68
64
    network_bytes_to_kind_and_offset,
69
65
    RecordingVersionedFilesDecorator,
70
66
    )
71
 
 
72
 
 
73
 
compiled_knit_feature = tests.ModuleAvailableFeature(
74
 
                            'bzrlib._knit_load_data_pyx')
 
67
from . import (
 
68
    features,
 
69
    )
 
70
 
 
71
 
 
72
compiled_knit_feature = features.ModuleAvailableFeature(
 
73
    'breezy._knit_load_data_pyx')
75
74
 
76
75
 
77
76
class KnitContentTestsMixin(object):
106
105
        line_delta = source_content.line_delta(target_content)
107
106
        delta_blocks = list(KnitContent.get_line_delta_blocks(line_delta,
108
107
            source_lines, target_lines))
109
 
        matcher = KnitSequenceMatcher(None, source_lines, target_lines)
110
 
        matcher_blocks = list(list(matcher.get_matching_blocks()))
 
108
        matcher = PatienceSequenceMatcher(None, source_lines, target_lines)
 
109
        matcher_blocks = list(matcher.get_matching_blocks())
111
110
        self.assertEqual(matcher_blocks, delta_blocks)
112
111
 
113
112
    def test_get_line_delta_blocks(self):
206
205
        content1 = self._make_content([("", "a"), ("", "b")])
207
206
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
208
207
        it = content1.line_delta_iter(content2)
209
 
        self.assertEqual(it.next(), (1, 2, 2, ["a", "c"]))
210
 
        self.assertRaises(StopIteration, it.next)
 
208
        self.assertEqual(next(it), (1, 2, 2, ["a", "c"]))
 
209
        self.assertRaises(StopIteration, next, it)
211
210
 
212
211
 
213
212
class TestAnnotatedKnitContent(TestCase, KnitContentTestsMixin):
233
232
        content1 = self._make_content([("", "a"), ("", "b")])
234
233
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
235
234
        it = content1.line_delta_iter(content2)
236
 
        self.assertEqual(it.next(), (1, 2, 2, [("", "a"), ("", "c")]))
237
 
        self.assertRaises(StopIteration, it.next)
 
235
        self.assertEqual(next(it), (1, 2, 2, [("", "a"), ("", "c")]))
 
236
        self.assertRaises(StopIteration, next, it)
238
237
 
239
238
 
240
239
class MockTransport(object):
249
248
        if self.file_lines is None:
250
249
            raise NoSuchFile(filename)
251
250
        else:
252
 
            return StringIO("\n".join(self.file_lines))
 
251
            return BytesIO(b"\n".join(self.file_lines))
253
252
 
254
253
    def readv(self, relpath, offsets):
255
254
        fp = self.get(relpath)
333
332
            transport.append_bytes(packname, bytes)
334
333
        writer = pack.ContainerWriter(write_data)
335
334
        writer.begin()
336
 
        access = _DirectPackAccess({})
 
335
        access = pack_repo._DirectPackAccess({})
337
336
        access.set_writer(writer, index, (transport, packname))
338
337
        return access, writer
339
338
 
346
345
        writer.end()
347
346
        return memos
348
347
 
 
348
    def test_pack_collection_pack_retries(self):
 
349
        """An explicit pack of a pack collection succeeds even when a
 
350
        concurrent pack happens.
 
351
        """
 
352
        builder = self.make_branch_builder('.')
 
353
        builder.start_series()
 
354
        builder.build_snapshot('rev-1', None, [
 
355
            ('add', ('', 'root-id', 'directory', None)),
 
356
            ('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
 
357
            ])
 
358
        builder.build_snapshot('rev-2', ['rev-1'], [
 
359
            ('modify', ('file-id', 'content\nrev 2\n')),
 
360
            ])
 
361
        builder.build_snapshot('rev-3', ['rev-2'], [
 
362
            ('modify', ('file-id', 'content\nrev 3\n')),
 
363
            ])
 
364
        self.addCleanup(builder.finish_series)
 
365
        b = builder.get_branch()
 
366
        self.addCleanup(b.lock_write().unlock)
 
367
        repo = b.repository
 
368
        collection = repo._pack_collection
 
369
        # Concurrently repack the repo.
 
370
        reopened_repo = repo.bzrdir.open_repository()
 
371
        reopened_repo.pack()
 
372
        # Pack the new pack.
 
373
        collection.pack()
 
374
 
349
375
    def make_vf_for_retrying(self):
350
376
        """Create 3 packs and a reload function.
351
377
 
378
404
        collection = repo._pack_collection
379
405
        collection.ensure_loaded()
380
406
        orig_packs = collection.packs
381
 
        packer = pack_repo.Packer(collection, orig_packs, '.testpack')
 
407
        packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
382
408
        new_pack = packer.pack()
383
409
        # forget about the new pack
384
410
        collection.reset()
420
446
        # populated
421
447
        try:
422
448
            raise _TestException('foobar')
423
 
        except _TestException, e:
 
449
        except _TestException as e:
424
450
            retry_exc = errors.RetryWithNewPacks(None, reload_occurred=False,
425
451
                                                 exc_info=sys.exc_info())
 
452
        # GZ 2010-08-10: Cycle with exc_info affects 3 tests
426
453
        return retry_exc
427
454
 
428
455
    def test_read_from_several_packs(self):
437
464
        memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
438
465
        writer.end()
439
466
        transport = self.get_transport()
440
 
        access = _DirectPackAccess({"FOO":(transport, 'packfile'),
 
467
        access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
441
468
            "FOOBAR":(transport, 'pack2'),
442
469
            "BAZ":(transport, 'pack3')})
443
470
        self.assertEqual(['1234567890', '12345', 'alpha'],
453
480
 
454
481
    def test_set_writer(self):
455
482
        """The writer should be settable post construction."""
456
 
        access = _DirectPackAccess({})
 
483
        access = pack_repo._DirectPackAccess({})
457
484
        transport = self.get_transport()
458
485
        packname = 'packfile'
459
486
        index = 'foo'
471
498
        transport = self.get_transport()
472
499
        reload_called, reload_func = self.make_reload_func()
473
500
        # Note that the index key has changed from 'foo' to 'bar'
474
 
        access = _DirectPackAccess({'bar':(transport, 'packname')},
 
501
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
475
502
                                   reload_func=reload_func)
476
503
        e = self.assertListRaises(errors.RetryWithNewPacks,
477
504
                                  access.get_raw_records, memos)
486
513
        memos = self.make_pack_file()
487
514
        transport = self.get_transport()
488
515
        # Note that the index key has changed from 'foo' to 'bar'
489
 
        access = _DirectPackAccess({'bar':(transport, 'packname')})
 
516
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
490
517
        e = self.assertListRaises(KeyError, access.get_raw_records, memos)
491
518
 
492
519
    def test_missing_file_raises_retry(self):
494
521
        transport = self.get_transport()
495
522
        reload_called, reload_func = self.make_reload_func()
496
523
        # Note that the 'filename' has been changed to 'different-packname'
497
 
        access = _DirectPackAccess({'foo':(transport, 'different-packname')},
498
 
                                   reload_func=reload_func)
 
524
        access = pack_repo._DirectPackAccess(
 
525
            {'foo':(transport, 'different-packname')},
 
526
            reload_func=reload_func)
499
527
        e = self.assertListRaises(errors.RetryWithNewPacks,
500
528
                                  access.get_raw_records, memos)
501
529
        # The file has gone missing, so we assume we need to reload
509
537
        memos = self.make_pack_file()
510
538
        transport = self.get_transport()
511
539
        # Note that the 'filename' has been changed to 'different-packname'
512
 
        access = _DirectPackAccess({'foo':(transport, 'different-packname')})
 
540
        access = pack_repo._DirectPackAccess(
 
541
            {'foo': (transport, 'different-packname')})
513
542
        e = self.assertListRaises(errors.NoSuchFile,
514
543
                                  access.get_raw_records, memos)
515
544
 
519
548
        failing_transport = MockReadvFailingTransport(
520
549
                                [transport.get_bytes('packname')])
521
550
        reload_called, reload_func = self.make_reload_func()
522
 
        access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
523
 
                                   reload_func=reload_func)
 
551
        access = pack_repo._DirectPackAccess(
 
552
            {'foo': (failing_transport, 'packname')},
 
553
            reload_func=reload_func)
524
554
        # Asking for a single record will not trigger the Mock failure
525
555
        self.assertEqual(['1234567890'],
526
556
            list(access.get_raw_records(memos[:1])))
542
572
        failing_transport = MockReadvFailingTransport(
543
573
                                [transport.get_bytes('packname')])
544
574
        reload_called, reload_func = self.make_reload_func()
545
 
        access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
 
575
        access = pack_repo._DirectPackAccess(
 
576
            {'foo':(failing_transport, 'packname')})
546
577
        # Asking for a single record will not trigger the Mock failure
547
578
        self.assertEqual(['1234567890'],
548
579
            list(access.get_raw_records(memos[:1])))
553
584
                                  access.get_raw_records, memos)
554
585
 
555
586
    def test_reload_or_raise_no_reload(self):
556
 
        access = _DirectPackAccess({}, reload_func=None)
 
587
        access = pack_repo._DirectPackAccess({}, reload_func=None)
557
588
        retry_exc = self.make_retry_exception()
558
589
        # Without a reload_func, we will just re-raise the original exception
559
590
        self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
560
591
 
561
592
    def test_reload_or_raise_reload_changed(self):
562
593
        reload_called, reload_func = self.make_reload_func(return_val=True)
563
 
        access = _DirectPackAccess({}, reload_func=reload_func)
 
594
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
564
595
        retry_exc = self.make_retry_exception()
565
596
        access.reload_or_raise(retry_exc)
566
597
        self.assertEqual([1], reload_called)
570
601
 
571
602
    def test_reload_or_raise_reload_no_change(self):
572
603
        reload_called, reload_func = self.make_reload_func(return_val=False)
573
 
        access = _DirectPackAccess({}, reload_func=reload_func)
 
604
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
574
605
        retry_exc = self.make_retry_exception()
575
606
        # If reload_occurred is False, then we consider it an error to have
576
607
        # reload_func() return False (no changes).
617
648
        vf, reload_counter = self.make_vf_for_retrying()
618
649
        keys = [('rev-1',), ('rev-2',), ('rev-3',)]
619
650
        record_stream = vf.get_record_stream(keys, 'topological', False)
620
 
        record = record_stream.next()
 
651
        record = next(record_stream)
621
652
        self.assertEqual(('rev-1',), record.key)
622
653
        self.assertEqual([0, 0, 0], reload_counter)
623
 
        record = record_stream.next()
 
654
        record = next(record_stream)
624
655
        self.assertEqual(('rev-2',), record.key)
625
656
        self.assertEqual([1, 1, 0], reload_counter)
626
 
        record = record_stream.next()
 
657
        record = next(record_stream)
627
658
        self.assertEqual(('rev-3',), record.key)
628
659
        self.assertEqual([1, 1, 0], reload_counter)
629
660
        # Now delete all pack files, and see that we raise the right error
699
730
class LowLevelKnitDataTests(TestCase):
700
731
 
701
732
    def create_gz_content(self, text):
702
 
        sio = StringIO()
 
733
        sio = BytesIO()
703
734
        gz_file = gzip.GzipFile(mode='wb', fileobj=sio)
704
735
        gz_file.write(text)
705
736
        gz_file.close()
707
738
 
708
739
    def make_multiple_records(self):
709
740
        """Create the content for multiple records."""
710
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
741
        sha1sum = osutils.sha_string('foo\nbar\n')
711
742
        total_txt = []
712
743
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
713
744
                                        'foo\n'
716
747
                                        % (sha1sum,))
717
748
        record_1 = (0, len(gz_txt), sha1sum)
718
749
        total_txt.append(gz_txt)
719
 
        sha1sum = osutils.sha('baz\n').hexdigest()
 
750
        sha1sum = osutils.sha_string('baz\n')
720
751
        gz_txt = self.create_gz_content('version rev-id-2 1 %s\n'
721
752
                                        'baz\n'
722
753
                                        'end rev-id-2\n'
726
757
        return total_txt, record_1, record_2
727
758
 
728
759
    def test_valid_knit_data(self):
729
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
760
        sha1sum = osutils.sha_string('foo\nbar\n')
730
761
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
731
762
                                        'foo\n'
732
763
                                        'bar\n'
763
794
                         raw_contents)
764
795
 
765
796
    def test_not_enough_lines(self):
766
 
        sha1sum = osutils.sha('foo\n').hexdigest()
 
797
        sha1sum = osutils.sha_string('foo\n')
767
798
        # record says 2 lines data says 1
768
799
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
769
800
                                        'foo\n'
781
812
        self.assertEqual([(('rev-id-1',),  gz_txt, sha1sum)], raw_contents)
782
813
 
783
814
    def test_too_many_lines(self):
784
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
815
        sha1sum = osutils.sha_string('foo\nbar\n')
785
816
        # record says 1 lines data says 2
786
817
        gz_txt = self.create_gz_content('version rev-id-1 1 %s\n'
787
818
                                        'foo\n'
800
831
        self.assertEqual([(('rev-id-1',), gz_txt, sha1sum)], raw_contents)
801
832
 
802
833
    def test_mismatched_version_id(self):
803
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
834
        sha1sum = osutils.sha_string('foo\nbar\n')
804
835
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
805
836
                                        'foo\n'
806
837
                                        'bar\n'
819
850
            knit._read_records_iter_raw(records))
820
851
 
821
852
    def test_uncompressed_data(self):
822
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
853
        sha1sum = osutils.sha_string('foo\nbar\n')
823
854
        txt = ('version rev-id-1 2 %s\n'
824
855
               'foo\n'
825
856
               'bar\n'
839
870
            knit._read_records_iter_raw(records))
840
871
 
841
872
    def test_corrupted_data(self):
842
 
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
873
        sha1sum = osutils.sha_string('foo\nbar\n')
843
874
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
844
875
                                        'foo\n'
845
876
                                        'bar\n'
862
893
 
863
894
    def get_knit_index(self, transport, name, mode):
864
895
        mapper = ConstantMapper(name)
865
 
        from bzrlib._knit_load_data_py import _load_data_py
 
896
        from breezy._knit_load_data_py import _load_data_py
866
897
        self.overrideAttr(knit, '_load_data', _load_data_py)
867
898
        allow_writes = lambda: 'w' in mode
868
899
        return _KndxIndex(transport, mapper, lambda:None, allow_writes, lambda:True)
872
903
        index = self.get_knit_index(transport, "filename", "w")
873
904
        index.keys()
874
905
        call = transport.calls.pop(0)
875
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
906
        # call[1][1] is a BytesIO - we can't test it by simple equality.
876
907
        self.assertEqual('put_file_non_atomic', call[0])
877
908
        self.assertEqual('filename.kndx', call[1][0])
878
909
        # With no history, _KndxIndex writes a new index:
914
945
            ])
915
946
        index = self.get_knit_index(transport, "filename", "r")
916
947
        self.assertEqual(1, len(index.keys()))
917
 
        self.assertEqual(set([("version",)]), index.keys())
 
948
        self.assertEqual({("version",)}, index.keys())
918
949
 
919
950
    def test_read_corrupted_header(self):
920
951
        transport = MockTransport(['not a bzr knit index header\n'])
960
991
        index.add_records([
961
992
            ((utf8_revision_id,), ["option"], ((utf8_revision_id,), 0, 1), [])])
962
993
        call = transport.calls.pop(0)
963
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
994
        # call[1][1] is a BytesIO - we can't test it by simple equality.
964
995
        self.assertEqual('put_file_non_atomic', call[0])
965
996
        self.assertEqual('filename.kndx', call[1][0])
966
997
        # With no history, _KndxIndex writes a new index:
979
1010
        index.add_records([
980
1011
            (("version",), ["option"], (("version",), 0, 1), [(utf8_revision_id,)])])
981
1012
        call = transport.calls.pop(0)
982
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1013
        # call[1][1] is a BytesIO - we can't test it by simple equality.
983
1014
        self.assertEqual('put_file_non_atomic', call[0])
984
1015
        self.assertEqual('filename.kndx', call[1][0])
985
1016
        # With no history, _KndxIndex writes a new index:
997
1028
        self.assertEqual(set(), index.keys())
998
1029
 
999
1030
        index.add_records([(("a",), ["option"], (("a",), 0, 1), [])])
1000
 
        self.assertEqual(set([("a",)]), index.keys())
 
1031
        self.assertEqual({("a",)}, index.keys())
1001
1032
 
1002
1033
        index.add_records([(("a",), ["option"], (("a",), 0, 1), [])])
1003
 
        self.assertEqual(set([("a",)]), index.keys())
 
1034
        self.assertEqual({("a",)}, index.keys())
1004
1035
 
1005
1036
        index.add_records([(("b",), ["option"], (("b",), 0, 1), [])])
1006
 
        self.assertEqual(set([("a",), ("b",)]), index.keys())
 
1037
        self.assertEqual({("a",), ("b",)}, index.keys())
1007
1038
 
1008
1039
    def add_a_b(self, index, random_id=None):
1009
1040
        kwargs = {}
1033
1064
 
1034
1065
        self.add_a_b(index)
1035
1066
        call = transport.calls.pop(0)
1036
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1067
        # call[1][1] is a BytesIO - we can't test it by simple equality.
1037
1068
        self.assertEqual('put_file_non_atomic', call[0])
1038
1069
        self.assertEqual('filename.kndx', call[1][0])
1039
1070
        # With no history, _KndxIndex writes a new index:
1073
1104
        self.assertEqual(_KndxIndex.HEADER, call[1][1].getvalue())
1074
1105
        self.assertEqual({'create_parent_dir': True}, call[2])
1075
1106
        call = transport.calls.pop(0)
1076
 
        # call[1][1] is a StringIO - we can't test it by simple equality.
 
1107
        # call[1][1] is a BytesIO - we can't test it by simple equality.
1077
1108
        self.assertEqual('put_file_non_atomic', call[0])
1078
1109
        self.assertEqual('filename.kndx', call[1][0])
1079
1110
        # With no history, _KndxIndex writes a new index:
1165
1196
        index = self.get_knit_index(transport, 'filename', 'r')
1166
1197
        try:
1167
1198
            self.assertRaises(errors.KnitCorrupt, index.keys)
1168
 
        except TypeError, e:
 
1199
        except TypeError as e:
1169
1200
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1170
 
                           ' not exceptions.IndexError')
1171
 
                and sys.version_info[0:2] >= (2,5)):
 
1201
                           ' not exceptions.IndexError')):
1172
1202
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1173
1203
                                  ' raising new style exceptions with python'
1174
1204
                                  ' >=2.5')
1185
1215
        index = self.get_knit_index(transport, 'filename', 'r')
1186
1216
        try:
1187
1217
            self.assertRaises(errors.KnitCorrupt, index.keys)
1188
 
        except TypeError, e:
 
1218
        except TypeError as e:
1189
1219
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1190
 
                           ' not exceptions.ValueError')
1191
 
                and sys.version_info[0:2] >= (2,5)):
 
1220
                           ' not exceptions.ValueError')):
1192
1221
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1193
1222
                                  ' raising new style exceptions with python'
1194
1223
                                  ' >=2.5')
1205
1234
        index = self.get_knit_index(transport, 'filename', 'r')
1206
1235
        try:
1207
1236
            self.assertRaises(errors.KnitCorrupt, index.keys)
1208
 
        except TypeError, e:
 
1237
        except TypeError as e:
1209
1238
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1210
 
                           ' not exceptions.ValueError')
1211
 
                and sys.version_info[0:2] >= (2,5)):
 
1239
                           ' not exceptions.ValueError')):
1212
1240
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1213
1241
                                  ' raising new style exceptions with python'
1214
1242
                                  ' >=2.5')
1223
1251
        index = self.get_knit_index(transport, 'filename', 'r')
1224
1252
        try:
1225
1253
            self.assertRaises(errors.KnitCorrupt, index.keys)
1226
 
        except TypeError, e:
 
1254
        except TypeError as e:
1227
1255
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1228
 
                           ' not exceptions.ValueError')
1229
 
                and sys.version_info[0:2] >= (2,5)):
 
1256
                           ' not exceptions.ValueError')):
1230
1257
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1231
1258
                                  ' raising new style exceptions with python'
1232
1259
                                  ' >=2.5')
1241
1268
        index = self.get_knit_index(transport, 'filename', 'r')
1242
1269
        try:
1243
1270
            self.assertRaises(errors.KnitCorrupt, index.keys)
1244
 
        except TypeError, e:
 
1271
        except TypeError as e:
1245
1272
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1246
 
                           ' not exceptions.ValueError')
1247
 
                and sys.version_info[0:2] >= (2,5)):
 
1273
                           ' not exceptions.ValueError')):
1248
1274
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1249
1275
                                  ' raising new style exceptions with python'
1250
1276
                                  ' >=2.5')
1267
1293
            "b option 10 10 0", # This line isn't terminated, ignored
1268
1294
            ])
1269
1295
        index = self.get_knit_index(transport, "filename", "r")
1270
 
        self.assertEqual(set([('a',)]), index.keys())
 
1296
        self.assertEqual({('a',)}, index.keys())
1271
1297
 
1272
1298
    def test_skip_incomplete_record(self):
1273
1299
        # A line with bogus data should just be skipped
1278
1304
            "c option 20 10 0 :", # Properly terminated, and starts with '\n'
1279
1305
            ])
1280
1306
        index = self.get_knit_index(transport, "filename", "r")
1281
 
        self.assertEqual(set([('a',), ('c',)]), index.keys())
 
1307
        self.assertEqual({('a',), ('c',)}, index.keys())
1282
1308
 
1283
1309
    def test_trailing_characters(self):
1284
1310
        # A line with bogus data should just be skipped
1289
1315
            "c option 20 10 0 :", # Properly terminated, and starts with '\n'
1290
1316
            ])
1291
1317
        index = self.get_knit_index(transport, "filename", "r")
1292
 
        self.assertEqual(set([('a',), ('c',)]), index.keys())
 
1318
        self.assertEqual({('a',), ('c',)}, index.keys())
1293
1319
 
1294
1320
 
1295
1321
class LowLevelKnitIndexTests_c(LowLevelKnitIndexTests):
1298
1324
 
1299
1325
    def get_knit_index(self, transport, name, mode):
1300
1326
        mapper = ConstantMapper(name)
1301
 
        from bzrlib._knit_load_data_pyx import _load_data_c
 
1327
        from breezy._knit_load_data_pyx import _load_data_c
1302
1328
        self.overrideAttr(knit, '_load_data', _load_data_c)
1303
1329
        allow_writes = lambda: mode == 'w'
1304
1330
        return _KndxIndex(transport, mapper, lambda:None,
1525
1551
            'a-2 fulltext 0 0 0 :\n'
1526
1552
            'a-3 fulltext 0 0 1 :'
1527
1553
            )
1528
 
        self.assertEqual(set([('a-3',), ('a-1',), ('a-2',)]), idx.keys())
 
1554
        self.assertEqual({('a-3',), ('a-1',), ('a-2',)}, idx.keys())
1529
1555
        self.assertEqual({
1530
1556
            ('a-1',): ((('a-1',), 0, 0), None, (), ('fulltext', False)),
1531
1557
            ('a-2',): ((('a-2',), 0, 0), None, (('a-1',),), ('fulltext', False)),
1563
1589
 
1564
1590
        # Assert the pre-condition
1565
1591
        def assertA1Only():
1566
 
            self.assertEqual(set([('a-1',)]), set(idx.keys()))
 
1592
            self.assertEqual({('a-1',)}, set(idx.keys()))
1567
1593
            self.assertEqual(
1568
1594
                {('a-1',): ((('a-1',), 0, 0), None, (), ('fulltext', False))},
1569
1595
                idx.get_build_details([('a-1',)]))
1579
1605
        # could leave an empty .kndx file, which bzr would later claim was a
1580
1606
        # corrupted file since the header was not present. In reality, the file
1581
1607
        # just wasn't created, so it should be ignored.
1582
 
        t = get_transport('.')
 
1608
        t = transport.get_transport_from_path('.')
1583
1609
        t.put_bytes('test.kndx', '')
1584
1610
 
1585
1611
        knit = self.make_test_knit()
1586
1612
 
1587
1613
    def test_knit_index_checks_header(self):
1588
 
        t = get_transport('.')
 
1614
        t = transport.get_transport_from_path('.')
1589
1615
        t.put_bytes('test.kndx', '# not really a knit header\n\n')
1590
1616
        k = self.make_test_knit()
1591
1617
        self.assertRaises(KnitHeaderError, k.keys)
1638
1664
 
1639
1665
    def test_keys(self):
1640
1666
        index = self.two_graph_index()
1641
 
        self.assertEqual(set([('tail',), ('tip',), ('parent',), ('separate',)]),
 
1667
        self.assertEqual({('tail',), ('tip',), ('parent',), ('separate',)},
1642
1668
            set(index.keys()))
1643
1669
 
1644
1670
    def test_get_position(self):
1940
1966
 
1941
1967
    def test_keys(self):
1942
1968
        index = self.two_graph_index()
1943
 
        self.assertEqual(set([('tail',), ('tip',), ('parent',), ('separate',)]),
 
1969
        self.assertEqual({('tail',), ('tip',), ('parent',), ('separate',)},
1944
1970
            set(index.keys()))
1945
1971
 
1946
1972
    def test_get_position(self):
2104
2130
            }
2105
2131
        self.assertGroupKeysForIo([([f_a], set())],
2106
2132
                                  [f_a], [], positions)
2107
 
        self.assertGroupKeysForIo([([f_a], set([f_a]))],
 
2133
        self.assertGroupKeysForIo([([f_a], {f_a})],
2108
2134
                                  [f_a], [f_a], positions)
2109
2135
        self.assertGroupKeysForIo([([f_a, f_b], set([]))],
2110
2136
                                  [f_a, f_b], [], positions)
2111
 
        self.assertGroupKeysForIo([([f_a, f_b], set([f_b]))],
 
2137
        self.assertGroupKeysForIo([([f_a, f_b], {f_b})],
2112
2138
                                  [f_a, f_b], [f_b], positions)
2113
2139
        self.assertGroupKeysForIo([([f_a, f_b, g_a, g_b], set())],
2114
2140
                                  [f_a, g_a, f_b, g_b], [], positions)
2211
2237
        self.assertEqual([(key_basis, 'foo\n'), (key_basis, 'bar\n')], details)
2212
2238
        # Not optimised to date:
2213
2239
        # self.assertEqual([("annotate", key_basis)], basis.calls)
2214
 
        self.assertEqual([('get_parent_map', set([key_basis])),
2215
 
            ('get_parent_map', set([key_basis])),
 
2240
        self.assertEqual([('get_parent_map', {key_basis}),
 
2241
            ('get_parent_map', {key_basis}),
2216
2242
            ('get_record_stream', [key_basis], 'topological', True)],
2217
2243
            basis.calls)
2218
2244
 
2238
2264
        parent_map = test.get_parent_map([key, key_basis, key_missing])
2239
2265
        self.assertEqual({key: (),
2240
2266
            key_basis: ()}, parent_map)
2241
 
        self.assertEqual([("get_parent_map", set([key_basis, key_missing]))],
 
2267
        self.assertEqual([("get_parent_map", {key_basis, key_missing})],
2242
2268
            basis.calls)
2243
2269
 
2244
2270
    def test_get_record_stream_unordered_fulltexts(self):
2275
2301
        # It's not strictly minimal, but it seems reasonable for now for it to
2276
2302
        # ask which fallbacks have which parents.
2277
2303
        self.assertEqual([
2278
 
            ("get_parent_map", set([key_basis, key_missing])),
 
2304
            ("get_parent_map", {key_basis, key_missing}),
2279
2305
            ("get_record_stream", [key_basis], 'unordered', True)],
2280
2306
            calls)
2281
2307
 
2312
2338
                source = test
2313
2339
            else:
2314
2340
                source = basis
2315
 
            record = source.get_record_stream([result[0]], 'unordered',
2316
 
                True).next()
 
2341
            record = next(source.get_record_stream([result[0]], 'unordered',
 
2342
                True))
2317
2343
            self.assertEqual(record.key, result[0])
2318
2344
            self.assertEqual(record.sha1, result[1])
2319
2345
            # We used to check that the storage kind matched, but actually it
2324
2350
        # It's not strictly minimal, but it seems reasonable for now for it to
2325
2351
        # ask which fallbacks have which parents.
2326
2352
        self.assertEqual([
2327
 
            ("get_parent_map", set([key_basis, key_basis_2, key_missing])),
 
2353
            ("get_parent_map", {key_basis, key_basis_2, key_missing}),
2328
2354
            # topological is requested from the fallback, because that is what
2329
2355
            # was requested at the top level.
2330
2356
            ("get_record_stream", [key_basis_2, key_basis], 'topological', True)],
2362
2388
        # It's not strictly minimal, but it seems reasonable for now for it to
2363
2389
        # ask which fallbacks have which parents.
2364
2390
        self.assertEqual([
2365
 
            ("get_parent_map", set([key_basis, key_missing])),
 
2391
            ("get_parent_map", {key_basis, key_missing}),
2366
2392
            ("get_record_stream", [key_basis], 'unordered', False)],
2367
2393
            calls)
2368
2394
 
2399
2425
                source = test
2400
2426
            else:
2401
2427
                source = basis
2402
 
            record = source.get_record_stream([result[0]], 'unordered',
2403
 
                False).next()
 
2428
            record = next(source.get_record_stream([result[0]], 'unordered',
 
2429
                False))
2404
2430
            self.assertEqual(record.key, result[0])
2405
2431
            self.assertEqual(record.sha1, result[1])
2406
2432
            self.assertEqual(record.storage_kind, result[2])
2408
2434
        # It's not strictly minimal, but it seems reasonable for now for it to
2409
2435
        # ask which fallbacks have which parents.
2410
2436
        self.assertEqual([
2411
 
            ("get_parent_map", set([key_basis, key_basis_2, key_missing])),
 
2437
            ("get_parent_map", {key_basis, key_basis_2, key_missing}),
2412
2438
            ("get_record_stream", [key_basis_2, key_basis], 'topological', False)],
2413
2439
            calls)
2414
2440
 
2419
2445
        key_basis = ('bar',)
2420
2446
        key_missing = ('missing',)
2421
2447
        test.add_lines(key, (), ['foo\n'])
2422
 
        key_sha1sum = osutils.sha('foo\n').hexdigest()
 
2448
        key_sha1sum = osutils.sha_string('foo\n')
2423
2449
        sha1s = test.get_sha1s([key])
2424
2450
        self.assertEqual({key: key_sha1sum}, sha1s)
2425
2451
        self.assertEqual([], basis.calls)
2427
2453
        # directly (rather than via text reconstruction) so that remote servers
2428
2454
        # etc don't have to answer with full content.
2429
2455
        basis.add_lines(key_basis, (), ['foo\n', 'bar\n'])
2430
 
        basis_sha1sum = osutils.sha('foo\nbar\n').hexdigest()
 
2456
        basis_sha1sum = osutils.sha_string('foo\nbar\n')
2431
2457
        basis.calls = []
2432
2458
        sha1s = test.get_sha1s([key, key_missing, key_basis])
2433
2459
        self.assertEqual({key: key_sha1sum,
2434
2460
            key_basis: basis_sha1sum}, sha1s)
2435
 
        self.assertEqual([("get_sha1s", set([key_basis, key_missing]))],
 
2461
        self.assertEqual([("get_sha1s", {key_basis, key_missing})],
2436
2462
            basis.calls)
2437
2463
 
2438
2464
    def test_insert_record_stream(self):
2451
2477
        test.insert_record_stream(stream)
2452
2478
        # XXX: this does somewhat too many calls in making sure of whether it
2453
2479
        # has to recreate the full text.
2454
 
        self.assertEqual([("get_parent_map", set([key_basis])),
2455
 
             ('get_parent_map', set([key_basis])),
 
2480
        self.assertEqual([("get_parent_map", {key_basis}),
 
2481
             ('get_parent_map', {key_basis}),
2456
2482
             ('get_record_stream', [key_basis], 'unordered', True)],
2457
2483
            basis.calls)
2458
2484
        self.assertEqual({key_delta:(key_basis,)},
2471
2497
        basis.calls = []
2472
2498
        lines = list(test.iter_lines_added_or_present_in_keys([key1]))
2473
2499
        self.assertEqual([("foo\n", key1)], lines)
2474
 
        self.assertEqual([("iter_lines_added_or_present_in_keys", set([key1]))],
 
2500
        self.assertEqual([("iter_lines_added_or_present_in_keys", {key1})],
2475
2501
            basis.calls)
2476
2502
        # keys in both are not duplicated:
2477
2503
        test.add_lines(key2, (), ["bar\n"])
2493
2519
        basis.add_lines(key1, (), [])
2494
2520
        basis.calls = []
2495
2521
        keys = test.keys()
2496
 
        self.assertEqual(set([key1]), set(keys))
 
2522
        self.assertEqual({key1}, set(keys))
2497
2523
        self.assertEqual([("keys",)], basis.calls)
2498
2524
        # keys in both are not duplicated:
2499
2525
        test.add_lines(key2, (), [])
2501
2527
        basis.calls = []
2502
2528
        keys = test.keys()
2503
2529
        self.assertEqual(2, len(keys))
2504
 
        self.assertEqual(set([key1, key2]), set(keys))
 
2530
        self.assertEqual({key1, key2}, set(keys))
2505
2531
        self.assertEqual([("keys",)], basis.calls)
2506
2532
 
2507
2533
    def test_add_mpdiffs(self):
2519
2545
        diffs = source.make_mpdiffs([key_delta])
2520
2546
        test.add_mpdiffs([(key_delta, (key_basis,),
2521
2547
            source.get_sha1s([key_delta])[key_delta], diffs[0])])
2522
 
        self.assertEqual([("get_parent_map", set([key_basis])),
 
2548
        self.assertEqual([("get_parent_map", {key_basis}),
2523
2549
            ('get_record_stream', [key_basis], 'unordered', True),],
2524
2550
            basis.calls)
2525
2551
        self.assertEqual({key_delta:(key_basis,)},
2547
2573
            diffs)
2548
2574
        self.assertEqual(3, len(basis.calls))
2549
2575
        self.assertEqual([
2550
 
            ("get_parent_map", set([key_left, key_right])),
2551
 
            ("get_parent_map", set([key_left, key_right])),
 
2576
            ("get_parent_map", {key_left, key_right}),
 
2577
            ("get_parent_map", {key_left, key_right}),
2552
2578
            ],
2553
2579
            basis.calls[:-1])
2554
2580
        last_call = basis.calls[-1]
2555
2581
        self.assertEqual('get_record_stream', last_call[0])
2556
 
        self.assertEqual(set([key_left, key_right]), set(last_call[1]))
 
2582
        self.assertEqual({key_left, key_right}, set(last_call[1]))
2557
2583
        self.assertEqual('topological', last_call[2])
2558
2584
        self.assertEqual(True, last_call[3])
2559
2585