~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test__dirstate_helpers.py

  • Committer: INADA Naoki
  • Date: 2011-05-18 06:27:34 UTC
  • mfrom: (5887 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5894.
  • Revision ID: songofacandy@gmail.com-20110518062734-1ilhll0rrqyyp8um
merge from lp:bzr and resolve conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
28
28
    )
29
29
from bzrlib.tests import (
30
30
    test_dirstate,
31
 
    test_osutils,
32
 
    )
33
 
 
34
 
try:
35
 
    from bzrlib import _dirstate_helpers_pyx
36
 
    has_dirstate_helpers_pyx = True
37
 
except ImportError:
38
 
    has_dirstate_helpers_pyx = False
39
 
 
40
 
 
41
 
class _CompiledDirstateHelpersFeature(tests.Feature):
42
 
    def _probe(self):
43
 
        return has_dirstate_helpers_pyx
44
 
 
45
 
    def feature_name(self):
46
 
        return 'bzrlib._dirstate_helpers_pyx'
47
 
CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
48
 
 
49
 
 
50
 
def load_tests(basic_tests, module, loader):
51
 
    # FIXME: we should also parametrize against SHA1Provider !
52
 
    suite = loader.suiteClass()
53
 
    remaining_tests = basic_tests
54
 
 
55
 
    dir_reader_scenarios = test_osutils.dir_reader_scenarios()
56
 
 
57
 
    ue_scenarios = [('dirstate_Python',
58
 
                     {'update_entry': dirstate.py_update_entry})]
59
 
    if has_dirstate_helpers_pyx:
60
 
        pyrex_scenario = ('dirstate_Pyrex',
61
 
                          {'update_entry': _dirstate_helpers_pyx.update_entry})
62
 
        ue_scenarios.append(pyrex_scenario)
63
 
    process_entry_tests, remaining_tests = tests.split_suite_by_condition(
64
 
        remaining_tests, tests.condition_isinstance(TestUpdateEntry))
65
 
    tests.multiply_tests(process_entry_tests,
66
 
                         tests.multiply_scenarios(dir_reader_scenarios,
67
 
                                                  ue_scenarios),
68
 
                         suite)
69
 
 
70
 
    pe_scenarios = [('dirstate_Python',
71
 
                     {'_process_entry': dirstate.ProcessEntryPython})]
72
 
    if has_dirstate_helpers_pyx:
73
 
        pyrex_scenario = (
74
 
            'dirstate_Pyrex',
75
 
            {'_process_entry': _dirstate_helpers_pyx.ProcessEntryC})
76
 
        pe_scenarios.append(pyrex_scenario)
77
 
    process_entry_tests, remaining_tests = tests.split_suite_by_condition(
78
 
        remaining_tests, tests.condition_isinstance(TestProcessEntry))
79
 
    tests.multiply_tests(process_entry_tests,
80
 
                         tests.multiply_scenarios(dir_reader_scenarios,
81
 
                                                  pe_scenarios),
82
 
                         suite)
83
 
 
84
 
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
85
 
        remaining_tests, tests.condition_isinstance(
86
 
            test_dirstate.TestCaseWithDirState))
87
 
    tests.multiply_tests(dir_reader_tests, dir_reader_scenarios, suite)
88
 
    suite.addTest(remaining_tests)
89
 
 
90
 
    return suite
 
31
    )
 
32
from bzrlib.tests.test_osutils import dir_reader_scenarios
 
33
from bzrlib.tests.scenarios import (
 
34
    load_tests_apply_scenarios,
 
35
    multiply_scenarios,
 
36
    )
 
37
 
 
38
 
 
39
load_tests = load_tests_apply_scenarios
 
40
 
 
41
 
 
42
compiled_dirstate_helpers_feature = tests.ModuleAvailableFeature(
 
43
    'bzrlib._dirstate_helpers_pyx')
 
44
 
 
45
 
 
46
# FIXME: we should also parametrize against SHA1Provider !
 
47
 
 
48
ue_scenarios = [('dirstate_Python',
 
49
    {'update_entry': dirstate.py_update_entry})]
 
