/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__dirstate_helpers.py

  • Committer: Andrew Bennetts
  • Date: 2008-10-27 06:14:45 UTC
  • mfrom: (3793 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3795.
  • Revision ID: andrew.bennetts@canonical.com-20081027061445-eqt9lz6uw1mbvq4g
Merge from bzr.dev.

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
21
22
 
22
23
from bzrlib import (
23
24
    dirstate,
24
25
    errors,
25
26
    tests,
26
27
    )
 
28
from bzrlib.tests import (
 
29
        SymlinkFeature,
 
30
        )
27
31
from bzrlib.tests import test_dirstate
28
32
 
29
33
 
765
769
            from bzrlib._dirstate_helpers_py import _read_dirblocks_py
766
770
            self.assertIs(_read_dirblocks_py, dirstate._read_dirblocks)
767
771
 
 
772
    def test_update_entry(self):
 
773
        if CompiledDirstateHelpersFeature.available():
 
774
            from bzrlib._dirstate_helpers_c import update_entry
 
775
            self.assertIs(update_entry, dirstate.update_entry)
 
776
        else:
 
777
            from bzrlib.dirstate import py_update_entry
 
778
            self.assertIs(py_update_entry, dirstate.py_update_entry)
 
779
 
 
780
    def test_process_entry(self):
 
781
        if CompiledDirstateHelpersFeature.available():
 
782
            from bzrlib._dirstate_helpers_c import ProcessEntryC
 
783
            self.assertIs(ProcessEntryC, dirstate._process_entry)
 
784
        else:
 
785
            from bzrlib.dirstate import ProcessEntryPython
 
786
            self.assertIs(ProcessEntryPython, dirstate._process_entry)
 
787
 
 
788
 
 
789
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
 
790
    """Test the DirState.update_entry functions"""
 
791
 
 
792
    def get_state_with_a(self):
 
793
        """Create a DirState tracking a single object named 'a'"""
 
794
        state = test_dirstate.InstrumentedDirState.initialize('dirstate')
 
795
        self.addCleanup(state.unlock)
 
796
        state.add('a', 'a-id', 'file', None, '')
 
797
        entry = state._get_entry(0, path_utf8='a')
 
798
        self.set_update_entry()
 
799
        return state, entry
 
800
 
 
801
    def set_update_entry(self):
 
802
        self.update_entry = dirstate.py_update_entry
 
803
 
 
804
    def test_observed_sha1_cachable(self):
 
805
        state, entry = self.get_state_with_a()
 
806
        atime = time.time() - 10
 
807
        self.build_tree(['a'])
 
808
        statvalue = os.lstat('a')
 
809
        statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
 
810
            statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
 
811
        state._observed_sha1(entry, "foo", statvalue)
 
812
        self.assertEqual('foo', entry[1][0][1])
 
813
        packed_stat = dirstate.pack_stat(statvalue)
 
814
        self.assertEqual(packed_stat, entry[1][0][4])
 
815
 
 
816
    def test_observed_sha1_not_cachable(self):
 
817
        state, entry = self.get_state_with_a()
 
818
        oldval = entry[1][0][1]
 
819
        oldstat = entry[1][0][4]
 
820
        self.build_tree(['a'])
 
821
        statvalue = os.lstat('a')
 
822
        state._observed_sha1(entry, "foo", statvalue)
 
823
        self.assertEqual(oldval, entry[1][0][1])
 
824
        self.assertEqual(oldstat, entry[1][0][4])
 
825
 
 
826
    def test_update_entry(self):
 
827
        state, _ = self.get_state_with_a()
 
828
        tree = self.make_branch_and_tree('tree')
 
829
        tree.lock_write()
 
830
        empty_revid = tree.commit('empty')
 
831
        self.build_tree(['tree/a'])
 
832
        tree.add(['a'], ['a-id'])
 
833
        with_a_id = tree.commit('with_a')
 
834
        self.addCleanup(tree.unlock)
 
835
        state.set_parent_trees(
 
836
            [(empty_revid, tree.branch.repository.revision_tree(empty_revid))],
 
837
            [])
 
838
        entry = state._get_entry(0, path_utf8='a')
 
839
        self.build_tree(['a'])
 
840
        # Add one where we don't provide the stat or sha already
 
841
        self.assertEqual(('', 'a', 'a-id'), entry[0])
 
842
        self.assertEqual(('f', '', 0, False, dirstate.DirState.NULLSTAT),
 
843
                         entry[1][0])
 
844
        # Flush the buffers to disk
 
845
        state.save()
 
846
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
847
                         state._dirblock_state)
 
