~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

  • Committer: John Arbash Meinel
  • Date: 2008-10-30 00:55:00 UTC
  • mto: (3815.2.5 prepare-1.9)
  • mto: This revision was merged to the branch mainline in revision 3811.
  • Revision ID: john@arbash-meinel.com-20081030005500-r5cej1cxflqhs3io
Switch so that we are using a simple timestamp as the first action.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
import bisect
20
20
import os
21
 
import time
22
21
 
23
22
from bzrlib import (
24
23
    dirstate,
25
24
    errors,
 
25
    inventory,
26
26
    osutils,
 
27
    revision as _mod_revision,
27
28
    )
28
29
from bzrlib.memorytree import MemoryTree
29
30
from bzrlib.tests import (
562
563
        state.lock_read()
563
564
        try:
564
565
            entry = state._get_entry(0, path_utf8='a-file')
565
 
            # The current sha1 sum should be empty
566
 
            self.assertEqual('', entry[1][0][1])
 
566
            # The current size should be 0 (default)
 
567
            self.assertEqual(0, entry[1][0][2])
567
568
            # We should have a real entry.
568
569
            self.assertNotEqual((None, None), entry)
569
570
            # Make sure everything is old enough
570
571
            state._sha_cutoff_time()
571
572
            state._cutoff_time += 10
572
 
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
573
 
            # We should have gotten a real sha1
574
 
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
575
 
                             sha1sum)
 
573
            # Change the file length
 
574
            self.build_tree_contents([('a-file', 'shorter')])
 
575
            sha1sum = dirstate.update_entry(state, entry, 'a-file',
 
576
                os.lstat('a-file'))
 
577
            # new file, no cached sha:
 
578
            self.assertEqual(None, sha1sum)
576
579
 
577
580
            # The dirblock has been updated
578
 
            self.assertEqual(sha1sum, entry[1][0][1])
 
581
            self.assertEqual(7, entry[1][0][2])
579
582
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
580
583
                             state._dirblock_state)
581
584
 
591
594
        state.lock_read()
592
595
        try:
593
596
            entry = state._get_entry(0, path_utf8='a-file')
594
 
            self.assertEqual(sha1sum, entry[1][0][1])
 
597
            self.assertEqual(7, entry[1][0][2])
595
598
        finally:
596
599
            state.unlock()
597
600
 
610
613
        state.lock_read()
611
614
        try:
612
615
            entry = state._get_entry(0, path_utf8='a-file')
613
 
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
614
 
            # We should have gotten a real sha1
615
 
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
616
 
                             sha1sum)
 
616
            sha1sum = dirstate.update_entry(state, entry, 'a-file',
 
617
                os.lstat('a-file'))
 
618
            # No sha - too new
 
619
            self.assertEqual(None, sha1sum)
617
620
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
618
621
                             state._dirblock_state)
619
622
 
965
968
            state.set_parent_trees(
966
969
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
967
970
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
968
 
                 ('ghost-rev', tree2.branch.repository.revision_tree(None))),
 
971
                 ('ghost-rev', tree2.branch.repository.revision_tree(
 
972
                                   _mod_revision.NULL_REVISION))),
969
973
                ['ghost-rev'])
970
974
            self.assertEqual([revid1, revid2, 'ghost-rev'],
971
975
                             state.get_parent_ids())
1602
1606
 
1603
1607
        # *really* cheesy way to just get an empty tree
1604
1608
        repo = self.make_repository('repo')
1605
 
        empty_tree = repo.revision_tree(None)
 
1609
        empty_tree = repo.revision_tree(_mod_revision.NULL_REVISION)
1606
1610
        state.set_parent_trees([('null:', empty_tree)], [])
1607
1611
 
1608
1612
        dirblock_names = [d[0] for d in state._dirblocks]
1663
1667
        self.st_mode = mode
1664
1668
 
1665
1669
 
1666
 
class TestUpdateEntry(TestCaseWithDirState):
1667
 
    """Test the DirState.update_entry functions"""
1668
 
 
1669
 
    def get_state_with_a(self):
1670
 
        """Create a DirState tracking a single object named 'a'"""
1671
 
        state = InstrumentedDirState.initialize('dirstate')
1672
 
        self.addCleanup(state.unlock)
1673
 
        state.add('a', 'a-id', 'file', None, '')
1674
 
        entry = state._get_entry(0, path_utf8='a')
1675
 
        return state, entry
1676
 
 
1677
 
    def test_update_entry(self):
1678
 
        state, entry = self.get_state_with_a()
1679
 
        self.build_tree(['a'])
1680
 
        # Add one where we don't provide the stat or sha already
