1
# Copyright (C) 2006-2011 Canonical Ltd
1
# Copyright (C) 2006-2010 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
23
24
from bzrlib import (
32
33
from bzrlib.errors import (
34
RevisionAlreadyPresent,
36
39
from bzrlib.index import *
37
40
from bzrlib.knit import (
38
41
AnnotatedKnitContent,
40
44
KnitVersionedFiles,
42
46
_VFContentMapGenerator,
48
from bzrlib.patiencediff import PatienceSequenceMatcher
49
from bzrlib.repofmt import (
53
from bzrlib.repofmt import pack_repo
53
54
from bzrlib.tests import (
55
58
TestCaseWithMemoryTransport,
56
59
TestCaseWithTransport,
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,
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)
107
113
def test_get_line_delta_blocks(self):
327
333
transport.append_bytes(packname, bytes)
328
334
writer = pack.ContainerWriter(write_data)
330
access = pack_repo._DirectPackAccess({})
336
access = _DirectPackAccess({})
331
337
access.set_writer(writer, index, (transport, packname))
332
338
return access, writer
343
def test_pack_collection_pack_retries(self):
344
"""An explicit pack of a pack collection succeeds even when a
345
concurrent pack happens.
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')),
353
builder.build_snapshot('rev-2', ['rev-1'], [
354
('modify', ('file-id', 'content\nrev 2\n')),
356
builder.build_snapshot('rev-3', ['rev-2'], [
357
('modify', ('file-id', 'content\nrev 3\n')),
359
self.addCleanup(builder.finish_series)
360
b = builder.get_branch()
361
self.addCleanup(b.lock_write().unlock)
363
collection = repo._pack_collection
364
# Concurrently repack the repo.
365
reopened_repo = repo.bzrdir.open_repository()
370
349
def make_vf_for_retrying(self):
371
350
"""Create 3 packs and a reload function.
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()
458
437
memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
460
439
transport = self.get_transport()
461
access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
440
access = _DirectPackAccess({"FOO":(transport, 'packfile'),
462
441
"FOOBAR":(transport, 'pack2'),
463
442
"BAZ":(transport, 'pack3')})
464
443
self.assertEqual(['1234567890', '12345', 'alpha'],
475
454
def test_set_writer(self):
476
455
"""The writer should be settable post construction."""
477
access = pack_repo._DirectPackAccess({})
456
access = _DirectPackAccess({})
478
457
transport = self.get_transport()
479
458
packname = 'packfile'
492
471
transport = self.get_transport()
493
472
reload_called, reload_func = self.make_reload_func()
494
473
# Note that the index key has changed from 'foo' to 'bar'
495
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
474
access = _DirectPackAccess({'bar':(transport, 'packname')},
496
475
reload_func=reload_func)
497
476
e = self.assertListRaises(errors.RetryWithNewPacks,
498
477
access.get_raw_records, memos)
507
486
memos = self.make_pack_file()
508
487
transport = self.get_transport()
509
488
# Note that the index key has changed from 'foo' to 'bar'
510
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
489
access = _DirectPackAccess({'bar':(transport, 'packname')})
511
490
e = self.assertListRaises(KeyError, access.get_raw_records, memos)
513
492
def test_missing_file_raises_retry(self):
515
494
transport = self.get_transport()
516
495
reload_called, reload_func = self.make_reload_func()
517
496
# Note that the 'filename' has been changed to 'different-packname'
518
access = pack_repo._DirectPackAccess(
519
{'foo':(transport, 'different-packname')},
520
reload_func=reload_func)
497
access = _DirectPackAccess({'foo':(transport, 'different-packname')},
498
reload_func=reload_func)
521
499
e = self.assertListRaises(errors.RetryWithNewPacks,
522
500
access.get_raw_records, memos)
523
501
# The file has gone missing, so we assume we need to reload
531
509
memos = self.make_pack_file()
532
510
transport = self.get_transport()
533
511
# Note that the 'filename' has been changed to 'different-packname'
534
access = pack_repo._DirectPackAccess(
535
{'foo': (transport, 'different-packname')})
512
access = _DirectPackAccess({'foo':(transport, 'different-packname')})
536
513
e = self.assertListRaises(errors.NoSuchFile,
537
514
access.get_raw_records, memos)
542
519
failing_transport = MockReadvFailingTransport(
543
520
[transport.get_bytes('packname')])
544
521
reload_called, reload_func = self.make_reload_func()
545
access = pack_repo._DirectPackAccess(
546
{'foo': (failing_transport, 'packname')},
547
reload_func=reload_func)
522
access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
523
reload_func=reload_func)
548
524
# Asking for a single record will not trigger the Mock failure
549
525
self.assertEqual(['1234567890'],
550
526
list(access.get_raw_records(memos[:1])))
566
542
failing_transport = MockReadvFailingTransport(
567
543
[transport.get_bytes('packname')])
568
544
reload_called, reload_func = self.make_reload_func()
569
access = pack_repo._DirectPackAccess(
570
{'foo':(failing_transport, 'packname')})
545
access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
571
546
# Asking for a single record will not trigger the Mock failure
572
547
self.assertEqual(['1234567890'],
573
548
list(access.get_raw_records(memos[:1])))
578
553
access.get_raw_records, memos)
580
555
def test_reload_or_raise_no_reload(self):
581
access = pack_repo._DirectPackAccess({}, reload_func=None)
556
access = _DirectPackAccess({}, reload_func=None)
582
557
retry_exc = self.make_retry_exception()
583
558
# Without a reload_func, we will just re-raise the original exception
584
559
self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
586
561
def test_reload_or_raise_reload_changed(self):
587
562
reload_called, reload_func = self.make_reload_func(return_val=True)
588
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
563
access = _DirectPackAccess({}, reload_func=reload_func)
589
564
retry_exc = self.make_retry_exception()
590
565
access.reload_or_raise(retry_exc)
591
566
self.assertEqual([1], reload_called)
596
571
def test_reload_or_raise_reload_no_change(self):
597
572
reload_called, reload_func = self.make_reload_func(return_val=False)
598
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
573
access = _DirectPackAccess({}, reload_func=reload_func)
599
574
retry_exc = self.make_retry_exception()
600
575
# If reload_occurred is False, then we consider it an error to have
601
576
# reload_func() return False (no changes).
1604
1579
# could leave an empty .kndx file, which bzr would later claim was a
1605
1580
# corrupted file since the header was not present. In reality, the file
1606
1581
# just wasn't created, so it should be ignored.
1607
t = transport.get_transport('.')
1582
t = get_transport('.')
1608
1583
t.put_bytes('test.kndx', '')
1610
1585
knit = self.make_test_knit()
1612
1587
def test_knit_index_checks_header(self):
1613
t = transport.get_transport('.')
1588
t = get_transport('.')
1614
1589
t.put_bytes('test.kndx', '# not really a knit header\n\n')
1615
1590
k = self.make_test_knit()
1616
1591
self.assertRaises(KnitHeaderError, k.keys)