~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test__dirstate_helpers.py

  • Committer: John Arbash Meinel
  • Date: 2008-09-25 22:12:07 UTC
  • mfrom: (3696.4.18 process-entry-optimised)
  • mto: This revision was merged to the branch mainline in revision 3740.
  • Revision ID: john@arbash-meinel.com-20080925221207-nkvw06twhw8gfrsc
Merge in Robert's faster iter-changes code.

Show diffs side-by-side

added added

removed removed

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