~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_knit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-02-16 00:53:04 UTC
  • mfrom: (4997.1.3 find-branches-local)
  • Revision ID: pqm@pqm.ubuntu.com-20100216005304-1p8xafkhiizh6ugi
(Jelmer) Add BzrDir.list_branches().

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
17
17
"""Tests for Knit data structure"""
18
18
 
19
19
from cStringIO import StringIO
 
20
import difflib
20
21
import gzip
21
22
import sys
22
23
 
23
24
from bzrlib import (
24
25
    errors,
 
26
    generate_ids,
25
27
    knit,
26
28
    multiparent,
27
29
    osutils,
28
30
    pack,
29
31
    tests,
30
 
    transport,
31
32
    )
32
33
from bzrlib.errors import (
 
34
    RevisionAlreadyPresent,
33
35
    KnitHeaderError,
 
36
    RevisionNotPresent,
34
37
    NoSuchFile,
35
38
    )
36
39
from bzrlib.index import *
37
40
from bzrlib.knit import (
38
41
    AnnotatedKnitContent,
39
42
    KnitContent,
 
43
    KnitSequenceMatcher,
40
44
    KnitVersionedFiles,
41
45
    PlainKnitContent,
42
46
    _VFContentMapGenerator,
 
47
    _DirectPackAccess,
43
48
    _KndxIndex,
44
49
    _KnitGraphIndex,
45
50
    _KnitKeyAccess,
46
51
    make_file_factory,
47
52
    )
48
 
from bzrlib.patiencediff import PatienceSequenceMatcher
49
 
from bzrlib.repofmt import (
50
 
    knitpack_repo,
51
 
    pack_repo,
52
 
    )
 
53
from bzrlib.repofmt import pack_repo
53
54
from bzrlib.tests import (
 
55
    Feature,
 
56
    KnownFailure,
54
57
    TestCase,
55
58
    TestCaseWithMemoryTransport,
56
59
    TestCaseWithTransport,
57
60
    TestNotApplicable,
58
61
    )
 
62
from bzrlib.transport import get_transport
 
63
from bzrlib.transport.memory import MemoryTransport
 