50
if compiled_dirstate_helpers_feature.available():
 
51
    update_entry = compiled_dirstate_helpers_feature.module.update_entry
 
52
    ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
 
53
 
 
54
pe_scenarios = [('dirstate_Python',
 
55
    {'_process_entry': dirstate.ProcessEntryPython})]
 
56
if compiled_dirstate_helpers_feature.available():
 
57
    process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
 
58
    pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
91
59
 
92
60
 
93
61
class TestBisectPathMixin(object):
259
227
class TestCompiledBisectPathLeft(TestBisectPathLeft):
260
228
    """Run all Bisect Path tests against _bisect_path_lect"""
261
229
 
262
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
230
    _test_needs_features = [compiled_dirstate_helpers_feature]
263
231
 
264
232
    def get_bisect_path(self):
265
233
        from bzrlib._dirstate_helpers_pyx import _bisect_path_left
280
248
class TestCompiledBisectPathRight(TestBisectPathRight):
281
249
    """Run all Bisect Path tests against _bisect_path_right"""
282
250
 
283
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
251
    _test_needs_features = [compiled_dirstate_helpers_feature]
284
252
 
285
253
    def get_bisect_path(self):
286
254
        from bzrlib._dirstate_helpers_pyx import _bisect_path_right
392
360
    compiled version.
393
361
    """
394
362
 
395
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
363
    _test_needs_features = [compiled_dirstate_helpers_feature]
396
364
 
397
365
    def get_bisect_dirblock(self):
398
366
        from bzrlib._dirstate_helpers_pyx import bisect_dirblock
514
482
class TestCompiledCmpByDirs(TestCmpByDirs):
515
483
    """Test the pyrex implementation of cmp_by_dirs"""
516
484
 
517
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
485
    _test_needs_features = [compiled_dirstate_helpers_feature]
518
486
 
519
487
    def get_cmp_by_dirs(self):
520
488
        from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
665
633
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
666
634
    """Test the pyrex implementation of _cmp_path_by_dirblock"""
667
635
 
668
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
636
    _test_needs_features = [compiled_dirstate_helpers_feature]
669
637
 
670
638
    def get_cmp_by_dirs(self):
671
639
        from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
675
643
class TestMemRChr(tests.TestCase):
676
644
    """Test memrchr functionality"""
677
645
 
678
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
646
    _test_needs_features = [compiled_dirstate_helpers_feature]
679
647
 
680
648
    def assertMemRChr(self, expected, s, c):
681
649
        from bzrlib._dirstate_helpers_pyx import _py_memrchr
725
693
    implementation.
726
694
    """
727
695
 
 
696
    # inherits scenarios from test_dirstate
 
697
 
728
698
    def get_read_dirblocks(self):
729
699
        from bzrlib._dirstate_helpers_py import _read_dirblocks
730
700
        return _read_dirblocks
743
713
 
744
714
    def test_trailing_garbage(self):
745
715
        tree, state, expected = self.create_basic_dirstate()
746
 
        # We can modify the file as long as it hasn't been read yet.
 
716
        # On Unix, we can write extra data as long as we haven't read yet, but
 
717
        # on Win32, if you've opened the file with FILE_SHARE_READ, trying to
 
718
        # open it in append mode will fail.
 
719
        state.unlock()
747
720
        f = open('dirstate', 'ab')
748
721
        try:
749
722
            # Add bogus trailing garbage
750
723
            f.write('bogus\n')
751
724
        finally:
752
725
            f.close()
 
726
            state.lock_read()
753
727
        e = self.assertRaises(errors.DirstateCorrupt,
754
728
                              state._read_dirblocks_if_needed)
755
729
        # Make sure we mention the bogus characters in the error
759
733
class TestCompiledReadDirblocks(TestReadDirblocks):
760
734
    """Test the pyrex implementation of _read_dirblocks"""
761
735
 
762
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
736
    _test_needs_features = [compiled_dirstate_helpers_feature]
763
737
 
764
738
    def get_read_dirblocks(self):
765
739
        from bzrlib._dirstate_helpers_pyx import _read_dirblocks