1681
 
        self.assertEqual(('', 'a', 'a-id'), entry[0])
1682
 
        self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1683
 
                         entry[1])
1684
 
        # Flush the buffers to disk
1685
 
        state.save()
1686
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1687
 
                         state._dirblock_state)
1688
 
 
1689
 
        stat_value = os.lstat('a')
1690
 
        packed_stat = dirstate.pack_stat(stat_value)
1691
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1692
 
                                          stat_value=stat_value)
1693
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1694
 
                         link_or_sha1)
1695
 
 
1696
 
        # The dirblock entry should not cache the file's sha1
1697
 
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1698
 
                         entry[1])
1699
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1700
 
                         state._dirblock_state)
1701
 
        mode = stat_value.st_mode
1702
 
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
1703
 
 
1704
 
        state.save()
1705
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1706
 
                         state._dirblock_state)
1707
 
 
1708
 
        # If we do it again right away, we don't know if the file has changed
1709
 
        # so we will re-read the file. Roll the clock back so the file is
1710
 
        # guaranteed to look too new.
1711
 
        state.adjust_time(-10)
1712
 
 
1713
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1714
 
                                          stat_value=stat_value)
1715
 
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1716
 
                          ('sha1', 'a'), ('is_exec', mode, False),
1717
 
                         ], state._log)
1718
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1719
 
                         link_or_sha1)
1720
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1721
 
                         state._dirblock_state)
1722
 
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1723
 
                         entry[1])
1724
 
        state.save()
1725
 
 
1726
 
        # However, if we move the clock forward so the file is considered
1727
 
        # "stable", it should just cache the value.
1728
 
        state.adjust_time(+20)
1729
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1730
 
                                          stat_value=stat_value)
1731
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1732
 
                         link_or_sha1)
1733
 
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1734
 
                          ('sha1', 'a'), ('is_exec', mode, False),
1735
 
                          ('sha1', 'a'), ('is_exec', mode, False),
1736
 
                         ], state._log)
1737
 
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1738
 
                         entry[1])
1739
 
 
1740
 
        # Subsequent calls will just return the cached value
1741
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1742
 
                                          stat_value=stat_value)
1743
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1744
 
                         link_or_sha1)
1745
 
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1746
 
                          ('sha1', 'a'), ('is_exec', mode, False),
1747
 
                          ('sha1', 'a'), ('is_exec', mode, False),
1748
 
                         ], state._log)
1749
 
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1750
 
                         entry[1])
1751
 
 
1752
 
    def test_update_entry_symlink(self):
1753
 
        """Update entry should read symlinks."""
1754
 
        self.requireFeature(SymlinkFeature)
1755
 
        state, entry = self.get_state_with_a()
1756
 
        state.save()
1757
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1758
 
                         state._dirblock_state)
1759
 
        os.symlink('target', 'a')
1760
 
 
1761
 
        state.adjust_time(-10) # Make the symlink look new
1762
 
        stat_value = os.lstat('a')
1763
 
        packed_stat = dirstate.pack_stat(stat_value)
1764
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1765
 
                                          stat_value=stat_value)
1766
 
        self.assertEqual('target', link_or_sha1)
1767
 
        self.assertEqual([('read_link', 'a', '')], state._log)
1768
 
        # Dirblock is not updated (the link is too new)
1769
 
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1770
 
                         entry[1])
1771
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1772
 
                         state._dirblock_state)
1773
 
 
1774
 
        # Because the stat_value looks new, we should re-read the target
1775
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1776
 
                                          stat_value=stat_value)
1777
 
        self.assertEqual('target', link_or_sha1)
1778
 
        self.assertEqual([('read_link', 'a', ''),
1779
 
                          ('read_link', 'a', ''),
1780
 
                         ], state._log)
1781
 
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1782
 
                         entry[1])
1783
 
        state.adjust_time(+20) # Skip into the future, all files look old
1784
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1785
 
                                          stat_value=stat_value)
1786
 
        self.assertEqual('target', link_or_sha1)
1787
 
        # We need to re-read the link because only now can we cache it
1788
 
        self.assertEqual([('read_link', 'a', ''),
1789
 
                          ('read_link', 'a', ''),
1790
 
                          ('read_link', 'a', ''),
1791
 
                         ], state._log)
1792
 
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1793
 
                         entry[1])
1794
 
 
1795
 
        # Another call won't re-read the link
1796
 
        self.assertEqual([('read_link', 'a', ''),
1797
 
                          ('read_link', 'a', ''),
1798
 
                          ('read_link', 'a', ''),
1799
 
                         ], state._log)
1800
 
        link_or_sha1 = state.update_entry(entry, abspath='a',
1801
 
                                          stat_value=stat_value)