848
 
 
849
        stat_value = os.lstat('a')
 
850
        packed_stat = dirstate.pack_stat(stat_value)
 
851
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
852
                                          stat_value=stat_value)
 
853
        self.assertEqual(None, link_or_sha1)
 
854
 
 
855
        # The dirblock entry should not have cached the file's sha1 (too new)
 
856
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
857
                         entry[1][0])
 
858
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
859
                         state._dirblock_state)
 
860
        mode = stat_value.st_mode
 
861
        self.assertEqual([('is_exec', mode, False)], state._log)
 
862
 
 
863
        state.save()
 
864
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
865
                         state._dirblock_state)
 
866
 
 
867
        # If we do it again right away, we don't know if the file has changed
 
868
        # so we will re-read the file. Roll the clock back so the file is
 
869
        # guaranteed to look too new.
 
870
        state.adjust_time(-10)
 
871
        del state._log[:]
 
872
 
 
873
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
874
                                          stat_value=stat_value)
 
875
        self.assertEqual([('is_exec', mode, False)], state._log)
 
876
        self.assertEqual(None, link_or_sha1)
 
877
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
878
                         state._dirblock_state)
 
879
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
880
                         entry[1][0])
 
881
        state.save()
 
882
 
 
883
        # If it is cachable (the clock has moved forward) but new it still
 
884
        # won't calculate the sha or cache it.
 
885
        state.adjust_time(+20)
 
886
        del state._log[:]
 
887
        link_or_sha1 = dirstate.update_entry(state, entry, abspath='a',
 
888
                                          stat_value=stat_value)
 
889
        self.assertEqual(None, link_or_sha1)
 
890
        self.assertEqual([('is_exec', mode, False)], state._log)
 
891
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
892
                         entry[1][0])
 
893
 
 
894
        # If the file is no longer new, and the clock has been moved forward
 
895
        # sufficiently, it will cache the sha.
 
896
        del state._log[:]
 
897
        state.set_parent_trees(
 
898
            [(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
 
899
            [])
 
900
        entry = state._get_entry(0, path_utf8='a')
 
901
 
 
902
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
903
                                          stat_value=stat_value)
 
904
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
905
                         link_or_sha1)
 
906
        self.assertEqual([('is_exec', mode, False), ('sha1', 'a')],
 
907
                          state._log)
 
908
        self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
 
909
                         entry[1][0])
 
910
 
 
911
        # Subsequent calls will just return the cached value
 
912
        del state._log[:]
 
913
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
914
                                          stat_value=stat_value)
 
915
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
916
                         link_or_sha1)
 
917
        self.assertEqual([], state._log)
 
918
        self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
 
919
                         entry[1][0])
 
920
 
 
921
    def test_update_entry_symlink(self):
 
922
        """Update entry should read symlinks."""
 
923
        self.requireFeature(SymlinkFeature)
 
924
        state, entry = self.get_state_with_a()
 
925
        state.save()
 
926
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
927
                         state._dirblock_state)
 
928
        os.symlink('target', 'a')
 
929
 
 
930
        state.adjust_time(-10) # Make the symlink look new
 
931
        stat_value = os.lstat('a')
 
932
        packed_stat = dirstate.pack_stat(stat_value)
 
933
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
934
                                          stat_value=stat_value)
 
935
        self.assertEqual('target', link_or_sha1)
 
936
        self.assertEqual([('read_link', 'a', '')], state._log)
 
937
        # Dirblock is not updated (the link is too new)
 
938
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
939
                         entry[1])
 
940
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
941
                         state._dirblock_state)
 
942
 
 
943
        # Because the stat_value looks new, we should re-read the target
 
944
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
945
                                          stat_value=stat_value)
 
946
        self.assertEqual('target', link_or_sha1)
 
947
        self.assertEqual([('read_link', 'a', ''),
 
948
                          ('read_link', 'a', ''),
 
949
                         ], state._log)
 
950
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
951
                         entry[1])
 
952
        state.adjust_time(+20) # Skip into the future, all files look old
 
953
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
954
                                          stat_value=stat_value)
 
955
        self.assertEqual('target', link_or_sha1)
 
956
        # We need to re-read the link because only now can we cache it
 
957
        self.assertEqual([('read_link', 'a', ''),
 
958
                          ('read_link', 'a', ''),
 
959
                          ('read_link', 'a', ''),
 
960
                         ], state._log)
 
