/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_versionedfile.py

  • Committer: John Arbash Meinel
  • Date: 2009-06-12 18:05:15 UTC
  • mto: (4371.4.5 vila-better-heads)
  • mto: This revision was merged to the branch mainline in revision 4449.
  • Revision ID: john@arbash-meinel.com-20090612180515-t0cwbjsnve094oik
Add a failing test for handling nodes that are in the same linear chain.

It fails because the ancestry skipping causes us to miss the fact that the two nodes
are actually directly related. We could check at the beginning, as the 
code used to do, but I think that will be incomplete for the more-than-two
heads cases.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2009 Canonical Ltd
2
2
#
3
3
# Authors:
4
4
#   Johan Rydberg <jrydberg@gnu.org>
26
26
 
27
27
from bzrlib import (
28
28
    errors,
29
 
    graph as _mod_graph,
30
29
    groupcompress,
31
30
    knit as _mod_knit,
32
31
    osutils,
33
32
    progress,
34
 
    ui,
35
33
    )
36
34
from bzrlib.errors import (
37
35
                           RevisionNotPresent,
734
732
        # the ordering here is to make a tree so that dumb searches have
735
733
        # more changes to muck up.
736
734
 
737
 
        class InstrumentedProgress(progress.ProgressTask):
 
735
        class InstrumentedProgress(progress.DummyProgress):
738
736
 
739
737
            def __init__(self):
740
 
                progress.ProgressTask.__init__(self)
 
738
 
 
739
                progress.DummyProgress.__init__(self)
741
740
                self.updates = []
742
741
 
743
742
            def update(self, msg=None, current=None, total=None):
1469
1468
            transport.mkdir('.')
1470
1469
        files = self.factory(transport)
1471
1470
        if self.cleanup is not None:
1472
 
            self.addCleanup(self.cleanup, files)
 
1471
            self.addCleanup(lambda:self.cleanup(files))
1473
1472
        return files
1474
1473
 
1475
 
    def get_simple_key(self, suffix):
1476
 
        """Return a key for the object under test."""
1477
 
        if self.key_length == 1:
1478
 
            return (suffix,)
1479
 
        else:
1480
 
            return ('FileA',) + (suffix,)
1481
 
 
1482
 
    def test_add_lines(self):
1483
 
        f = self.get_versionedfiles()
1484
 
        key0 = self.get_simple_key('r0')
1485
 
        key1 = self.get_simple_key('r1')
1486
 
        key2 = self.get_simple_key('r2')
1487
 
        keyf = self.get_simple_key('foo')
1488
 
        f.add_lines(key0, [], ['a\n', 'b\n'])
1489
 
        if self.graph:
1490
 
            f.add_lines(key1, [key0], ['b\n', 'c\n'])
1491
 
        else:
1492
 
            f.add_lines(key1, [], ['b\n', 'c\n'])
1493
 
        keys = f.keys()
1494
 
        self.assertTrue(key0 in keys)
1495
 
        self.assertTrue(key1 in keys)
1496
 
        records = []
1497
 
        for record in f.get_record_stream([key0, key1], 'unordered', True):
1498
 
            records.append((record.key, record.get_bytes_as('fulltext')))
1499
 
        records.sort()
1500
 
        self.assertEqual([(key0, 'a\nb\n'), (key1, 'b\nc\n')], records)
1501
 
 
1502
 
    def test__add_text(self):
1503
 
        f = self.get_versionedfiles()
1504
 
        key0 = self.get_simple_key('r0')
1505
 
        key1 = self.get_simple_key('r1')
1506
 
        key2 = self.get_simple_key('r2')
1507
 
        keyf = self.get_simple_key('foo')
1508
 
        f._add_text(key0, [], 'a\nb\n')
1509
 
        if self.graph:
1510
 
            f._add_text(key1, [key0], 'b\nc\n')
1511
 
        else:
1512
 
            f._add_text(key1, [], 'b\nc\n')
1513
 
        keys = f.keys()
1514
 
        self.assertTrue(key0 in keys)
1515
 
        self.assertTrue(key1 in keys)
1516
 
        records = []
1517
 
        for record in f.get_record_stream([key0, key1], 'unordered', True):
1518
 
            records.append((record.key, record.get_bytes_as('fulltext')))
1519
 
        records.sort()
1520
 
        self.assertEqual([(key0, 'a\nb\n'), (key1, 'b\nc\n')], records)
1521
 
 
1522
1474
    def test_annotate(self):
1523
1475
        files = self.get_versionedfiles()
1524
1476
        self.get_diamond_files(files)
1558
1510
        self.assertRaises(RevisionNotPresent,
1559
1511
            files.annotate, prefix + ('missing-key',))
1560
1512
 
1561
 
    def test_check_no_parameters(self):
1562
 
        files = self.get_versionedfiles()
1563
 
 
1564
 
    def test_check_progressbar_parameter(self):
1565
 
        """A progress bar can be supplied because check can be a generator."""
1566
 
        pb = ui.ui_factory.nested_progress_bar()
1567
 
        self.addCleanup(pb.finished)
1568
 
        files = self.get_versionedfiles()
1569
 
        files.check(progress_bar=pb)
1570
 
 
1571
 
    def test_check_with_keys_becomes_generator(self):
1572
 
        files = self.get_versionedfiles()
1573
 
        self.get_diamond_files(files)
1574
 
        keys = files.keys()
1575
 
        entries = files.check(keys=keys)
1576
 
        seen = set()
1577
 
        # Texts output should be fulltexts.
1578
 
        self.capture_stream(files, entries, seen.add,
1579
 
            files.get_parent_map(keys), require_fulltext=True)
1580
 
        # All texts should be output.
1581
 
        self.assertEqual(set(keys), seen)
1582
 
 
1583
 
    def test_clear_cache(self):
1584
 
        files = self.get_versionedfiles()
1585
 
        files.clear_cache()
1586
 
 
1587
1513
    def test_construct(self):
1588
1514
        """Each parameterised test can be constructed on a transport."""
1589
1515
        files = self.get_versionedfiles()
1594
1520
            trailing_eol=trailing_eol, nograph=not self.graph,
1595
1521
            left_only=left_only, nokeys=nokeys)
