1524
1536
[('parent',)])])
1525
1537
# but neither should have added data:
1526
1538
self.assertEqual([[], [], [], []], self.caught_entries)
1528
1540
def test_add_version_different_dup(self):
1529
1541
index = self.two_graph_index(deltas=True, catch_adds=True)
1530
1542
# change options
1531
1543
self.assertRaises(errors.KnitCorrupt, index.add_records,
1532
[(('tip',), 'no-eol,line-delta', (None, 0, 100), [('parent',)])])
1533
self.assertRaises(errors.KnitCorrupt, index.add_records,
1534
[(('tip',), 'line-delta,no-eol', (None, 0, 100), [('parent',)])])
1544
[(('tip',), 'line-delta', (None, 0, 100), [('parent',)])])
1535
1545
self.assertRaises(errors.KnitCorrupt, index.add_records,
1536
1546
[(('tip',), 'fulltext', (None, 0, 100), [('parent',)])])
1538
1548
self.assertRaises(errors.KnitCorrupt, index.add_records,
1539
1549
[(('tip',), 'fulltext,no-eol', (None, 0, 100), [])])
1540
1550
self.assertEqual([], self.caught_entries)
1542
1552
def test_add_versions_nodeltas(self):
1543
1553
index = self.two_graph_index(catch_adds=True)
1544
1554
index.add_records([
1586
1596
[('parent',)])])
1587
1597
# but neither should have added data.
1588
1598
self.assertEqual([[], [], [], []], self.caught_entries)
1590
1600
def test_add_versions_different_dup(self):
1591
1601
index = self.two_graph_index(deltas=True, catch_adds=True)
1592
1602
# change options
1593
1603
self.assertRaises(errors.KnitCorrupt, index.add_records,
1594
[(('tip',), 'no-eol,line-delta', (None, 0, 100), [('parent',)])])
1595
self.assertRaises(errors.KnitCorrupt, index.add_records,
1596
[(('tip',), 'line-delta,no-eol', (None, 0, 100), [('parent',)])])
1604
[(('tip',), 'line-delta', (None, 0, 100), [('parent',)])])
1597
1605
self.assertRaises(errors.KnitCorrupt, index.add_records,
1598
1606
[(('tip',), 'fulltext', (None, 0, 100), [('parent',)])])
1602
1610
# change options in the second record
1603
1611
self.assertRaises(errors.KnitCorrupt, index.add_records,
1604
1612
[(('tip',), 'fulltext,no-eol', (None, 0, 100), [('parent',)]),
1605
(('tip',), 'no-eol,line-delta', (None, 0, 100), [('parent',)])])
1613
(('tip',), 'line-delta', (None, 0, 100), [('parent',)])])
1606
1614
self.assertEqual([], self.caught_entries)
1616
def make_g_index_missing_compression_parent(self):
1617
graph_index = self.make_g_index('missing_comp', 2,
1618
[(('tip', ), ' 100 78',
1619
([('missing-parent', ), ('ghost', )], [('missing-parent', )]))])
1622
def make_g_index_no_external_refs(self):
1623
graph_index = self.make_g_index('no_external_refs', 2,
1624
[(('rev', ), ' 100 78',
1625
([('parent', ), ('ghost', )], []))])
1628
def test_add_good_unvalidated_index(self):
1629
unvalidated = self.make_g_index_no_external_refs()
1630
combined = CombinedGraphIndex([unvalidated])
1631
index = _KnitGraphIndex(combined, lambda: True, deltas=True)
1632
index.scan_unvalidated_index(unvalidated)
1633
self.assertEqual(frozenset(), index.get_missing_compression_parents())
1635
def test_add_incomplete_unvalidated_index(self):
1636
unvalidated = self.make_g_index_missing_compression_parent()
1637
combined = CombinedGraphIndex([unvalidated])
1638
index = _KnitGraphIndex(combined, lambda: True, deltas=True)
1639
index.scan_unvalidated_index(unvalidated)
1640
# This also checks that its only the compression parent that is
1641
# examined, otherwise 'ghost' would also be reported as a missing
1644
frozenset([('missing-parent',)]),
1645
index.get_missing_compression_parents())
1647
def test_add_unvalidated_index_with_present_external_references(self):
1648
index = self.two_graph_index(deltas=True)
1649
# Ugly hack to get at one of the underlying GraphIndex objects that
1650
# two_graph_index built.
1651
unvalidated = index._graph_index._indices[1]
1652
# 'parent' is an external ref of _indices[1] (unvalidated), but is
1653
# present in _indices[0].
1654
index.scan_unvalidated_index(unvalidated)
1655
self.assertEqual(frozenset(), index.get_missing_compression_parents())
1657
def make_new_missing_parent_g_index(self, name):
1658
missing_parent = name + '-missing-parent'
1659
graph_index = self.make_g_index(name, 2,
1660
[((name + 'tip', ), ' 100 78',
1661
([(missing_parent, ), ('ghost', )], [(missing_parent, )]))])
1664
def test_add_mulitiple_unvalidated_indices_with_missing_parents(self):
1665
g_index_1 = self.make_new_missing_parent_g_index('one')
1666
g_index_2 = self.make_new_missing_parent_g_index('two')
1667
combined = CombinedGraphIndex([g_index_1, g_index_2])
1668
index = _KnitGraphIndex(combined, lambda: True, deltas=True)
1669
index.scan_unvalidated_index(g_index_1)
1670
index.scan_unvalidated_index(g_index_2)
1672
frozenset([('one-missing-parent',), ('two-missing-parent',)]),
1673
index.get_missing_compression_parents())
1675
def test_add_mulitiple_unvalidated_indices_with_mutual_dependencies(self):
1676
graph_index_a = self.make_g_index('one', 2,
1677
[(('parent-one', ), ' 100 78', ([('non-compression-parent',)], [])),
1678
(('child-of-two', ), ' 100 78',
1679
([('parent-two',)], [('parent-two',)]))])
1680
graph_index_b = self.make_g_index('two', 2,
1681
[(('parent-two', ), ' 100 78', ([('non-compression-parent',)], [])),
1682
(('child-of-one', ), ' 100 78',
1683
([('parent-one',)], [('parent-one',)]))])
1684
combined = CombinedGraphIndex([graph_index_a, graph_index_b])
1685
index = _KnitGraphIndex(combined, lambda: True, deltas=True)
1686
index.scan_unvalidated_index(graph_index_a)
1687
index.scan_unvalidated_index(graph_index_b)
1689
frozenset([]), index.get_missing_compression_parents())
1609
1692
class TestNoParentsGraphIndexKnit(KnitTests):
1610
1693
"""Tests for knits using _KnitGraphIndex with no parents."""
2177
2271
self.assertEqual(set([key_left, key_right]), set(last_call[1]))
2178
2272
self.assertEqual('unordered', last_call[2])
2179
2273
self.assertEqual(True, last_call[3])
2276
class TestNetworkBehaviour(KnitTests):
2277
"""Tests for getting data out of/into knits over the network."""
2279
def test_include_delta_closure_generates_a_knit_delta_closure(self):
2280
vf = self.make_test_knit(name='test')
2281
# put in three texts, giving ft, delta, delta
2282
vf.add_lines(('base',), (), ['base\n', 'content\n'])
2283
vf.add_lines(('d1',), (('base',),), ['d1\n'])
2284
vf.add_lines(('d2',), (('d1',),), ['d2\n'])
2285
# But heuristics could interfere, so check what happened:
2286
self.assertEqual(['knit-ft-gz', 'knit-delta-gz', 'knit-delta-gz'],
2287
[record.storage_kind for record in
2288
vf.get_record_stream([('base',), ('d1',), ('d2',)],
2289
'topological', False)])
2290
# generate a stream of just the deltas include_delta_closure=True,
2291
# serialise to the network, and check that we get a delta closure on the wire.
2292
stream = vf.get_record_stream([('d1',), ('d2',)], 'topological', True)
2293
netb = [record.get_bytes_as(record.storage_kind) for record in stream]
2294
# The first bytes should be a memo from _ContentMapGenerator, and the
2295
# second bytes should be empty (because its a API proxy not something
2296
# for wire serialisation.
2297
self.assertEqual('', netb[1])
2299
kind, line_end = network_bytes_to_kind_and_offset(bytes)
2300
self.assertEqual('knit-delta-closure', kind)
2303
class TestContentMapGenerator(KnitTests):
2304
"""Tests for ContentMapGenerator"""
2306
def test_get_record_stream_gives_records(self):
2307
vf = self.make_test_knit(name='test')
2308
# put in three texts, giving ft, delta, delta
2309
vf.add_lines(('base',), (), ['base\n', 'content\n'])
2310
vf.add_lines(('d1',), (('base',),), ['d1\n'])
2311
vf.add_lines(('d2',), (('d1',),), ['d2\n'])
2312
keys = [('d1',), ('d2',)]
2313
generator = _VFContentMapGenerator(vf, keys,
2314
global_map=vf.get_parent_map(keys))
2315
for record in generator.get_record_stream():
2316
if record.key == ('d1',):
2317
self.assertEqual('d1\n', record.get_bytes_as('fulltext'))
2319
self.assertEqual('d2\n', record.get_bytes_as('fulltext'))
2321
def test_get_record_stream_kinds_are_raw(self):
2322
vf = self.make_test_knit(name='test')
2323
# put in three texts, giving ft, delta, delta
2324
vf.add_lines(('base',), (), ['base\n', 'content\n'])
2325
vf.add_lines(('d1',), (('base',),), ['d1\n'])
2326
vf.add_lines(('d2',), (('d1',),), ['d2\n'])
2327
keys = [('base',), ('d1',), ('d2',)]
2328
generator = _VFContentMapGenerator(vf, keys,
2329
global_map=vf.get_parent_map(keys))
2330
kinds = {('base',): 'knit-delta-closure',
2331
('d1',): 'knit-delta-closure-ref',
2332
('d2',): 'knit-delta-closure-ref',
2334
for record in generator.get_record_stream():
2335
self.assertEqual(kinds[record.key], record.storage_kind)