40
from ...errors import (
39
from ..errors import (
41
40
RevisionNotPresent,
42
41
RevisionAlreadyPresent,
43
from ..bzr.knit import (
49
from ...tests import (
48
from ..sixish import (
51
54
TestCaseWithMemoryTransport,
55
from ...tests.http_utils import TestCaseWithWebserver
56
from ...transport.memory import MemoryTransport
57
from .. import versionedfile as versionedfile
58
from ..versionedfile import (
59
ChunkedContentFactory,
58
from .http_utils import TestCaseWithWebserver
59
from ..transport.memory import MemoryTransport
60
from ..bzr import versionedfile as versionedfile
61
from ..bzr.versionedfile import (
62
63
HashEscapedPrefixMapper,
64
UnavailableRepresentation,
65
65
VirtualVersionedFiles,
66
66
make_versioned_files_factory,
68
from ..bzr.weave import (
70
70
WeaveInvalidChecksum,
72
from ..weavefile import write_weave
73
from ...tests.scenarios import load_tests_apply_scenarios
72
from ..bzr.weavefile import write_weave
73
from .scenarios import load_tests_apply_scenarios
76
76
load_tests = load_tests_apply_scenarios
305
305
# we now have a copy of all the lines in the vf.
306
306
for sha, (version, lines) in zip(
307
307
shas, (empty_text, sample_text_nl, sample_text_no_nl)):
308
self.assertRaises(ExistingContent,
308
self.assertRaises(errors.ExistingContent,
309
309
vf.add_lines, version + b"2", [], lines,
311
311
# and no new version should have been added.
330
330
raise TestSkipped("add_lines_with_ghosts is optional")
331
331
for sha, (version, lines) in zip(
332
332
shas, (empty_text, sample_text_nl, sample_text_no_nl)):
333
self.assertRaises(ExistingContent,
333
self.assertRaises(errors.ExistingContent,
334
334
vf.add_lines_with_ghosts, version + b"2", [], lines,
336
336
# and no new version should have been added.
535
535
def test_ancestry(self):
536
536
f = self.get_file()
537
self.assertEqual(set(), f.get_ancestry([]))
537
self.assertEqual([], f.get_ancestry([]))
538
538
f.add_lines(b'r0', [], [b'a\n', b'b\n'])
539
539
f.add_lines(b'r1', [b'r0'], [b'b\n', b'c\n'])
540
540
f.add_lines(b'r2', [b'r0'], [b'b\n', b'c\n'])
541
541
f.add_lines(b'r3', [b'r2'], [b'b\n', b'c\n'])
542
542
f.add_lines(b'rM', [b'r1', b'r2'], [b'b\n', b'c\n'])
543
self.assertEqual(set(), f.get_ancestry([]))
543
self.assertEqual([], f.get_ancestry([]))
544
544
versions = f.get_ancestry([b'rM'])
545
# there are some possibilities:
549
# so we check indexes
550
r0 = versions.index(b'r0')
551
r1 = versions.index(b'r1')
552
r2 = versions.index(b'r2')
553
self.assertFalse(b'r3' in versions)
554
rM = versions.index(b'rM')
555
self.assertTrue(r0 < r1)
556
self.assertTrue(r0 < r2)
557
self.assertTrue(r1 < rM)
558
self.assertTrue(r2 < rM)
546
560
self.assertRaises(RevisionNotPresent,
547
561
f.get_ancestry, [b'rM', b'rX'])
549
563
self.assertEqual(set(f.get_ancestry(b'rM')),
550
set(f.get_ancestry(b'rM')))
564
set(f.get_ancestry(b'rM', topo_sorted=False)))
552
566
def test_mutate_after_finish(self):
553
567
self._transaction = 'before'
720
734
# test key graph related apis: getncestry, _graph, get_parents
722
736
# - these are ghost unaware and must not be reflect ghosts
723
self.assertEqual(set([b'notbxbfse']), vf.get_ancestry(b'notbxbfse'))
737
self.assertEqual([b'notbxbfse'], vf.get_ancestry(b'notbxbfse'))
724
738
self.assertFalse(vf.has_version(parent_id_utf8))
725
739
# we have _with_ghost apis to give us ghost information.
726
self.assertEqual(set([parent_id_utf8, b'notbxbfse']),
740
self.assertEqual([parent_id_utf8, b'notbxbfse'],
727
741
vf.get_ancestry_with_ghosts([b'notbxbfse']))
728
742
self.assertEqual([parent_id_utf8],
729
743
vf.get_parents_with_ghosts(b'notbxbfse'))
730
744
# if we add something that is a ghost of another, it should correct the
731
745
# results of the prior apis
732
746
vf.add_lines(parent_id_utf8, [], [])
733
self.assertEqual(set([parent_id_utf8, b'notbxbfse']),
747
self.assertEqual([parent_id_utf8, b'notbxbfse'],
734
748
vf.get_ancestry([b'notbxbfse']))
735
749
self.assertEqual({b'notbxbfse': (parent_id_utf8,)},
736
750
vf.get_parent_map([b'notbxbfse']))
737
751
self.assertTrue(vf.has_version(parent_id_utf8))
738
752
# we have _with_ghost apis to give us ghost information.
739
self.assertEqual(set([parent_id_utf8, b'notbxbfse']),
753
self.assertEqual([parent_id_utf8, b'notbxbfse'],
740
754
vf.get_ancestry_with_ghosts([b'notbxbfse']))
741
755
self.assertEqual([parent_id_utf8],
742
756
vf.get_parents_with_ghosts(b'notbxbfse'))
895
909
return next(self.plan_merge_vf.get_record_stream(
896
910
[(b'root', suffix)], 'unordered', True))
897
911
self.assertEqual(b'a', get_record(b'A').get_bytes_as('fulltext'))
898
self.assertEqual(b'a', b''.join(get_record(b'A').iter_bytes_as('chunked')))
899
912
self.assertEqual(b'c', get_record(b'C').get_bytes_as('fulltext'))
900
913
self.assertEqual(b'e', get_record(b'E:').get_bytes_as('fulltext'))
901
914
self.assertEqual('absent', get_record('F').storage_kind)
1201
1214
# Each is source_kind, requested_kind, adapter class
1203
1216
('knit-delta-gz', 'fulltext', _mod_knit.DeltaPlainToFullText),
1204
('knit-delta-gz', 'lines', _mod_knit.DeltaPlainToFullText),
1205
('knit-delta-gz', 'chunked', _mod_knit.DeltaPlainToFullText),
1206
1217
('knit-ft-gz', 'fulltext', _mod_knit.FTPlainToFullText),
1207
('knit-ft-gz', 'lines', _mod_knit.FTPlainToFullText),
1208
('knit-ft-gz', 'chunked', _mod_knit.FTPlainToFullText),
1209
1218
('knit-annotated-delta-gz', 'knit-delta-gz',
1210
1219
_mod_knit.DeltaAnnotatedToUnannotated),
1211
1220
('knit-annotated-delta-gz', 'fulltext',
1214
1223
_mod_knit.FTAnnotatedToUnannotated),
1215
1224
('knit-annotated-ft-gz', 'fulltext',
1216
1225
_mod_knit.FTAnnotatedToFullText),
1217
('knit-annotated-ft-gz', 'lines',
1218
_mod_knit.FTAnnotatedToFullText),
1219
('knit-annotated-ft-gz', 'chunked',
1220
_mod_knit.FTAnnotatedToFullText),
1222
1227
for source, requested, klass in scenarios:
1223
1228
adapter_factory = versionedfile.adapter_registry.get(
1230
1235
transport = self.get_transport()
1231
1236
return make_file_factory(annotated, mapper)(transport)
1233
def helpGetBytes(self, f, ft_name, ft_adapter, delta_name, delta_adapter):
1238
def helpGetBytes(self, f, ft_adapter, delta_adapter):
1234
1239
"""Grab the interested adapted texts for tests."""
1235
1240
# origin is a fulltext
1236
1241
entries = f.get_record_stream([(b'origin',)], 'unordered', False)
1237
1242
base = next(entries)
1238
ft_data = ft_adapter.get_bytes(base, ft_name)
1243
ft_data = ft_adapter.get_bytes(base)
1239
1244
# merged is both a delta and multiple parents.
1240
1245
entries = f.get_record_stream([(b'merged',)], 'unordered', False)
1241
1246
merged = next(entries)
1242
delta_data = delta_adapter.get_bytes(merged, delta_name)
1247
delta_data = delta_adapter.get_bytes(merged)
1243
1248
return ft_data, delta_data
1245
1250
def test_deannotation_noeol(self):
1247
1252
# we need a full text, and a delta
1248
1253
f = self.get_knit()
1249
1254
get_diamond_files(f, 1, trailing_eol=False)
1250
ft_data, delta_data = self.helpGetBytes(
1251
f, 'knit-ft-gz', _mod_knit.FTAnnotatedToUnannotated(None),
1252
'knit-delta-gz', _mod_knit.DeltaAnnotatedToUnannotated(None))
1255
ft_data, delta_data = self.helpGetBytes(f,
1256
_mod_knit.FTAnnotatedToUnannotated(
1258
_mod_knit.DeltaAnnotatedToUnannotated(None))
1253
1259
self.assertEqual(
1254
1260
b'version origin 1 b284f94827db1fa2970d9e2014f080413b547a7e\n'
1265
1271
# we need a full text, and a delta
1266
1272
f = self.get_knit()
1267
1273
get_diamond_files(f, 1)
1268
ft_data, delta_data = self.helpGetBytes(
1269
f, 'knit-ft-gz', _mod_knit.FTAnnotatedToUnannotated(None),
1270
'knit-delta-gz', _mod_knit.DeltaAnnotatedToUnannotated(None))
1274
ft_data, delta_data = self.helpGetBytes(f,
1275
_mod_knit.FTAnnotatedToUnannotated(
1277
_mod_knit.DeltaAnnotatedToUnannotated(None))
1271
1278
self.assertEqual(
1272
1279
b'version origin 1 00e364d235126be43292ab09cb4686cf703ddc17\n'
1286
1293
# Reconstructing a full text requires a backing versioned file, and it
1287
1294
# must have the base lines requested from it.
1288
1295
logged_vf = versionedfile.RecordingVersionedFilesDecorator(f)
1289
ft_data, delta_data = self.helpGetBytes(
1290
f, 'fulltext', _mod_knit.FTAnnotatedToFullText(None),
1291
'fulltext', _mod_knit.DeltaAnnotatedToFullText(logged_vf))
1296
ft_data, delta_data = self.helpGetBytes(f,
1297
_mod_knit.FTAnnotatedToFullText(
1299
_mod_knit.DeltaAnnotatedToFullText(logged_vf))
1292
1300
self.assertEqual(b'origin', ft_data)
1293
1301
self.assertEqual(b'base\nleft\nright\nmerged', delta_data)
1294
1302
self.assertEqual([('get_record_stream', [(b'left',)], 'unordered',
1302
1310
# Reconstructing a full text requires a backing versioned file, and it
1303
1311
# must have the base lines requested from it.
1304
1312
logged_vf = versionedfile.RecordingVersionedFilesDecorator(f)
1305
ft_data, delta_data = self.helpGetBytes(
1306
f, 'fulltext', _mod_knit.FTAnnotatedToFullText(None),
1307
'fulltext', _mod_knit.DeltaAnnotatedToFullText(logged_vf))
1313
ft_data, delta_data = self.helpGetBytes(f,
1314
_mod_knit.FTAnnotatedToFullText(
1316
_mod_knit.DeltaAnnotatedToFullText(logged_vf))
1308
1317
self.assertEqual(b'origin\n', ft_data)
1309
1318
self.assertEqual(b'base\nleft\nright\nmerged\n', delta_data)
1310
1319
self.assertEqual([('get_record_stream', [(b'left',)], 'unordered',
1321
1330
# Reconstructing a full text requires a backing versioned file, and it
1322
1331
# must have the base lines requested from it.
1323
1332
logged_vf = versionedfile.RecordingVersionedFilesDecorator(f)
1324
ft_data, delta_data = self.helpGetBytes(
1325
f, 'fulltext', _mod_knit.FTPlainToFullText(None),
1326
'fulltext', _mod_knit.DeltaPlainToFullText(logged_vf))
1333
ft_data, delta_data = self.helpGetBytes(f,
1334
_mod_knit.FTPlainToFullText(
1336
_mod_knit.DeltaPlainToFullText(logged_vf))
1327
1337
self.assertEqual(b'origin\n', ft_data)
1328
1338
self.assertEqual(b'base\nleft\nright\nmerged\n', delta_data)
1329
1339
self.assertEqual([('get_record_stream', [(b'left',)], 'unordered',
1340
1350
# Reconstructing a full text requires a backing versioned file, and it
1341
1351
# must have the base lines requested from it.
1342
1352
logged_vf = versionedfile.RecordingVersionedFilesDecorator(f)
1343
ft_data, delta_data = self.helpGetBytes(
1344
f, 'fulltext', _mod_knit.FTPlainToFullText(None),
1345
'fulltext', _mod_knit.DeltaPlainToFullText(logged_vf))
1353
ft_data, delta_data = self.helpGetBytes(f,
1354
_mod_knit.FTPlainToFullText(
1356
_mod_knit.DeltaPlainToFullText(logged_vf))
1346
1357
self.assertEqual(b'origin', ft_data)
1347
1358
self.assertEqual(b'base\nleft\nright\nmerged', delta_data)
1348
1359
self.assertEqual([('get_record_stream', [(b'left',)], 'unordered',
1528
1539
self.assertEqual([(key0, b'a\nb\n'), (key1, b'b\nc\n')], records)
1530
def test_add_chunks(self):
1531
f = self.get_versionedfiles()
1532
key0 = self.get_simple_key(b'r0')
1533
key1 = self.get_simple_key(b'r1')
1534
key2 = self.get_simple_key(b'r2')
1535
keyf = self.get_simple_key(b'foo')
1536
def add_chunks(key, parents, chunks):
1537
factory = ChunkedContentFactory(
1538
key, parents, osutils.sha_strings(chunks), chunks)
1539
return f.add_content(factory)
1541
add_chunks(key0, [], [b'a', b'\nb\n'])
1543
add_chunks(key1, [key0], [b'b', b'\n', b'c\n'])
1545
add_chunks(key1, [], [b'b\n', b'c\n'])
1547
self.assertIn(key0, keys)
1548
self.assertIn(key1, keys)
1550
for record in f.get_record_stream([key0, key1], 'unordered', True):
1551
records.append((record.key, record.get_bytes_as('fulltext')))
1553
self.assertEqual([(key0, b'a\nb\n'), (key1, b'b\nc\n')], records)
1555
1541
def test_annotate(self):
1556
1542
files = self.get_versionedfiles()
1557
1543
self.get_diamond_files(files)
1646
1632
for sha, (version, lines) in zip(
1647
1633
shas, (empty_text, sample_text_nl, sample_text_no_nl)):
1648
1634
new_key = self.get_simple_key(version + b"2")
1649
self.assertRaises(ExistingContent,
1635
self.assertRaises(errors.ExistingContent,
1650
1636
vf.add_lines, new_key, [], lines,
1651
1637
nostore_sha=sha)
1652
self.assertRaises(ExistingContent,
1638
self.assertRaises(errors.ExistingContent,
1653
1639
vf.add_lines, new_key, [], lines,
1654
1640
nostore_sha=sha)
1655
1641
# and no new version should have been added.
1927
1913
self.assertIsInstance(ft_bytes, bytes)
1928
1914
chunked_bytes = factory.get_bytes_as('chunked')
1929
1915
self.assertEqualDiff(ft_bytes, b''.join(chunked_bytes))
1930
chunked_bytes = factory.iter_bytes_as('chunked')
1931
self.assertEqualDiff(ft_bytes, b''.join(chunked_bytes))
1933
1917
self.assertStreamOrder(sort_order, seen, keys)
1985
1969
self.assertEqual(parent_map[factory.key], factory.parents)
1986
1970
# currently no stream emits mpdiff
1987
self.assertRaises(UnavailableRepresentation,
1971
self.assertRaises(errors.UnavailableRepresentation,
1988
1972
factory.get_bytes_as, 'mpdiff')
1989
1973
self.assertIsInstance(factory.get_bytes_as(factory.storage_kind),