1596
1522
 
1597
 
    def _add_content_nostoresha(self, add_lines):
 
1523
    def test_add_lines_nostoresha(self):
1598
1524
        """When nostore_sha is supplied using old content raises."""
1599
1525
        vf = self.get_versionedfiles()
1600
1526
        empty_text = ('a', [])
1602
1528
        sample_text_no_nl = ('c', ["foo\n", "bar"])
1603
1529
        shas = []
1604
1530
        for version, lines in (empty_text, sample_text_nl, sample_text_no_nl):
1605
 
            if add_lines:
1606
 
                sha, _, _ = vf.add_lines(self.get_simple_key(version), [],
1607
 
                                         lines)
1608
 
            else:
1609
 
                sha, _, _ = vf._add_text(self.get_simple_key(version), [],
1610
 
                                         ''.join(lines))
 
1531
            sha, _, _ = vf.add_lines(self.get_simple_key(version), [], lines)
1611
1532
            shas.append(sha)
1612
1533
        # we now have a copy of all the lines in the vf.
1613
1534
        for sha, (version, lines) in zip(
1616
1537
            self.assertRaises(errors.ExistingContent,
1617
1538
                vf.add_lines, new_key, [], lines,
1618
1539
                nostore_sha=sha)
1619
 
            self.assertRaises(errors.ExistingContent,
1620
 
                vf._add_text, new_key, [], ''.join(lines),
1621
 
                nostore_sha=sha)
1622
1540
            # and no new version should have been added.
1623
1541
            record = vf.get_record_stream([new_key], 'unordered', True).next()
1624
1542
            self.assertEqual('absent', record.storage_kind)
1625
1543
 
1626
 
    def test_add_lines_nostoresha(self):
1627
 
        self._add_content_nostoresha(add_lines=True)
1628
 
 
1629
 
    def test__add_text_nostoresha(self):
1630
 
        self._add_content_nostoresha(add_lines=False)
1631
 
 
1632
1544
    def test_add_lines_return(self):
1633
1545
        files = self.get_versionedfiles()
1634
1546
        # save code by using the stock data insertion helper.
1741
1653
            f.get_record_stream([key_b], 'unordered', True
1742
1654
                ).next().get_bytes_as('fulltext'))
1743
1655
 
1744
 
    def test_get_known_graph_ancestry(self):
1745
 
        f = self.get_versionedfiles()
1746
 
        if not self.graph:
1747
 
            raise TestNotApplicable('ancestry info only relevant with graph.')
1748
 
        key_a = self.get_simple_key('a')
