38
37
from bzrlib.errors import (
39
38
RevisionNotPresent,
40
39
RevisionAlreadyPresent,
42
42
from bzrlib.knit import (
47
49
from bzrlib.tests import (
49
51
TestCaseWithMemoryTransport,
55
split_suite_by_condition,
53
58
from bzrlib.tests.http_utils import TestCaseWithWebserver
59
from bzrlib.trace import mutter
54
60
from bzrlib.transport.memory import MemoryTransport
61
from bzrlib.tsort import topo_sort
62
from bzrlib.tuned_gzip import GzipFile
55
63
import bzrlib.versionedfile as versionedfile
56
64
from bzrlib.versionedfile import (
61
69
make_versioned_files_factory,
63
71
from bzrlib.weave import WeaveFile
64
from bzrlib.weavefile import write_weave
65
from bzrlib.tests.scenarios import load_tests_apply_scenarios
68
load_tests = load_tests_apply_scenarios
72
from bzrlib.weavefile import read_weave, write_weave
75
def load_tests(standard_tests, module, loader):
76
"""Parameterize VersionedFiles tests for different implementations."""
77
to_adapt, result = split_suite_by_condition(
78
standard_tests, condition_isinstance(TestVersionedFiles))
79
# We want to be sure of behaviour for:
80
# weaves prefix layout (weave texts)
81
# individually named weaves (weave inventories)
82
# annotated knits - prefix|hash|hash-escape layout, we test the third only
83
# as it is the most complex mapper.
84
# individually named knits
85
# individual no-graph knits in packs (signatures)
86
# individual graph knits in packs (inventories)
87
# individual graph nocompression knits in packs (revisions)
88
# plain text knits in packs (texts)
92
'factory':make_versioned_files_factory(WeaveFile,
93
ConstantMapper('inventory')),
96
'support_partial_insertion': False,
100
'factory':make_file_factory(False, ConstantMapper('revisions')),
103
'support_partial_insertion': False,
105
('named-nograph-nodelta-knit-pack', {
106
'cleanup':cleanup_pack_knit,
107
'factory':make_pack_factory(False, False, 1),
110
'support_partial_insertion': False,
112
('named-graph-knit-pack', {
113
'cleanup':cleanup_pack_knit,
114
'factory':make_pack_factory(True, True, 1),
117
'support_partial_insertion': True,
119
('named-graph-nodelta-knit-pack', {
120
'cleanup':cleanup_pack_knit,
121
'factory':make_pack_factory(True, False, 1),
124
'support_partial_insertion': False,
126
('groupcompress-nograph', {
127
'cleanup':groupcompress.cleanup_pack_group,
128
'factory':groupcompress.make_pack_factory(False, False, 1),
131
'support_partial_insertion':False,
134
len_two_scenarios = [
137
'factory':make_versioned_files_factory(WeaveFile,
141
'support_partial_insertion': False,
143
('annotated-knit-escape', {
145
'factory':make_file_factory(True, HashEscapedPrefixMapper()),
148
'support_partial_insertion': False,
150
('plain-knit-pack', {
151
'cleanup':cleanup_pack_knit,
152
'factory':make_pack_factory(True, True, 2),
155
'support_partial_insertion': True,
158
'cleanup':groupcompress.cleanup_pack_group,
159
'factory':groupcompress.make_pack_factory(True, False, 1),
162
'support_partial_insertion':False,
165
scenarios = len_one_scenarios + len_two_scenarios
166
return multiply_tests(to_adapt, scenarios, result)
71
169
def get_diamond_vf(f, trailing_eol=True, left_only=False):
182
280
versions = f.versions()
183
281
self.assertTrue('r0' in versions)
184
282
self.assertTrue('r1' in versions)
185
self.assertEqual(f.get_lines('r0'), ['a\n', 'b\n'])
186
self.assertEqual(f.get_text('r0'), 'a\nb\n')
187
self.assertEqual(f.get_lines('r1'), ['b\n', 'c\n'])
283
self.assertEquals(f.get_lines('r0'), ['a\n', 'b\n'])
284
self.assertEquals(f.get_text('r0'), 'a\nb\n')
285
self.assertEquals(f.get_lines('r1'), ['b\n', 'c\n'])
188
286
self.assertEqual(2, len(f))
189
287
self.assertEqual(2, f.num_versions())
216
314
self.assertTrue('r0' in versions)
217
315
self.assertTrue('r1' in versions)
218
316
self.assertTrue('r2' in versions)
219
self.assertEqual(f.get_lines('r0'), ['a\n', 'b\n'])
220
self.assertEqual(f.get_lines('r1'), ['b\n', 'c\n'])
221
self.assertEqual(f.get_lines('r2'), ['c\n', 'd\n'])
317
self.assertEquals(f.get_lines('r0'), ['a\n', 'b\n'])
318
self.assertEquals(f.get_lines('r1'), ['b\n', 'c\n'])
319
self.assertEquals(f.get_lines('r2'), ['c\n', 'd\n'])
222
320
self.assertEqual(3, f.num_versions())
223
321
origins = f.annotate('r1')
224
self.assertEqual(origins[0][0], 'r0')
225
self.assertEqual(origins[1][0], 'r1')
322
self.assertEquals(origins[0][0], 'r0')
323
self.assertEquals(origins[1][0], 'r1')
226
324
origins = f.annotate('r2')
227
self.assertEqual(origins[0][0], 'r1')
228
self.assertEqual(origins[1][0], 'r2')
325
self.assertEquals(origins[0][0], 'r1')
326
self.assertEquals(origins[1][0], 'r2')
231
329
f = self.reopen_file()
746
844
['base', 'a_ghost'],
747
845
['line\n', 'line_b\n', 'line_c\n'])
748
846
origins = vf.annotate('references_ghost')
749
self.assertEqual(('base', 'line\n'), origins[0])
750
self.assertEqual(('base', 'line_b\n'), origins[1])
751
self.assertEqual(('references_ghost', 'line_c\n'), origins[2])
847
self.assertEquals(('base', 'line\n'), origins[0])
848
self.assertEquals(('base', 'line_b\n'), origins[1])
849
self.assertEquals(('references_ghost', 'line_c\n'), origins[2])
753
851
def test_readonly_mode(self):
754
t = self.get_transport()
852
t = transport.get_transport(self.get_url('.'))
755
853
factory = self.get_factory()
756
854
vf = factory('id', t, 0777, create=True, access_mode='w')
757
855
vf = factory('id', t, access_mode='r')
782
880
class TestWeave(TestCaseWithMemoryTransport, VersionedFileTestMixIn):
784
882
def get_file(self, name='foo'):
785
return WeaveFile(name, self.get_transport(),
883
return WeaveFile(name, transport.get_transport(self.get_url('.')),
787
885
get_scope=self.get_transaction)
789
887
def get_file_corrupted_text(self):
790
w = WeaveFile('foo', self.get_transport(),
888
w = WeaveFile('foo', transport.get_transport(self.get_url('.')),
792
890
get_scope=self.get_transaction)
793
891
w.add_lines('v1', [], ['hello\n'])
914
1012
# now with feeling.
915
1013
vf.add_lines('1', [], ['a\n'])
916
1014
vf.add_lines('2', ['1'], ['b\n', 'a\n'])
917
readonly_vf = self.get_factory()('foo',
918
transport.get_transport_from_url(self.get_readonly_url('.')))
1015
readonly_vf = self.get_factory()('foo', transport.get_transport(
1016
self.get_readonly_url('.')))
919
1017
self.assertEqual(['1', '2'], vf.versions())
920
1018
self.assertEqual(['1', '2'], readonly_vf.versions())
921
1019
for version in readonly_vf.versions():
1377
1475
class TestVersionedFiles(TestCaseWithMemoryTransport):
1378
1476
"""Tests for the multiple-file variant of VersionedFile."""
1380
# We want to be sure of behaviour for:
1381
# weaves prefix layout (weave texts)
1382
# individually named weaves (weave inventories)
1383
# annotated knits - prefix|hash|hash-escape layout, we test the third only
1384
# as it is the most complex mapper.
1385
# individually named knits
1386
# individual no-graph knits in packs (signatures)
1387
# individual graph knits in packs (inventories)
1388
# individual graph nocompression knits in packs (revisions)
1389
# plain text knits in packs (texts)
1390
len_one_scenarios = [
1393
'factory':make_versioned_files_factory(WeaveFile,
1394
ConstantMapper('inventory')),
1397
'support_partial_insertion': False,
1401
'factory':make_file_factory(False, ConstantMapper('revisions')),
1404
'support_partial_insertion': False,
1406
('named-nograph-nodelta-knit-pack', {
1407
'cleanup':cleanup_pack_knit,
1408
'factory':make_pack_factory(False, False, 1),
1411
'support_partial_insertion': False,
1413
('named-graph-knit-pack', {
1414
'cleanup':cleanup_pack_knit,
1415
'factory':make_pack_factory(True, True, 1),
1418
'support_partial_insertion': True,
1420
('named-graph-nodelta-knit-pack', {
1421
'cleanup':cleanup_pack_knit,
1422
'factory':make_pack_factory(True, False, 1),
1425
'support_partial_insertion': False,
1427
('groupcompress-nograph', {
1428
'cleanup':groupcompress.cleanup_pack_group,
1429
'factory':groupcompress.make_pack_factory(False, False, 1),
1432
'support_partial_insertion':False,
1435
len_two_scenarios = [
1438
'factory':make_versioned_files_factory(WeaveFile,
1442
'support_partial_insertion': False,
1444
('annotated-knit-escape', {
1446
'factory':make_file_factory(True, HashEscapedPrefixMapper()),
1449
'support_partial_insertion': False,
1451
('plain-knit-pack', {
1452
'cleanup':cleanup_pack_knit,
1453
'factory':make_pack_factory(True, True, 2),
1456
'support_partial_insertion': True,
1459
'cleanup':groupcompress.cleanup_pack_group,
1460
'factory':groupcompress.make_pack_factory(True, False, 1),
1463
'support_partial_insertion':False,
1467
scenarios = len_one_scenarios + len_two_scenarios
1469
1478
def get_versionedfiles(self, relpath='files'):
1470
1479
transport = self.get_transport(relpath)
1471
1480
if relpath != '.':
1483
1492
return ('FileA',) + (suffix,)
1485
def test_add_fallback_implies_without_fallbacks(self):
1486
f = self.get_versionedfiles('files')
1487
if getattr(f, 'add_fallback_versioned_files', None) is None:
1488
raise TestNotApplicable("%s doesn't support fallbacks"
1489
% (f.__class__.__name__,))
1490
g = self.get_versionedfiles('fallback')
1491
key_a = self.get_simple_key('a')
1492
g.add_lines(key_a, [], ['\n'])
1493
f.add_fallback_versioned_files(g)
1494
self.assertTrue(key_a in f.get_parent_map([key_a]))
1495
self.assertFalse(key_a in f.without_fallbacks().get_parent_map([key_a]))
1497
1494
def test_add_lines(self):
1498
1495
f = self.get_versionedfiles()
1499
1496
key0 = self.get_simple_key('r0')
2770
2767
def test_get_sha1s_nonexistent(self):
2771
self.assertEqual({}, self.texts.get_sha1s([("NONEXISTENT",)]))
2768
self.assertEquals({}, self.texts.get_sha1s([("NONEXISTENT",)]))
2773
2770
def test_get_sha1s(self):
2774
2771
self._lines["key"] = ["dataline1", "dataline2"]
2775
self.assertEqual({("key",): osutils.sha_strings(self._lines["key"])},
2772
self.assertEquals({("key",): osutils.sha_strings(self._lines["key"])},
2776
2773
self.texts.get_sha1s([("key",)]))
2778
2775
def test_get_parent_map(self):
2779
2776
self._parent_map = {"G": ("A", "B")}
2780
self.assertEqual({("G",): (("A",),("B",))},
2777
self.assertEquals({("G",): (("A",),("B",))},
2781
2778
self.texts.get_parent_map([("G",), ("L",)]))
2783
2780
def test_get_record_stream(self):
2784
2781
self._lines["A"] = ["FOO", "BAR"]
2785
2782
it = self.texts.get_record_stream([("A",)], "unordered", True)
2786
2783
record = it.next()
2787
self.assertEqual("chunked", record.storage_kind)
2788
self.assertEqual("FOOBAR", record.get_bytes_as("fulltext"))
2789
self.assertEqual(["FOO", "BAR"], record.get_bytes_as("chunked"))
2784
self.assertEquals("chunked", record.storage_kind)
2785
self.assertEquals("FOOBAR", record.get_bytes_as("fulltext"))
2786
self.assertEquals(["FOO", "BAR"], record.get_bytes_as("chunked"))
2791
2788
def test_get_record_stream_absent(self):
2792
2789
it = self.texts.get_record_stream([("A",)], "unordered", True)
2793
2790
record = it.next()
2794
self.assertEqual("absent", record.storage_kind)
2791
self.assertEquals("absent", record.storage_kind)
2796
2793
def test_iter_lines_added_or_present_in_keys(self):
2797
2794
self._lines["A"] = ["FOO", "BAR"]
2798
2795
self._lines["B"] = ["HEY"]
2799
2796
self._lines["C"] = ["Alberta"]
2800
2797
it = self.texts.iter_lines_added_or_present_in_keys([("A",), ("B",)])
2801
self.assertEqual(sorted([("FOO", "A"), ("BAR", "A"), ("HEY", "B")]),
2798
self.assertEquals(sorted([("FOO", "A"), ("BAR", "A"), ("HEY", "B")]),
2802
2799
sorted(list(it)))