961
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
962
                         entry[1])
 
963
 
 
964
        # Another call won't re-read the link
 
965
        self.assertEqual([('read_link', 'a', ''),
 
966
                          ('read_link', 'a', ''),
 
967
                          ('read_link', 'a', ''),
 
968
                         ], state._log)
 
969
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
970
                                          stat_value=stat_value)
 
971
        self.assertEqual('target', link_or_sha1)
 
972
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
973
                         entry[1])
 
974
 
 
975
    def do_update_entry(self, state, entry, abspath):
 
976
        stat_value = os.lstat(abspath)
 
977
        return self.update_entry(state, entry, abspath, stat_value)
 
978
 
 
979
    def test_update_entry_dir(self):
 
980
        state, entry = self.get_state_with_a()
 
981
        self.build_tree(['a/'])
 
982
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
983
 
 
984
    def test_update_entry_dir_unchanged(self):
 
985
        state, entry = self.get_state_with_a()
 
986
        self.build_tree(['a/'])
 
987
        state.adjust_time(+20)
 
988
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
989
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
990
                         state._dirblock_state)
 
991
        state.save()
 
992
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
993
                         state._dirblock_state)
 
994
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
995
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
996
                         state._dirblock_state)
 
997
 
 
998
    def test_update_entry_file_unchanged(self):
 
999
        state, _ = self.get_state_with_a()
 
1000
        tree = self.make_branch_and_tree('tree')
 
1001
        tree.lock_write()
 
1002
        self.build_tree(['tree/a'])
 
1003
        tree.add(['a'], ['a-id'])
 
1004
        with_a_id = tree.commit('witha')
 
1005
        self.addCleanup(tree.unlock)
 
1006
        state.set_parent_trees(
 
1007
            [(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
 
1008
            [])
 
1009
        entry = state._get_entry(0, path_utf8='a')
 
1010
        self.build_tree(['a'])
 
1011
        sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1012
        state.adjust_time(+20)
 
1013
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1014
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
1015
                         state._dirblock_state)
 
1016
        state.save()
 
1017
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1018
                         state._dirblock_state)
 
1019
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1020
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1021
                         state._dirblock_state)
 
1022
 
 
1023
    def create_and_test_file(self, state, entry):
 
1024
        """Create a file at 'a' and verify the state finds it during update.
 
1025
 
 
1026
        The state should already be versioning *something* at 'a'. This makes
 
1027
        sure that state.update_entry recognizes it as a file.
 
1028
        """
 
1029
        self.build_tree(['a'])
 
1030
        stat_value = os.lstat('a')
 
1031
        packed_stat = dirstate.pack_stat(stat_value)
 
1032
 
 
1033
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1034
        self.assertEqual(None, link_or_sha1)
 
1035
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
 
1036
                         entry[1])
 
1037
        return packed_stat
 
1038
 
 
1039
    def create_and_test_dir(self, state, entry):
 
1040
        """Create a directory at 'a' and verify the state finds it.
 
1041
 
 
1042
        The state should already be versioning *something* at 'a'. This makes
 
1043
        sure that state.update_entry recognizes it as a directory.
 
1044
        """
 
1045
        self.build_tree(['a/'])
 
1046
        stat_value = os.lstat('a')
 
1047
        packed_stat = dirstate.pack_stat(stat_value)
 
1048
 
 
1049
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1050
        self.assertIs(None, link_or_sha1)
 
1051
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
 
1052
 
 
1053
        return packed_stat
 
1054
 
 
1055
    def create_and_test_symlink(self, state, entry):
 
1056
        """Create a symlink at 'a' and verify the state finds it.
 
1057
 
 
1058
        The state should already be versioning *something* at 'a'. This makes
 
1059
        sure that state.update_entry recognizes it as a symlink.
 
1060
 
 
1061
        This should not be called if this platform does not have symlink
 
1062
        support.
 
1063
        """
 
1064
        # caller should care about skipping test on platforms without symlinks
 
1065
        os.symlink('path/to/foo', 'a')
 
1066
 
 
1067
        stat_value = os.lstat('a')
 
1068
        packed_stat = dirstate.pack_stat(stat_value)
 
1069
 
 
1070
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1071
        self.assertEqual('path/to/foo', link_or_sha1)
 
1072
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
 
1073
                         entry[1])
 
1074
        return packed_stat
 
1075
 
 
1076
    def test_update_file_to_dir(self):
 