1749
 
        key_b = self.get_simple_key('b')
1750
 
        key_c = self.get_simple_key('c')
1751
 
        # A
1752
 
        # |\
1753
 
        # | B
1754
 
        # |/
1755
 
        # C
1756
 
        f.add_lines(key_a, [], ['\n'])
1757
 
        f.add_lines(key_b, [key_a], ['\n'])
1758
 
        f.add_lines(key_c, [key_a, key_b], ['\n'])
1759
 
        kg = f.get_known_graph_ancestry([key_c])
1760
 
        self.assertIsInstance(kg, _mod_graph.KnownGraph)
1761
 
        self.assertEqual([key_a, key_b, key_c], list(kg.topo_sort()))
1762
 
 
1763
 
    def test_known_graph_with_fallbacks(self):
1764
 
        f = self.get_versionedfiles('files')
1765
 
        if not self.graph:
1766
 
            raise TestNotApplicable('ancestry info only relevant with graph.')
1767
 
        if getattr(f, 'add_fallback_versioned_files', None) is None:
1768
 
            raise TestNotApplicable("%s doesn't support fallbacks"
1769
 
                                    % (f.__class__.__name__,))
1770
 
        key_a = self.get_simple_key('a')
1771
 
        key_b = self.get_simple_key('b')
1772
 
        key_c = self.get_simple_key('c')
1773
 
        # A     only in fallback
1774
 
        # |\
1775
 
        # | B
1776
 
        # |/
1777
 
        # C
1778
 
        g = self.get_versionedfiles('fallback')
1779
 
        g.add_lines(key_a, [], ['\n'])
1780
 
        f.add_fallback_versioned_files(g)
1781
 
        f.add_lines(key_b, [key_a], ['\n'])
1782
 
        f.add_lines(key_c, [key_a, key_b], ['\n'])
1783
 
        kg = f.get_known_graph_ancestry([key_c])
1784
 
        self.assertEqual([key_a, key_b, key_c], list(kg.topo_sort()))
1785
 
 
1786
1656
    def test_get_record_stream_empty(self):
1787
1657
        """An empty stream can be requested without error."""
1788
1658
        f = self.get_versionedfiles()
1799
1669
             'knit-delta-closure', 'knit-delta-closure-ref',
1800
1670
             'groupcompress-block', 'groupcompress-block-ref'])
1801
1671
 
1802
 
    def capture_stream(self, f, entries, on_seen, parents,
1803
 
        require_fulltext=False):
 
1672
    def capture_stream(self, f, entries, on_seen, parents):
1804
1673
        """Capture a stream for testing."""
1805
1674
        for factory in entries:
1806
1675
            on_seen(factory.key)
1811
1680
            self.assertEqual(parents[factory.key], factory.parents)
1812
1681
            self.assertIsInstance(factory.get_bytes_as(factory.storage_kind),
1813
1682
                str)
1814
 
            if require_fulltext:
1815
 
                factory.get_bytes_as('fulltext')
1816
1683
 
1817
1684
    def test_get_record_stream_interface(self):
1818
1685
        """each item in a stream has to provide a regular interface."""
1825
1692
        self.capture_stream(files, entries, seen.add, parent_map)
1826
1693
        self.assertEqual(set(keys), seen)
1827
1694
 
 
1695
    def get_simple_key(self, suffix):
 
1696
        """Return a key for the object under test."""
 
1697
        if self.key_length == 1:
 
1698
            return (suffix,)
 
1699
        else:
 
1700
            return ('FileA',) + (suffix,)
 
1701
 
1828
1702
    def get_keys_and_sort_order(self):
1829
1703
        """Get diamond test keys list, and their sort ordering."""
1830
1704
        if self.key_length == 1:
2193
2067
        else:
2194
2068
            return None
2195
2069
 
2196
 
    def test_get_annotator(self):
2197
 
        files = self.get_versionedfiles()
2198
 
        self.get_diamond_files(files)
2199
 
        origin_key = self.get_simple_key('origin')
2200
 
        base_key = self.get_simple_key('base')
2201
 
        left_key = self.get_simple_key('left')
2202
 
        right_key = self.get_simple_key('right')
2203
 
        merged_key = self.get_simple_key('merged')
2204
 
        # annotator = files.get_annotator()
2205
 
        # introduced full text
2206
 
        origins, lines = files.get_annotator().annotate(origin_key)
2207
 
        self.assertEqual([(origin_key,)], origins)
