1667
1663
self.st_mode = mode
1666
class TestUpdateEntry(TestCaseWithDirState):
1667
"""Test the DirState.update_entry functions"""
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')
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)],
1684
# Flush the buffers to disk
1686
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1687
state._dirblock_state)
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',
1696
# The dirblock entry should not cache the file's sha1
1697
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
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)
1705
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1706
state._dirblock_state)
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)
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),
1718
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1720
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1721
state._dirblock_state)
1722
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
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',
1733
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1734
('sha1', 'a'), ('is_exec', mode, False),
1735
('sha1', 'a'), ('is_exec', mode, False),
1737
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
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',
1745
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1746
('sha1', 'a'), ('is_exec', mode, False),
1747
('sha1', 'a'), ('is_exec', mode, False),
1749
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
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()
1757
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1758
state._dirblock_state)
1759
os.symlink('target', 'a')
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)],
1771
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1772
state._dirblock_state)
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', ''),
1781
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
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', ''),
1792
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1795
# Another call won't re-read the link
1796
self.assertEqual([('read_link', 'a', ''),
1797
('read_link', 'a', ''),
1798
('read_link', 'a', ''),
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)],
1806
def do_update_entry(self, state, entry, abspath):
1807
stat_value = os.lstat(abspath)
1808
return state.update_entry(entry, abspath, stat_value)
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'))
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)
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)
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)
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)
1844
def create_and_test_file(self, state, entry):
1845
"""Create a file at 'a' and verify the state finds it.
1847
The state should already be versioning *something* at 'a'. This makes
1848
sure that state.update_entry recognizes it as a file.
1850
self.build_tree(['a'])
1851
stat_value = os.lstat('a')
1852
packed_stat = dirstate.pack_stat(stat_value)
1854
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1855
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1857
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1861
def create_and_test_dir(self, state, entry):
1862
"""Create a directory at 'a' and verify the state finds it.
1864
The state should already be versioning *something* at 'a'. This makes
1865
sure that state.update_entry recognizes it as a directory.
1867
self.build_tree(['a/'])
1868
stat_value = os.lstat('a')
1869
packed_stat = dirstate.pack_stat(stat_value)
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])
1877
def create_and_test_symlink(self, state, entry):
1878
"""Create a symlink at 'a' and verify the state finds it.
1880
The state should already be versioning *something* at 'a'. This makes
1881
sure that state.update_entry recognizes it as a symlink.
1883
This should not be called if this platform does not have symlink
1886
# caller should care about skipping test on platforms without symlinks
1887
os.symlink('path/to/foo', 'a')
1889
stat_value = os.lstat('a')
1890
packed_stat = dirstate.pack_stat(stat_value)
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)],
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.
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)
1907
self.create_and_test_dir(state, entry)
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)
1917
self.create_and_test_symlink(state, entry)
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)
1926
self.create_and_test_file(state, entry)
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)
1936
self.create_and_test_symlink(state, entry)
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)
1946
self.create_and_test_file(state, entry)
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)
1956
self.create_and_test_dir(state, entry)
1958
def test__is_executable_win32(self):
1959
state, entry = self.get_state_with_a()
1960
self.build_tree(['a'])
1962
# Make sure we are using the win32 implementation of _is_executable
1963
state._is_executable = state._is_executable_win32
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)
1969
stat_value = os.lstat('a')
1970
packed_stat = dirstate.pack_stat(stat_value)
1972
state.adjust_time(-10) # Make sure everything is new
1973
state.update_entry(entry, abspath='a', stat_value=stat_value)
1975
# The row is updated, but the executable bit stays set.
1976
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
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])
1670
1986
class TestPackStat(TestCaseWithTransport):
1672
1988
def assertPackStat(self, expected, stat_value):