775
749
    """
776
750
 
777
751
    def test_bisect_dirblock(self):
778
 
        if CompiledDirstateHelpersFeature.available():
 
752
        if compiled_dirstate_helpers_feature.available():
779
753
            from bzrlib._dirstate_helpers_pyx import bisect_dirblock
780
754
        else:
781
755
            from bzrlib._dirstate_helpers_py import bisect_dirblock
782
756
        self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
783
757
 
784
758
    def test__bisect_path_left(self):
785
 
        if CompiledDirstateHelpersFeature.available():
 
759
        if compiled_dirstate_helpers_feature.available():
786
760
            from bzrlib._dirstate_helpers_pyx import _bisect_path_left
787
761
        else:
788
762
            from bzrlib._dirstate_helpers_py import _bisect_path_left
789
763
        self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
790
764
 
791
765
    def test__bisect_path_right(self):
792
 
        if CompiledDirstateHelpersFeature.available():
 
766
        if compiled_dirstate_helpers_feature.available():
793
767
            from bzrlib._dirstate_helpers_pyx import _bisect_path_right
794
768
        else:
795
769
            from bzrlib._dirstate_helpers_py import _bisect_path_right
796
770
        self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
797
771
 
798
772
    def test_cmp_by_dirs(self):
799
 
        if CompiledDirstateHelpersFeature.available():
 
773
        if compiled_dirstate_helpers_feature.available():
800
774
            from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
801
775
        else:
802
776
            from bzrlib._dirstate_helpers_py import cmp_by_dirs
803
777
        self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
804
778
 
805
779
    def test__read_dirblocks(self):
806
 
        if CompiledDirstateHelpersFeature.available():
 
780
        if compiled_dirstate_helpers_feature.available():
807
781
            from bzrlib._dirstate_helpers_pyx import _read_dirblocks
808
782
        else:
809
783
            from bzrlib._dirstate_helpers_py import _read_dirblocks
810
784
        self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
811
785
 
812
786
    def test_update_entry(self):
813
 
        if CompiledDirstateHelpersFeature.available():
 
787
        if compiled_dirstate_helpers_feature.available():
814
788
            from bzrlib._dirstate_helpers_pyx import update_entry
815
789
        else:
816
790
            from bzrlib.dirstate import update_entry
817
791
        self.assertIs(update_entry, dirstate.update_entry)
818
792
 
819
793
    def test_process_entry(self):
820
 
        if CompiledDirstateHelpersFeature.available():
 
794
        if compiled_dirstate_helpers_feature.available():
821
795
            from bzrlib._dirstate_helpers_pyx import ProcessEntryC
822
796
            self.assertIs(ProcessEntryC, dirstate._process_entry)
823
797
        else:
828
802
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
829
803
    """Test the DirState.update_entry functions"""
830
804
 
 
805
    scenarios = multiply_scenarios(
 
806
        dir_reader_scenarios(), ue_scenarios)
 
807
 
831
808
    # Set by load_tests
832
809
    update_entry = None
833
810
 
834
811
    def setUp(self):
835
812
        super(TestUpdateEntry, self).setUp()
836
 
        orig = dirstate.update_entry
837
 
        def cleanup():
838
 
            dirstate.update_entry = orig
839
 
        self.addCleanup(cleanup)
840
 
        dirstate.update_entry = self.update_entry
 
813
        self.overrideAttr(dirstate, 'update_entry', self.update_entry)
841
814
 
842
815
    def get_state_with_a(self):
843
816
        """Create a DirState tracking a single object named 'a'"""
849
822
 
850
823
    def test_observed_sha1_cachable(self):
851
824
        state, entry = self.get_state_with_a()
 
825
        state.save()
852
826
        atime = time.time() - 10
853
827
        self.build_tree(['a'])
854
 
        statvalue = os.lstat('a')
855
 
        statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
856
 
            statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
 
828
        statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
 
829
        statvalue.st_mtime = statvalue.st_ctime = atime
 
830
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
831
                         state._dirblock_state)
857
832
        state._observed_sha1(entry, "foo", statvalue)
858
833
        self.assertEqual('foo', entry[1][0][1])
859
834
        packed_stat = dirstate.pack_stat(statvalue)
860
835
        self.assertEqual(packed_stat, entry[1][0][4])
 
836
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
837
                         state._dirblock_state)
861
838
 
862
839
    def test_observed_sha1_not_cachable(self):
863
840
        state, entry = self.get_state_with_a()
 
841
        state.save()
864
842
        oldval = entry[1][0][1]
865
843
        oldstat = entry[1][0][4]
866
844
        self.build_tree(['a'])
867
845
        statvalue = os.lstat('a')
 
846
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
847
                         state._dirblock_state)
868
848
        state._observed_sha1(entry, "foo", statvalue)
869
849
        self.assertEqual(oldval, entry[1][0][1])
870
850
        self.assertEqual(oldstat, entry[1][0][4])
 
851
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
852
                         state._dirblock_state)
871
853
 
872
854
    def test_update_entry(self):
873
855
        state, _ = self.get_state_with_a()
898
880
                                          stat_value=stat_value)
899
881
        self.assertEqual(None, link_or_sha1)
900
882
 
901
 
        # The dirblock entry should not have cached the file's sha1 (too new)
 
883
        # The dirblock entry should not have computed or cached the file's
 
884
        # sha1, but it did update the files' st_size. However, this is not
 
885
        # worth writing a dirstate file for, so we leave the state UNMODIFIED
902
886
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
903
887
                         entry[1][0])
904
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
888
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
905
889
                         state._dirblock_state)
906
890
        mode = stat_value.st_mode
907
891
        self.assertEqual([('is_exec', mode, False)], state._log)
910
894
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
911
895
                         state._dirblock_state)
912
896
 
913
 
        # If we do it again right away, we don't know if the file has changed
914
 
        # so we will re-read the file. Roll the clock back so the file is
915
 
        # guaranteed to look too new.
 
897
        # Roll the clock back so the file is guaranteed to look too new. We
 
898
        # should still not compute the sha1.
916
899
        state.adjust_time(-10)
917
900
        del state._log[:]
918
901
 
920
903
                                          stat_value=stat_value)
921
904
        self.assertEqual([('is_exec', mode, False)], state._log)
922
905
        self.assertEqual(None, link_or_sha1)
923
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
906
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
924
907
                         state._dirblock_state)
925
908
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
926
909
                         entry[1][0])
936
919
        self.assertEqual([('is_exec', mode, False)], state._log)
937
920
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
938
921
                         entry[1][0])
 
922
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
923
                         state._dirblock_state)
939
924
 
940
925
        # If the file is no longer new, and the clock has been moved forward
941
926
        # sufficiently, it will cache the sha.
983
968
        # Dirblock is not updated (the link is too new)
984
969
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
985
970
                         entry[1])
986
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
971
        # The file entry turned into a symlink, that is considered
 
972
        # HASH modified worthy.
 
973
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
987
974
                         state._dirblock_state)
988
975
 
989
976
        # Because the stat_value looks new, we should re-read the target
 
977
        del state._log[:]
990
978
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
991
979
                                          stat_value=stat_value)
992
980
        self.assertEqual('target', link_or_sha1)
993
 
        self.assertEqual([('read_link', 'a', ''),
994
 
                          ('read_link', 'a', ''),
995
 
                         ], state._log)
 
981
        self.assertEqual([('read_link', 'a', '')], state._log)
996
982
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
997
983
                         entry[1])
 
984
        state.save()
998
985
        state.adjust_time(+20) # Skip into the future, all files look old
 
986
        del state._log[:]
999
987
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1000
988
                                          stat_value=stat_value)
 
989
        # The symlink stayed a symlink. So while it is new enough to cache, we
 
990
        # don't bother setting the flag, because it is not really worth saving
 
991
        # (when we stat the symlink, we'll have paged in the target.)
 
992
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
993
                         state._dirblock_state)
1001
994
        self.assertEqual('target', link_or_sha1)
1002
995
        # We need to re-read the link because only now can we cache it
1003
 
        self.assertEqual([('read_link', 'a', ''),
1004
 
                          ('read_link', 'a', ''),
1005
 
                          ('read_link', 'a', ''),
1006
 
                         ], state._log)
 
996
        self.assertEqual([('read_link', 'a', '')], state._log)
1007
997
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1008
998
                         entry[1])
1009
999
 
 
1000
        del state._log[:]
1010
1001
        # Another call won't re-read the link
1011
 
        self.assertEqual([('read_link', 'a', ''),
1012
 
                          ('read_link', 'a', ''),
1013
 
                          ('read_link', 'a', ''),
1014
 
                         ], state._log)
 
1002
        self.assertEqual([], state._log)
1015
1003
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1016
1004
                                          stat_value=stat_value)
1017
1005
        self.assertEqual('target', link_or_sha1)
1032
1020
        self.build_tree(['a/'])
1033
1021
        state.adjust_time(+20)
1034
1022
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1023
        # a/ used to be a file, but is now a directory, worth saving
1035
1024
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1036
1025
                         state._dirblock_state)
1037
1026
        state.save()
1038
1027
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1039
1028
                         state._dirblock_state)
1040
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1029
        # No changes to a/ means not worth saving.
 
1030
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1031
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1032
                         state._dirblock_state)
 
1033
        # Change the last-modified time for the directory
 
1034
        t = time.time() - 100.0
 
1035
        try:
 
1036
            os.utime('a', (t, t))
 
1037
        except OSError:
 
1038
            # It looks like Win32 + FAT doesn't allow to change times on a dir.
 
1039
            raise tests.TestSkipped("can't update mtime of a dir on FAT")
 
1040
        saved_packed_stat = entry[1][0][-1]
 
1041
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1042
        # We *do* go ahead and update the information in the dirblocks, but we
 
1043
        # don't bother setting IN_MEMORY_MODIFIED because it is trivial to
 
1044
        # recompute.
 
1045
        self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
1041
1046
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1042
1047
                         state._dirblock_state)
1043
1048
 
1275
1280
 
1276
1281
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1277
1282
 
 
1283
    scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
 
1284
 
1278
1285
    # Set by load_tests
1279
1286
    _process_entry = None
1280
1287
 
1281
1288
    def setUp(self):
1282
1289
        super(TestProcessEntry, self).setUp()
1283
 
        orig = dirstate._process_entry
1284
 
        def cleanup():
1285
 
            dirstate._process_entry = orig
1286
 
        self.addCleanup(cleanup)
1287
 
        dirstate._process_entry = self._process_entry
 
1290
        self.overrideAttr(dirstate, '_process_entry', self._process_entry)
1288
1291
 
1289
1292
    def assertChangedFileIds(self, expected, tree):
1290
1293
        tree.lock_read()
1295
1298
            tree.unlock()
1296
1299
        self.assertEqual(sorted(expected), sorted(file_ids))
1297
1300
 
 
1301
    def test_exceptions_raised(self):
 
1302
        # This is a direct test of bug #495023, it relies on osutils.is_inside
 
1303
        # getting called in an inner function. Which makes it a bit brittle,
 
1304
        # but at least it does reproduce the bug.
 
1305
        tree = self.make_branch_and_tree('tree')
 
1306
        self.build_tree(['tree/file', 'tree/dir/', 'tree/dir/sub',
 
1307
                         'tree/dir2/', 'tree/dir2/sub2'])
 
1308
        tree.add(['file', 'dir', 'dir/sub', 'dir2', 'dir2/sub2'])
 
1309
        tree.commit('first commit')
 
1310
        tree.lock_read()
 
1311
        self.addCleanup(tree.unlock)
 
1312
        basis_tree = tree.basis_tree()
 
1313
        def is_inside_raises(*args, **kwargs):
 
1314
            raise RuntimeError('stop this')
 
1315
        self.overrideAttr(osutils, 'is_inside', is_inside_raises)
 
1316
        self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
 
1317
 
1298
1318
    def test_simple_changes(self):
1299
1319
        tree = self.make_branch_and_tree('tree')
1300
1320
        self.build_tree(['tree/file'])