1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006-2011 Canonical Ltd
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"""
19
19
from cStringIO import StringIO
24
23
from bzrlib import (
33
32
from bzrlib.errors import (
34
RevisionAlreadyPresent,
39
36
from bzrlib.index import *
40
37
from bzrlib.knit import (
41
38
AnnotatedKnitContent,
44
40
KnitVersionedFiles,
46
42
_VFContentMapGenerator,
49
from bzrlib.patiencediff import PatienceSequenceMatcher
53
50
from bzrlib.repofmt import pack_repo
54
51
from bzrlib.tests import (
58
53
TestCaseWithMemoryTransport,
59
54
TestCaseWithTransport,
62
from bzrlib.transport import get_transport
63
from bzrlib.transport.memory import MemoryTransport
64
from bzrlib.tuned_gzip import GzipFile
65
57
from bzrlib.versionedfile import (
66
58
AbsentContentFactory,
106
98
line_delta = source_content.line_delta(target_content)
107
99
delta_blocks = list(KnitContent.get_line_delta_blocks(line_delta,
108
100
source_lines, target_lines))
109
matcher = KnitSequenceMatcher(None, source_lines, target_lines)
110
matcher_blocks = list(list(matcher.get_matching_blocks()))
101
matcher = PatienceSequenceMatcher(None, source_lines, target_lines)
102
matcher_blocks = list(matcher.get_matching_blocks())
111
103
self.assertEqual(matcher_blocks, delta_blocks)
113
105
def test_get_line_delta_blocks(self):
333
325
transport.append_bytes(packname, bytes)
334
326
writer = pack.ContainerWriter(write_data)
336
access = _DirectPackAccess({})
328
access = pack_repo._DirectPackAccess({})
337
329
access.set_writer(writer, index, (transport, packname))
338
330
return access, writer
341
def test_pack_collection_pack_retries(self):
342
"""An explicit pack of a pack collection succeeds even when a
343
concurrent pack happens.
345
builder = self.make_branch_builder('.')
346
builder.start_series()
347
builder.build_snapshot('rev-1', None, [
348
('add', ('', 'root-id', 'directory', None)),
349
('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
351
builder.build_snapshot('rev-2', ['rev-1'], [
352
('modify', ('file-id', 'content\nrev 2\n')),
354
builder.build_snapshot('rev-3', ['rev-2'], [
355
('modify', ('file-id', 'content\nrev 3\n')),
357
self.addCleanup(builder.finish_series)
358
b = builder.get_branch()
359
self.addCleanup(b.lock_write().unlock)
361
collection = repo._pack_collection
362
# Concurrently repack the repo.
363
reopened_repo = repo.bzrdir.open_repository()
349
368
def make_vf_for_retrying(self):
350
369
"""Create 3 packs and a reload function.
437
456
memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
439
458
transport = self.get_transport()
440
access = _DirectPackAccess({"FOO":(transport, 'packfile'),
459
access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
441
460
"FOOBAR":(transport, 'pack2'),
442
461
"BAZ":(transport, 'pack3')})
443
462
self.assertEqual(['1234567890', '12345', 'alpha'],
454
473
def test_set_writer(self):
455
474
"""The writer should be settable post construction."""
456
access = _DirectPackAccess({})
475
access = pack_repo._DirectPackAccess({})
457
476
transport = self.get_transport()
458
477
packname = 'packfile'
471
490
transport = self.get_transport()
472
491
reload_called, reload_func = self.make_reload_func()
473
492
# Note that the index key has changed from 'foo' to 'bar'
474
access = _DirectPackAccess({'bar':(transport, 'packname')},
493
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
475
494
reload_func=reload_func)
476
495
e = self.assertListRaises(errors.RetryWithNewPacks,
477
496
access.get_raw_records, memos)
486
505
memos = self.make_pack_file()
487
506
transport = self.get_transport()
488
507
# Note that the index key has changed from 'foo' to 'bar'
489
access = _DirectPackAccess({'bar':(transport, 'packname')})
508
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
490
509
e = self.assertListRaises(KeyError, access.get_raw_records, memos)
492
511
def test_missing_file_raises_retry(self):
494
513
transport = self.get_transport()
495
514
reload_called, reload_func = self.make_reload_func()
496
515
# Note that the 'filename' has been changed to 'different-packname'
497
access = _DirectPackAccess({'foo':(transport, 'different-packname')},
498
reload_func=reload_func)
516
access = pack_repo._DirectPackAccess(
517
{'foo':(transport, 'different-packname')},
518
reload_func=reload_func)
499
519
e = self.assertListRaises(errors.RetryWithNewPacks,
500
520
access.get_raw_records, memos)
501
521
# The file has gone missing, so we assume we need to reload
509
529
memos = self.make_pack_file()
510
530
transport = self.get_transport()
511
531
# Note that the 'filename' has been changed to 'different-packname'
512
access = _DirectPackAccess({'foo':(transport, 'different-packname')})
532
access = pack_repo._DirectPackAccess(
533
{'foo': (transport, 'different-packname')})
513
534
e = self.assertListRaises(errors.NoSuchFile,
514
535
access.get_raw_records, memos)
519
540
failing_transport = MockReadvFailingTransport(
520
541
[transport.get_bytes('packname')])
521
542
reload_called, reload_func = self.make_reload_func()
522
access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
523
reload_func=reload_func)
543
access = pack_repo._DirectPackAccess(
544
{'foo': (failing_transport, 'packname')},
545
reload_func=reload_func)
524
546
# Asking for a single record will not trigger the Mock failure
525
547
self.assertEqual(['1234567890'],
526
548
list(access.get_raw_records(memos[:1])))
542
564
failing_transport = MockReadvFailingTransport(
543
565
[transport.get_bytes('packname')])
544
566
reload_called, reload_func = self.make_reload_func()
545
access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
567
access = pack_repo._DirectPackAccess(
568
{'foo':(failing_transport, 'packname')})
546
569
# Asking for a single record will not trigger the Mock failure
547
570
self.assertEqual(['1234567890'],
548
571
list(access.get_raw_records(memos[:1])))
553
576
access.get_raw_records, memos)
555
578
def test_reload_or_raise_no_reload(self):
556
access = _DirectPackAccess({}, reload_func=None)
579
access = pack_repo._DirectPackAccess({}, reload_func=None)
557
580
retry_exc = self.make_retry_exception()
558
581
# Without a reload_func, we will just re-raise the original exception
559
582
self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
561
584
def test_reload_or_raise_reload_changed(self):
562
585
reload_called, reload_func = self.make_reload_func(return_val=True)
563
access = _DirectPackAccess({}, reload_func=reload_func)
586
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
564
587
retry_exc = self.make_retry_exception()
565
588
access.reload_or_raise(retry_exc)
566
589
self.assertEqual([1], reload_called)
571
594
def test_reload_or_raise_reload_no_change(self):
572
595
reload_called, reload_func = self.make_reload_func(return_val=False)
573
access = _DirectPackAccess({}, reload_func=reload_func)
596
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
574
597
retry_exc = self.make_retry_exception()
575
598
# If reload_occurred is False, then we consider it an error to have
576
599
# reload_func() return False (no changes).
1579
1602
# could leave an empty .kndx file, which bzr would later claim was a
1580
1603
# corrupted file since the header was not present. In reality, the file
1581
1604
# just wasn't created, so it should be ignored.
1582
t = get_transport('.')
1605
t = transport.get_transport('.')
1583
1606
t.put_bytes('test.kndx', '')
1585
1608
knit = self.make_test_knit()
1587
1610
def test_knit_index_checks_header(self):
1588
t = get_transport('.')
1611
t = transport.get_transport('.')
1589
1612
t.put_bytes('test.kndx', '# not really a knit header\n\n')
1590
1613
k = self.make_test_knit()
1591
1614
self.assertRaises(KnitHeaderError, k.keys)