64
from bzrlib.tuned_gzip import GzipFile
59
65
from bzrlib.versionedfile import (
60
66
    AbsentContentFactory,
61
67
    ConstantMapper,
100
106
        line_delta = source_content.line_delta(target_content)
101
107
        delta_blocks = list(KnitContent.get_line_delta_blocks(line_delta,
102
108
            source_lines, target_lines))
103
 
        matcher = PatienceSequenceMatcher(None, source_lines, target_lines)
104
 
        matcher_blocks = list(matcher.get_matching_blocks())
 
109
        matcher = KnitSequenceMatcher(None, source_lines, target_lines)
 
110
        matcher_blocks = list(list(matcher.get_matching_blocks()))
105
111
        self.assertEqual(matcher_blocks, delta_blocks)
106
112
 
107
113
    def test_get_line_delta_blocks(self):
327
333
            transport.append_bytes(packname, bytes)
328
334
        writer = pack.ContainerWriter(write_data)
329
335
        writer.begin()
330
 
        access = pack_repo._DirectPackAccess({})
 
336
        access = _DirectPackAccess({})
331
337
        access.set_writer(writer, index, (transport, packname))
332
338
        return access, writer
333
339
 
340
346
        writer.end()
341
347
        return memos
342
348
 
343
 
    def test_pack_collection_pack_retries(self):
344
 
        """An explicit pack of a pack collection succeeds even when a
345
 
        concurrent pack happens.
346
 
        """
347
 
        builder = self.make_branch_builder('.')
348
 
        builder.start_series()
349
 
        builder.build_snapshot('rev-1', None, [
350
 
            ('add', ('', 'root-id', 'directory', None)),
351
 
            ('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
352
 
            ])
353
 
        builder.build_snapshot('rev-2', ['rev-1'], [
354
 
            ('modify', ('file-id', 'content\nrev 2\n')),
355
 
            ])
356
 
        builder.build_snapshot('rev-3', ['rev-2'], [
357
 
            ('modify', ('file-id', 'content\nrev 3\n')),
358
 
            ])
359
 
        self.addCleanup(builder.finish_series)
360
 
        b = builder.get_branch()
361
 
        self.addCleanup(b.lock_write().unlock)
362
 
        repo = b.repository
363
 
        collection = repo._pack_collection
364
 
        # Concurrently repack the repo.
365
 
        reopened_repo = repo.bzrdir.open_repository()
366
 
        reopened_repo.pack()
367
 
        # Pack the new pack.
368
 
        collection.pack()
369
 
 
370
349
    def make_vf_for_retrying(self):
371
350
        """Create 3 packs and a reload function.
372
351
 
399
378
        collection = repo._pack_collection
400
379
        collection.ensure_loaded()
401
380
        orig_packs = collection.packs
402
 
        packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
 
381
        packer = pack_repo.Packer(collection, orig_packs, '.testpack')
403
382
        new_pack = packer.pack()
404
383
        # forget about the new pack
405
384
        collection.reset()
444
423
        except _TestException, e:
445
424
            retry_exc = errors.RetryWithNewPacks(None, reload_occurred=False,
446
425
                                                 exc_info=sys.exc_info())
447
 
        # GZ 2010-08-10: Cycle with exc_info affects 3 tests
448
426
        return retry_exc
449
427
 
450
428
    def test_read_from_several_packs(self):
459
437
        memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
460
438
        writer.end()
461
439
        transport = self.get_transport()
462
 
        access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
 
440
        access = _DirectPackAccess({"FOO":(transport, 'packfile'),
463
441
            "FOOBAR":(transport, 'pack2'),
464
442
            "BAZ":(transport, 'pack3')})
465
443
        self.assertEqual(['1234567890', '12345', 'alpha'],
475
453
 
476
454
    def test_set_writer(self):
477
455
        """The writer should be settable post construction."""
478
 
        access = pack_repo._DirectPackAccess({})
 
456
        access = _DirectPackAccess({})
479
457
        transport = self.get_transport()
480
458
        packname = 'packfile'
481
459
        index = 'foo'
493
471
        transport = self.get_transport()
494
472
        reload_called, reload_func = self.make_reload_func()
495
473
        # Note that the index key has changed from 'foo' to 'bar'
496
 
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
 
474
        access = _DirectPackAccess({'bar':(transport, 'packname')},
497
475
                                   reload_func=reload_func)
498
476
        e = self.assertListRaises(errors.RetryWithNewPacks,
499
477
                                  access.get_raw_records, memos)
508
486
        memos = self.make_pack_file()
509
487
        transport = self.get_transport()
510
488
        # Note that the index key has changed from 'foo' to 'bar'
511
 
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
 
489
        access = _DirectPackAccess({'bar':(transport, 'packname')})
512
490
        e = self.assertListRaises(KeyError, access.get_raw_records, memos)
513
491
 
514
492
    def test_missing_file_raises_retry(self):
516
494
        transport = self.get_transport()
517
495
        reload_called, reload_func = self.make_reload_func()
518
496
        # Note that the 'filename' has been changed to 'different-packname'
519
 
        access = pack_repo._DirectPackAccess(
520
 
            {'foo':(transport, 'different-packname')},
521
 
            reload_func=reload_func)
 
497
        access = _DirectPackAccess({'foo':(transport, 'different-packname')},
 
498
                                   reload_func=reload_func)
522
499
        e = self.assertListRaises(errors.RetryWithNewPacks,
523
500
                                  access.get_raw_records, memos)
524
501
        # The file has gone missing, so we assume we need to reload
532
509
        memos = self.make_pack_file()
533
510
        transport = self.get_transport()
534
511
        # Note that the 'filename' has been changed to 'different-packname'
535
 
        access = pack_repo._DirectPackAccess(
536
 
            {'foo': (transport, 'different-packname')})
 
512
        access = _DirectPackAccess({'foo':(transport, 'different-packname')})
537
513
        e = self.assertListRaises(errors.NoSuchFile,
538
514
                                  access.get_raw_records, memos)
539
515
 
543
519
        failing_transport = MockReadvFailingTransport(
544
520
                                [transport.get_bytes('packname')])
545
521
        reload_called, reload_func = self.make_reload_func()
546
 
        access = pack_repo._DirectPackAccess(
547
 
            {'foo': (failing_transport, 'packname')},
548
 
            reload_func=reload_func)
 
522
        access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
 
523
                                   reload_func=reload_func)
549
524
        # Asking for a single record will not trigger the Mock failure
550
525
        self.assertEqual(['1234567890'],
551
526
            list(access.get_raw_records(memos[:1])))
567
542
        failing_transport = MockReadvFailingTransport(
568
543
                                [transport.get_bytes('packname')])
569
544
        reload_called, reload_func = self.make_reload_func()
570
 
        access = pack_repo._DirectPackAccess(
571
 
            {'foo':(failing_transport, 'packname')})
 
545
        access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
572
546
        # Asking for a single record will not trigger the Mock failure
573
547
        self.assertEqual(['1234567890'],
574
548
            list(access.get_raw_records(memos[:1])))
579
553
                                  access.get_raw_records, memos)
580
554
 
581
555
    def test_reload_or_raise_no_reload(self):
582
 
        access = pack_repo._DirectPackAccess({}, reload_func=None)
 
556
        access = _DirectPackAccess({}, reload_func=None)
583
557
        retry_exc = self.make_retry_exception()
584
558
        # Without a reload_func, we will just re-raise the original exception
585
559
        self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
586
560
 
587
561
    def test_reload_or_raise_reload_changed(self):
588
562
        reload_called, reload_func = self.make_reload_func(return_val=True)
589
 
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
 
563
        access = _DirectPackAccess({}, reload_func=reload_func)
590
564
        retry_exc = self.make_retry_exception()
591
565
        access.reload_or_raise(retry_exc)
592
566
        self.assertEqual([1], reload_called)
596
570
 
597
571
    def test_reload_or_raise_reload_no_change(self):
598
572
        reload_called, reload_func = self.make_reload_func(return_val=False)
599
 
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
 
573
        access = _DirectPackAccess({}, reload_func=reload_func)
600
574
        retry_exc = self.make_retry_exception()
601
575
        # If reload_occurred is False, then we consider it an error to have
602
576
        # reload_func() return False (no changes).
733
707
 
734
708
    def make_multiple_records(self):
735
709
        """Create the content for multiple records."""
736
 
        sha1sum = osutils.sha_string('foo\nbar\n')
 
710
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
737
711
        total_txt = []
738
712
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
739
713
                                        'foo\n'
742
716
                                        % (sha1sum,))
743
717
        record_1 = (0, len(gz_txt), sha1sum)
744
718
        total_txt.append(gz_txt)
745
 
        sha1sum = osutils.sha_string('baz\n')
 
719
        sha1sum = osutils.sha('baz\n').hexdigest()
746
720
        gz_txt = self.create_gz_content('version rev-id-2 1 %s\n'
747
721
                                        'baz\n'
748
722
                                        'end rev-id-2\n'
752
726
        return total_txt, record_1, record_2
753
727
 
754
728
    def test_valid_knit_data(self):
755
 
        sha1sum = osutils.sha_string('foo\nbar\n')
 
729
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
756
730
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
757
731
                                        'foo\n'
758
732
                                        'bar\n'
789
763
                         raw_contents)
790
764
 
791
765
    def test_not_enough_lines(self):
792
 
        sha1sum = osutils.sha_string('foo\n')
 
766
        sha1sum = osutils.sha('foo\n').hexdigest()
793
767
        # record says 2 lines data says 1
794
768
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
795
769
                                        'foo\n'
807
781
        self.assertEqual([(('rev-id-1',),  gz_txt, sha1sum)], raw_contents)
808
782
 
809
783
    def test_too_many_lines(self):
810
 
        sha1sum = osutils.sha_string('foo\nbar\n')
 
784
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
811
785
        # record says 1 lines data says 2
812
786
        gz_txt = self.create_gz_content('version rev-id-1 1 %s\n'
813
787
                                        'foo\n'
826
800
        self.assertEqual([(('rev-id-1',), gz_txt, sha1sum)], raw_contents)
827
801
 
828
802
    def test_mismatched_version_id(self):
829
 
        sha1sum = osutils.sha_string('foo\nbar\n')
 
803
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
830
804
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
831
805
                                        'foo\n'
832
806
                                        'bar\n'
845
819
            knit._read_records_iter_raw(records))
846
820
 
847
821
    def test_uncompressed_data(self):
848
 
        sha1sum = osutils.sha_string('foo\nbar\n')
 
822
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
849
823
        txt = ('version rev-id-1 2 %s\n'
850
824
               'foo\n'
851
825
               'bar\n'
865
839
            knit._read_records_iter_raw(records))
866
840
 
867
841
    def test_corrupted_data(self):
868
 
        sha1sum = osutils.sha_string('foo\nbar\n')
 
842
        sha1sum = osutils.sha('foo\nbar\n').hexdigest()
869
843
        gz_txt = self.create_gz_content('version rev-id-1 2 %s\n'
870
844
                                        'foo\n'
871
845
                                        'bar\n'
1193
1167
            self.assertRaises(errors.KnitCorrupt, index.keys)
1194
1168
        except TypeError, e:
1195
1169
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1196
 
                           ' not exceptions.IndexError')):
 
1170
                           ' not exceptions.IndexError')
 
1171
                and sys.version_info[0:2] >= (2,5)):
1197
1172
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1198
1173
                                  ' raising new style exceptions with python'
1199
1174
                                  ' >=2.5')
1212
1187
            self.assertRaises(errors.KnitCorrupt, index.keys)
1213
1188
        except TypeError, e:
1214
1189
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1215
 
                           ' not exceptions.ValueError')):
 
1190
                           ' not exceptions.ValueError')
 
1191
                and sys.version_info[0:2] >= (2,5)):
1216
1192
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1217
1193
                                  ' raising new style exceptions with python'
1218
1194
                                  ' >=2.5')
1231
1207
            self.assertRaises(errors.KnitCorrupt, index.keys)
1232
1208
        except TypeError, e:
1233
1209
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1234
 
                           ' not exceptions.ValueError')):
 
1210
                           ' not exceptions.ValueError')
 
1211
                and sys.version_info[0:2] >= (2,5)):
1235
1212
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1236
1213
                                  ' raising new style exceptions with python'
1237
1214
                                  ' >=2.5')
1248
1225
            self.assertRaises(errors.KnitCorrupt, index.keys)
1249
1226
        except TypeError, e:
1250
1227
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1251
 
                           ' not exceptions.ValueError')):
 
1228
                           ' not exceptions.ValueError')
 
1229
                and sys.version_info[0:2] >= (2,5)):
1252
1230
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1253
1231
                                  ' raising new style exceptions with python'
1254
1232
                                  ' >=2.5')
1265
1243
            self.assertRaises(errors.KnitCorrupt, index.keys)
1266
1244
        except TypeError, e:
1267
1245
            if (str(e) == ('exceptions must be strings, classes, or instances,'
1268
 
                           ' not exceptions.ValueError')):
 
1246
                           ' not exceptions.ValueError')
 
1247
                and sys.version_info[0:2] >= (2,5)):
1269
1248
                self.knownFailure('Pyrex <0.9.5 fails with TypeError when'
1270
1249
                                  ' raising new style exceptions with python'
1271
1250
                                  ' >=2.5')
1600
1579
        # could leave an empty .kndx file, which bzr would later claim was a
1601
1580
        # corrupted file since the header was not present. In reality, the file
1602
1581
        # just wasn't created, so it should be ignored.
1603
 
        t = transport.get_transport('.')
 
1582
        t = get_transport('.')
1604
1583
        t.put_bytes('test.kndx', '')
1605
1584
 
1606
1585
        knit = self.make_test_knit()
1607
1586
 
1608
1587
    def test_knit_index_checks_header(self):
1609
 
        t = transport.get_transport('.')
 
1588
        t = get_transport('.')
1610
1589
        t.put_bytes('test.kndx', '# not really a knit header\n\n')
1611
1590
        k = self.make_test_knit()
1612
1591
        self.assertRaises(KnitHeaderError, k.keys)
2440
2419
        key_basis = ('bar',)
2441
2420
        key_missing = ('missing',)
2442
2421
        test.add_lines(key, (), ['foo\n'])
2443
 
        key_sha1sum = osutils.sha_string('foo\n')
 
2422
        key_sha1sum = osutils.sha('foo\n').hexdigest()
2444
2423
        sha1s = test.get_sha1s([key])
2445
2424
        self.assertEqual({key: key_sha1sum}, sha1s)
2446
2425
        self.assertEqual([], basis.calls)
2448
2427
        # directly (rather than via text reconstruction) so that remote servers
2449
2428
        # etc don't have to answer with full content.
2450
2429
        basis.add_lines(key_basis, (), ['foo\n', 'bar\n'])
2451
 
        basis_sha1sum = osutils.sha_string('foo\nbar\n')
 
2430
        basis_sha1sum = osutils.sha('foo\nbar\n').hexdigest()
2452
2431
        basis.calls = []
2453
2432
        sha1s = test.get_sha1s([key, key_missing, key_basis])
2454
2433
        self.assertEqual({key: key_sha1sum,