1802
 
        self.assertEqual('target', link_or_sha1)
1803
 
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1804
 
                         entry[1])
1805
 
 
1806
 
    def do_update_entry(self, state, entry, abspath):
1807
 
        stat_value = os.lstat(abspath)
1808
 
        return state.update_entry(entry, abspath, stat_value)
1809
 
 
1810
 
    def test_update_entry_dir(self):
1811
 
        state, entry = self.get_state_with_a()
1812
 
        self.build_tree(['a/'])
1813
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1814
 
 
1815
 
    def test_update_entry_dir_unchanged(self):
1816
 
        state, entry = self.get_state_with_a()
1817
 
        self.build_tree(['a/'])
1818
 
        state.adjust_time(+20)
1819
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1820
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1821
 
                         state._dirblock_state)
1822
 
        state.save()
1823
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1824
 
                         state._dirblock_state)
1825
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1826
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1827
 
                         state._dirblock_state)
1828
 
 
1829
 
    def test_update_entry_file_unchanged(self):
1830
 
        state, entry = self.get_state_with_a()
1831
 
        self.build_tree(['a'])
1832
 
        sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1833
 
        state.adjust_time(+20)
1834
 
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1835
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1836
 
                         state._dirblock_state)
1837
 
        state.save()
1838
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1839
 
                         state._dirblock_state)
1840
 
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1841
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1842
 
                         state._dirblock_state)
1843
 
 
1844
 
    def create_and_test_file(self, state, entry):
1845
 
        """Create a file at 'a' and verify the state finds it.
1846
 
 
1847
 
        The state should already be versioning *something* at 'a'. This makes
1848
 
        sure that state.update_entry recognizes it as a file.
1849
 
        """
1850
 
        self.build_tree(['a'])
1851
 
        stat_value = os.lstat('a')
1852
 
        packed_stat = dirstate.pack_stat(stat_value)
1853
 
 
1854
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1855
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1856
 
                         link_or_sha1)
1857
 
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1858
 
                         entry[1])
1859
 
        return packed_stat
1860
 
 
1861
 
    def create_and_test_dir(self, state, entry):
1862
 
        """Create a directory at 'a' and verify the state finds it.
1863
 
 
1864
 
        The state should already be versioning *something* at 'a'. This makes
1865
 
        sure that state.update_entry recognizes it as a directory.
1866
 
        """
1867
 
        self.build_tree(['a/'])
1868
 
        stat_value = os.lstat('a')
1869
 
        packed_stat = dirstate.pack_stat(stat_value)
1870
 
 
1871
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1872
 
        self.assertIs(None, link_or_sha1)
1873
 
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1874
 
 
1875
 
        return packed_stat
1876
 
 
1877
 
    def create_and_test_symlink(self, state, entry):
1878
 
        """Create a symlink at 'a' and verify the state finds it.
1879
 
 
1880
 
        The state should already be versioning *something* at 'a'. This makes
1881
 
        sure that state.update_entry recognizes it as a symlink.
1882
 
 
1883
 
        This should not be called if this platform does not have symlink
1884
 
        support.
1885
 
        """
1886
 
        # caller should care about skipping test on platforms without symlinks
1887
 
        os.symlink('path/to/foo', 'a')
1888
 
 
1889
 
        stat_value = os.lstat('a')
1890
 
        packed_stat = dirstate.pack_stat(stat_value)
1891
 
 
1892
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1893
 
        self.assertEqual('path/to/foo', link_or_sha1)
1894
 
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1895
 
                         entry[1])
1896
 
        return packed_stat
1897
 
 
1898
 
    def test_update_file_to_dir(self):
1899
 
        """If a file changes to a directory we return None for the sha.
1900
 
        We also update the inventory record.
1901
 
        """
1902
 
        state, entry = self.get_state_with_a()
1903
 
        # The file sha1 won't be cached unless the file is old
1904
 
        state.adjust_time(+10)
1905
 
        self.create_and_test_file(state, entry)
1906
 
        os.remove('a')
1907
 
        self.create_and_test_dir(state, entry)
1908
 
 
1909
 
    def test_update_file_to_symlink(self):
1910
 
        """File becomes a symlink"""
1911
 
        self.requireFeature(SymlinkFeature)
1912
 
        state, entry = self.get_state_with_a()
1913
 
        # The file sha1 won't be cached unless the file is old
1914
 
        state.adjust_time(+10)
1915
 
        self.create_and_test_file(state, entry)
1916
 
        os.remove('a')
1917
 
        self.create_and_test_symlink(state, entry)
1918
 
 
1919
 
    def test_update_dir_to_file(self):
