/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_knit.py

  • Committer: Andrew Bennetts
  • Date: 2011-07-12 23:33:11 UTC
  • mto: (6015.3.2 2.4)
  • mto: This revision was merged to the branch mainline in revision 6027.
  • Revision ID: andrew.bennetts@canonical.com-20110712233311-o5j4bvptl3kvw0l6
Backport lp:bzr r6020: Speed up TestCaseWithMemoryTransport._check_safety_net by reading the dirstate file directly rather than using WorkingTree.open().

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