1077
        """If a file changes to a directory we return None for the sha.
 
1078
        We also update the inventory record.
 
1079
        """
 
1080
        state, entry = self.get_state_with_a()
 
1081
        # The file sha1 won't be cached unless the file is old
 
1082
        state.adjust_time(+10)
 
1083
        self.create_and_test_file(state, entry)
 
1084
        os.remove('a')
 
1085
        self.create_and_test_dir(state, entry)
 
1086
 
 
1087
    def test_update_file_to_symlink(self):
 
1088
        """File becomes a symlink"""
 
1089
        self.requireFeature(SymlinkFeature)
 
1090
        state, entry = self.get_state_with_a()
 
1091
        # The file sha1 won't be cached unless the file is old
 
1092
        state.adjust_time(+10)
 
1093
        self.create_and_test_file(state, entry)
 
1094
        os.remove('a')
 
1095
        self.create_and_test_symlink(state, entry)
 
1096
 
 
1097
    def test_update_dir_to_file(self):
 
1098
        """Directory becoming a file updates the entry."""
 
1099
        state, entry = self.get_state_with_a()
 
1100
        # The file sha1 won't be cached unless the file is old
 
1101
        state.adjust_time(+10)
 
1102
        self.create_and_test_dir(state, entry)
 
1103
        os.rmdir('a')
 
1104
        self.create_and_test_file(state, entry)
 
1105
 
 
1106
    def test_update_dir_to_symlink(self):
 
1107
        """Directory becomes a symlink"""
 
1108
        self.requireFeature(SymlinkFeature)
 
1109
        state, entry = self.get_state_with_a()
 
1110
        # The symlink target won't be cached if it isn't old
 
1111
        state.adjust_time(+10)
 
1112
        self.create_and_test_dir(state, entry)
 
1113
        os.rmdir('a')
 
1114
        self.create_and_test_symlink(state, entry)
 
1115
 
 
1116
    def test_update_symlink_to_file(self):
 
1117
        """Symlink becomes a file"""
 
1118
        self.requireFeature(SymlinkFeature)
 
1119
        state, entry = self.get_state_with_a()
 
1120
        # The symlink and file info won't be cached unless old
 
1121
        state.adjust_time(+10)
 
1122
        self.create_and_test_symlink(state, entry)
 
1123
        os.remove('a')
 
1124
        self.create_and_test_file(state, entry)
 
1125
 
 
1126
    def test_update_symlink_to_dir(self):
 
1127
        """Symlink becomes a directory"""
 
1128
        self.requireFeature(SymlinkFeature)
 
1129
        state, entry = self.get_state_with_a()
 
1130
        # The symlink target won't be cached if it isn't old
 
1131
        state.adjust_time(+10)
 
1132
        self.create_and_test_symlink(state, entry)
 
1133
        os.remove('a')
 
1134
        self.create_and_test_dir(state, entry)
 
1135
 
 
1136
    def test__is_executable_win32(self):
 
1137
        state, entry = self.get_state_with_a()
 
1138
        self.build_tree(['a'])
 
1139
 
 
1140
        # Make sure we are using the win32 implementation of _is_executable
 
1141
        state._is_executable = state._is_executable_win32
 
1142
 
 
1143
        # The file on disk is not executable, but we are marking it as though
 
1144
        # it is. With _is_executable_win32 we ignore what is on disk.
 
1145
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
 
1146
 
 
1147
        stat_value = os.lstat('a')
 
1148
        packed_stat = dirstate.pack_stat(stat_value)
 
1149
 
 
1150
        state.adjust_time(-10) # Make sure everything is new
 
1151
        self.update_entry(state, entry, abspath='a', stat_value=stat_value)
 
1152
 
 
1153
        # The row is updated, but the executable bit stays set.
 
1154
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
 
1155
                         entry[1])
 
1156
 
 
1157
        # Make the disk object look old enough to cache (but it won't cache the sha
 
1158
        # as it is a new file).
 
1159
        state.adjust_time(+20)
 
1160
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1161
        self.update_entry(state, entry, abspath='a', stat_value=stat_value)
 
1162
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
 
1163
            entry[1])
 
1164
 
 
1165
 
 
1166
class TestCompiledUpdateEntry(TestUpdateEntry):
 
1167
    """Test the pyrex implementation of _read_dirblocks"""
 
1168
 
 
1169
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
1170
 
 
1171
    def set_update_entry(self):
 
1172
        from bzrlib._dirstate_helpers_c import update_entry
 
1173
        self.update_entry = update_entry