1920
 
        """Directory becoming a file updates the entry."""
1921
 
        state, entry = self.get_state_with_a()
1922
 
        # The file sha1 won't be cached unless the file is old
1923
 
        state.adjust_time(+10)
1924
 
        self.create_and_test_dir(state, entry)
1925
 
        os.rmdir('a')
1926
 
        self.create_and_test_file(state, entry)
1927
 
 
1928
 
    def test_update_dir_to_symlink(self):
1929
 
        """Directory becomes a symlink"""
1930
 
        self.requireFeature(SymlinkFeature)
1931
 
        state, entry = self.get_state_with_a()
1932
 
        # The symlink target won't be cached if it isn't old
1933
 
        state.adjust_time(+10)
1934
 
        self.create_and_test_dir(state, entry)
1935
 
        os.rmdir('a')
1936
 
        self.create_and_test_symlink(state, entry)
1937
 
 
1938
 
    def test_update_symlink_to_file(self):
1939
 
        """Symlink becomes a file"""
1940
 
        self.requireFeature(SymlinkFeature)
1941
 
        state, entry = self.get_state_with_a()
1942
 
        # The symlink and file info won't be cached unless old
1943
 
        state.adjust_time(+10)
1944
 
        self.create_and_test_symlink(state, entry)
1945
 
        os.remove('a')
1946
 
        self.create_and_test_file(state, entry)
1947
 
 
1948
 
    def test_update_symlink_to_dir(self):
1949
 
        """Symlink becomes a directory"""
1950
 
        self.requireFeature(SymlinkFeature)
1951
 
        state, entry = self.get_state_with_a()
1952
 
        # The symlink target won't be cached if it isn't old
1953
 
        state.adjust_time(+10)
1954
 
        self.create_and_test_symlink(state, entry)
1955
 
        os.remove('a')
1956
 
        self.create_and_test_dir(state, entry)
1957
 
 
1958
 
    def test__is_executable_win32(self):
1959
 
        state, entry = self.get_state_with_a()
1960
 
        self.build_tree(['a'])
1961
 
 
1962
 
        # Make sure we are using the win32 implementation of _is_executable
1963
 
        state._is_executable = state._is_executable_win32
1964
 
 
1965
 
        # The file on disk is not executable, but we are marking it as though
1966
 
        # it is. With _is_executable_win32 we ignore what is on disk.
1967
 
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1968
 
 
1969
 
        stat_value = os.lstat('a')
1970
 
        packed_stat = dirstate.pack_stat(stat_value)
1971
 
 
1972
 
        state.adjust_time(-10) # Make sure everything is new
1973
 
        state.update_entry(entry, abspath='a', stat_value=stat_value)
1974
 
 
1975
 
        # The row is updated, but the executable bit stays set.
1976
 
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1977
 
                         entry[1])
1978
 
 
1979
 
        # Make the disk object look old enough to cache
1980
 
        state.adjust_time(+20)
1981
 
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1982
 
        state.update_entry(entry, abspath='a', stat_value=stat_value)
1983
 
        self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1984
 
 
1985
 
 
1986
1670
class TestPackStat(TestCaseWithTransport):
1987
1671
 
1988
1672
    def assertPackStat(self, expected, stat_value):
2514
2198
        state._discard_merge_parents()
2515
2199
        state._validate()
2516
2200
        self.assertEqual(exp_dirblocks, state._dirblocks)
 
2201
 
 
2202
 
 
2203
class Test_InvEntryToDetails(TestCaseWithDirState):
 
2204
 
 
2205
    def assertDetails(self, expected, inv_entry):
 
2206
        details = dirstate.DirState._inv_entry_to_details(inv_entry)
 
2207
        self.assertEqual(expected, details)
 
2208
        # details should always allow join() and always be a plain str when
 
2209
        # finished
 
2210
        (minikind, fingerprint, size, executable, tree_data) = details
 
2211
        self.assertIsInstance(minikind, str)
 
2212
        self.assertIsInstance(fingerprint, str)
 
2213
        self.assertIsInstance(tree_data, str)
 
2214
 
 
2215
    def test_unicode_symlink(self):
 
2216
        # In general, the code base doesn't support a target that contains
 
2217
        # non-ascii characters. So we just assert tha 
 
2218
        inv_entry = inventory.InventoryLink('link-file-id', 'name',
 
2219
                                            'link-parent-id')
 
2220
        inv_entry.revision = 'link-revision-id'
 
2221
        inv_entry.symlink_target = u'link-target'
 
2222
        details = self.assertDetails(('l', 'link-target', 0, False,
 
2223
                                      'link-revision-id'), inv_entry)