1688
1663
self.st_ino = ino
1689
1664
self.st_mode = mode
1693
return _FakeStat(st.st_size, st.st_mtime, st.st_ctime, st.st_dev,
1694
st.st_ino, st.st_mode)
1697
class TestPackStat(tests.TestCaseWithTransport):
1667
class TestUpdateEntry(TestCaseWithDirState):
1668
"""Test the DirState.update_entry functions"""
1670
def get_state_with_a(self):
1671
"""Create a DirState tracking a single object named 'a'"""
1672
state = InstrumentedDirState.initialize('dirstate')
1673
self.addCleanup(state.unlock)
1674
state.add('a', 'a-id', 'file', None, '')
1675
entry = state._get_entry(0, path_utf8='a')
1678
def test_update_entry(self):
1679
state, entry = self.get_state_with_a()
1680
self.build_tree(['a'])
1681
# Add one where we don't provide the stat or sha already
1682
self.assertEqual(('', 'a', 'a-id'), entry[0])
1683
self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1685
# Flush the buffers to disk
1687
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1688
state._dirblock_state)
1690
stat_value = os.lstat('a')
1691
packed_stat = dirstate.pack_stat(stat_value)
1692
link_or_sha1 = state.update_entry(entry, abspath='a',
1693
stat_value=stat_value)
1694
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1697
# The dirblock entry should not cache the file's sha1
1698
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1700
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1701
state._dirblock_state)
1702
mode = stat_value.st_mode
1703
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
1706
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1707
state._dirblock_state)
1709
# If we do it again right away, we don't know if the file has changed
1710
# so we will re-read the file. Roll the clock back so the file is
1711
# guaranteed to look too new.
1712
state.adjust_time(-10)
1714
link_or_sha1 = state.update_entry(entry, abspath='a',
1715
stat_value=stat_value)
1716
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1717
('sha1', 'a'), ('is_exec', mode, False),
1719
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1721
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1722
state._dirblock_state)
1723
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1727
# However, if we move the clock forward so the file is considered
1728
# "stable", it should just cache the value.
1729
state.adjust_time(+20)
1730
link_or_sha1 = state.update_entry(entry, abspath='a',
1731
stat_value=stat_value)
1732
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1734
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1735
('sha1', 'a'), ('is_exec', mode, False),
1736
('sha1', 'a'), ('is_exec', mode, False),
1738
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1741
# Subsequent calls will just return the cached value
1742
link_or_sha1 = state.update_entry(entry, abspath='a',
1743
stat_value=stat_value)
1744
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1746
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1747
('sha1', 'a'), ('is_exec', mode, False),
1748
('sha1', 'a'), ('is_exec', mode, False),
1750
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1753
def test_update_entry_symlink(self):
1754
"""Update entry should read symlinks."""
1755
self.requireFeature(SymlinkFeature)
1756
state, entry = self.get_state_with_a()
1758
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1759
state._dirblock_state)
1760
os.symlink('target', 'a')
1762
state.adjust_time(-10) # Make the symlink look new
1763
stat_value = os.lstat('a')
1764
packed_stat = dirstate.pack_stat(stat_value)
1765
link_or_sha1 = state.update_entry(entry, abspath='a',
1766
stat_value=stat_value)
1767
self.assertEqual('target', link_or_sha1)
1768
self.assertEqual([('read_link', 'a', '')], state._log)
1769
# Dirblock is not updated (the link is too new)
1770
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1772
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1773
state._dirblock_state)
1775
# Because the stat_value looks new, we should re-read the target
1776
link_or_sha1 = state.update_entry(entry, abspath='a',
1777
stat_value=stat_value)
1778
self.assertEqual('target', link_or_sha1)
1779
self.assertEqual([('read_link', 'a', ''),
1780
('read_link', 'a', ''),
1782
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1784
state.adjust_time(+20) # Skip into the future, all files look old
1785
link_or_sha1 = state.update_entry(entry, abspath='a',
1786
stat_value=stat_value)
1787
self.assertEqual('target', link_or_sha1)
1788
# We need to re-read the link because only now can we cache it
1789
self.assertEqual([('read_link', 'a', ''),
1790
('read_link', 'a', ''),
1791
('read_link', 'a', ''),
1793
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1796
# Another call won't re-read the link
1797
self.assertEqual([('read_link', 'a', ''),
1798
('read_link', 'a', ''),
1799
('read_link', 'a', ''),
1801
link_or_sha1 = state.update_entry(entry, abspath='a',
1802
stat_value=stat_value)
1803
self.assertEqual('target', link_or_sha1)
1804
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1807
def do_update_entry(self, state, entry, abspath):
1808
stat_value = os.lstat(abspath)
1809
return state.update_entry(entry, abspath, stat_value)
1811
def test_update_entry_dir(self):
1812
state, entry = self.get_state_with_a()
1813
self.build_tree(['a/'])
1814
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1816
def test_update_entry_dir_unchanged(self):
1817
state, entry = self.get_state_with_a()
1818
self.build_tree(['a/'])
1819
state.adjust_time(+20)
1820
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1821
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1822
state._dirblock_state)
1824
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1825
state._dirblock_state)
1826
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1827
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1828
state._dirblock_state)
1830
def test_update_entry_file_unchanged(self):
1831
state, entry = self.get_state_with_a()
1832
self.build_tree(['a'])
1833
sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1834
state.adjust_time(+20)
1835
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1836
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1837
state._dirblock_state)
1839
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1840
state._dirblock_state)
1841
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1842
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1843
state._dirblock_state)
1845
def create_and_test_file(self, state, entry):
1846
"""Create a file at 'a' and verify the state finds it.
1848
The state should already be versioning *something* at 'a'. This makes
1849
sure that state.update_entry recognizes it as a file.
1851
self.build_tree(['a'])
1852
stat_value = os.lstat('a')
1853
packed_stat = dirstate.pack_stat(stat_value)
1855
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1856
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1858
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1862
def create_and_test_dir(self, state, entry):
1863
"""Create a directory at 'a' and verify the state finds it.
1865
The state should already be versioning *something* at 'a'. This makes
1866
sure that state.update_entry recognizes it as a directory.
1868
self.build_tree(['a/'])
1869
stat_value = os.lstat('a')
1870
packed_stat = dirstate.pack_stat(stat_value)
1872
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1873
self.assertIs(None, link_or_sha1)
1874
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1878
def create_and_test_symlink(self, state, entry):
1879
"""Create a symlink at 'a' and verify the state finds it.
1881
The state should already be versioning *something* at 'a'. This makes
1882
sure that state.update_entry recognizes it as a symlink.
1884
This should not be called if this platform does not have symlink
1887
# caller should care about skipping test on platforms without symlinks
1888
os.symlink('path/to/foo', 'a')
1890
stat_value = os.lstat('a')
1891
packed_stat = dirstate.pack_stat(stat_value)
1893
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1894
self.assertEqual('path/to/foo', link_or_sha1)
1895
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1899
def test_update_file_to_dir(self):
1900
"""If a file changes to a directory we return None for the sha.
1901
We also update the inventory record.
1903
state, entry = self.get_state_with_a()
1904
# The file sha1 won't be cached unless the file is old
1905
state.adjust_time(+10)
1906
self.create_and_test_file(state, entry)
1908
self.create_and_test_dir(state, entry)
1910
def test_update_file_to_symlink(self):
1911
"""File becomes a symlink"""
1912
self.requireFeature(SymlinkFeature)
1913
state, entry = self.get_state_with_a()
1914
# The file sha1 won't be cached unless the file is old
1915
state.adjust_time(+10)
1916
self.create_and_test_file(state, entry)
1918
self.create_and_test_symlink(state, entry)
1920
def test_update_dir_to_file(self):
1921
"""Directory becoming a file updates the entry."""
1922
state, entry = self.get_state_with_a()
1923
# The file sha1 won't be cached unless the file is old
1924
state.adjust_time(+10)
1925
self.create_and_test_dir(state, entry)
1927
self.create_and_test_file(state, entry)
1929
def test_update_dir_to_symlink(self):
1930
"""Directory becomes a symlink"""
1931
self.requireFeature(SymlinkFeature)
1932
state, entry = self.get_state_with_a()
1933
# The symlink target won't be cached if it isn't old
1934
state.adjust_time(+10)
1935
self.create_and_test_dir(state, entry)
1937
self.create_and_test_symlink(state, entry)
1939
def test_update_symlink_to_file(self):
1940
"""Symlink becomes a file"""
1941
self.requireFeature(SymlinkFeature)
1942
state, entry = self.get_state_with_a()
1943
# The symlink and file info won't be cached unless old
1944
state.adjust_time(+10)
1945
self.create_and_test_symlink(state, entry)
1947
self.create_and_test_file(state, entry)
1949
def test_update_symlink_to_dir(self):
1950
"""Symlink becomes a directory"""
1951
self.requireFeature(SymlinkFeature)
1952
state, entry = self.get_state_with_a()
1953
# The symlink target won't be cached if it isn't old
1954
state.adjust_time(+10)
1955
self.create_and_test_symlink(state, entry)
1957
self.create_and_test_dir(state, entry)
1959
def test__is_executable_win32(self):
1960
state, entry = self.get_state_with_a()
1961
self.build_tree(['a'])
1963
# Make sure we are using the win32 implementation of _is_executable
1964
state._is_executable = state._is_executable_win32
1966
# The file on disk is not executable, but we are marking it as though
1967
# it is. With _is_executable_win32 we ignore what is on disk.
1968
entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1970
stat_value = os.lstat('a')
1971
packed_stat = dirstate.pack_stat(stat_value)
1973
state.adjust_time(-10) # Make sure everything is new
1974
state.update_entry(entry, abspath='a', stat_value=stat_value)
1976
# The row is updated, but the executable bit stays set.
1977
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1980
# Make the disk object look old enough to cache
1981
state.adjust_time(+20)
1982
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1983
state.update_entry(entry, abspath='a', stat_value=stat_value)
1984
self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1987
class TestPackStat(TestCaseWithTransport):
1699
1989
def assertPackStat(self, expected, stat_value):
1700
1990
"""Check the packed and serialized form of a stat value."""