2208
 
        self.assertEqual(['origin\n'], lines)
2209
 
        # a delta
2210
 
        origins, lines = files.get_annotator().annotate(base_key)
2211
 
        self.assertEqual([(base_key,)], origins)
2212
 
        # a merge
2213
 
        origins, lines = files.get_annotator().annotate(merged_key)
2214
 
        if self.graph:
2215
 
            self.assertEqual([
2216
 
                (base_key,),
2217
 
                (left_key,),
2218
 
                (right_key,),
2219
 
                (merged_key,),
2220
 
                ], origins)
2221
 
        else:
2222
 
            # Without a graph everything is new.
2223
 
            self.assertEqual([
2224
 
                (merged_key,),
2225
 
                (merged_key,),
2226
 
                (merged_key,),
2227
 
                (merged_key,),
2228
 
                ], origins)
2229
 
        self.assertRaises(RevisionNotPresent,
2230
 
            files.get_annotator().annotate, self.get_simple_key('missing-key'))
2231
 
 
2232
2070
    def test_get_parent_map(self):
2233
2071
        files = self.get_versionedfiles()
2234
2072
        if self.key_length == 1:
2437
2275
        else:
2438
2276
            self.assertIdenticalVersionedFile(source, files)
2439
2277
 
2440
 
    def test_insert_record_stream_long_parent_chain_out_of_order(self):
2441
 
        """An out of order stream can either error or work."""
2442
 
        if not self.graph:
2443
 
            raise TestNotApplicable('ancestry info only relevant with graph.')
2444
 
        # Create a reasonably long chain of records based on each other, where
2445
 
        # most will be deltas.
2446
 
        source = self.get_versionedfiles('source')
2447
 
        parents = ()
2448
 
        keys = []
2449
 
        content = [('same same %d\n' % n) for n in range(500)]
2450
 
        for letter in 'abcdefghijklmnopqrstuvwxyz':
2451
 
            key = ('key-' + letter,)
2452
 
            if self.key_length == 2:
2453
 
                key = ('prefix',) + key
2454
 
            content.append('content for ' + letter + '\n')
2455
 
            source.add_lines(key, parents, content)
2456
 
            keys.append(key)
2457
 
            parents = (key,)
2458
 
        # Create a stream of these records, excluding the first record that the
2459
 
        # rest ultimately depend upon, and insert it into a new vf.
2460
 
        streams = []
2461
 
        for key in reversed(keys):
2462
 
            streams.append(source.get_record_stream([key], 'unordered', False))
2463
 
        deltas = chain(*streams[:-1])
2464
 
        files = self.get_versionedfiles()
2465
 
        try:
2466
 
            files.insert_record_stream(deltas)
2467
 
        except RevisionNotPresent:
2468
 
            # Must not have corrupted the file.
2469
 
            files.check()
2470
 
        else:
2471
 
            # Must only report either just the first key as a missing parent,
2472
 
            # no key as missing (for nodelta scenarios).
2473
 
            missing = set(files.get_missing_compression_parent_keys())
2474
 
            missing.discard(keys[0])
2475
 
            self.assertEqual(set(), missing)
2476
 
 
2477
2278
    def get_knit_delta_source(self):
2478
2279
        """Get a source that can produce a stream with knit delta records,
2479
2280
        regardless of this test's scenario.
2547
2348
        # the ordering here is to make a tree so that dumb searches have
2548
2349
        # more changes to muck up.
2549
2350
 
2550
 
        class InstrumentedProgress(progress.ProgressTask):
 
2351
        class InstrumentedProgress(progress.DummyProgress):
2551
2352
 
2552
2353
            def __init__(self):
2553
 
                progress.ProgressTask.__init__(self)
 
2354
 
 
2355
                progress.DummyProgress.__init__(self)
2554
2356
                self.updates = []
2555
2357
 
2556
2358
            def update(self, msg=None, current=None, total=None):
2745
2547
        self.assertRaises(NotImplementedError,
2746
2548
                self.texts.add_mpdiffs, [])
2747
2549
 
2748
 
    def test_check_noerrors(self):
2749
 
        self.texts.check()
 
2550
    def test_check(self):
 
2551
        self.assertTrue(self.texts.check())
2750
2552
 
2751
2553
    def test_insert_record_stream(self):
2752
2554
        self.assertRaises(NotImplementedError, self.texts.insert_record_stream,