~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test__dirstate_helpers.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-05-21 13:36:51 UTC
  • mfrom: (5243.2.1 readdir_cleanup)
  • Revision ID: pqm@pqm.ubuntu.com-20100521133651-p62dndo2giy5ls21
(lifeless) Some cleanups to the readdir pyrex code for a little efficiency
 and to avoid compile warnings. (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 Canonical Ltd
 
1
# Copyright (C) 2007-2010 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
25
25
    errors,
26
26
    osutils,
27
27
    tests,
28
 
    _dirstate_helpers_py,
29
28
    )
30
29
from bzrlib.tests import (
31
30
    test_dirstate,
32
 
    )
33
 
from bzrlib.tests.test_osutils import dir_reader_scenarios
34
 
from bzrlib.tests.scenarios import (
35
 
    load_tests_apply_scenarios,
36
 
    multiply_scenarios,
37
 
    )
38
 
from bzrlib.tests import (
39
 
    features,
40
 
    )
41
 
 
42
 
 
43
 
load_tests = load_tests_apply_scenarios
44
 
 
45
 
 
46
 
compiled_dirstate_helpers_feature = features.ModuleAvailableFeature(
47
 
    'bzrlib._dirstate_helpers_pyx')
48
 
 
49
 
 
50
 
# FIXME: we should also parametrize against SHA1Provider !
51
 
 
52
 
ue_scenarios = [('dirstate_Python',
53
 
    {'update_entry': dirstate.py_update_entry})]
54
 
if compiled_dirstate_helpers_feature.available():
55
 
    update_entry = compiled_dirstate_helpers_feature.module.update_entry
56
 
    ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
57
 
 
58
 
pe_scenarios = [('dirstate_Python',
59
 
    {'_process_entry': dirstate.ProcessEntryPython})]
60
 
if compiled_dirstate_helpers_feature.available():
61
 
    process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
62
 
    pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
63
 
 
64
 
helper_scenarios = [('dirstate_Python', {'helpers': _dirstate_helpers_py})]
65
 
if compiled_dirstate_helpers_feature.available():
66
 
    helper_scenarios.append(('dirstate_Pyrex',
67
 
        {'helpers': compiled_dirstate_helpers_feature.module}))
 
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
compiled_dirstate_helpers_feature = tests.ModuleAvailableFeature(
 
42
                                'bzrlib._dirstate_helpers_pyx')
 
43
 
 
44
 
 
45
def load_tests(basic_tests, module, loader):
 
46
    # FIXME: we should also parametrize against SHA1Provider !
 
47
    suite = loader.suiteClass()
 
48
    remaining_tests = basic_tests
 
49
 
 
50
    dir_reader_scenarios = test_osutils.dir_reader_scenarios()
 
51
 
 
52
    ue_scenarios = [('dirstate_Python',
 
53
                     {'update_entry': dirstate.py_update_entry})]
 
54
    if compiled_dirstate_helpers_feature.available():
 
55
        update_entry = compiled_dirstate_helpers_feature.module.update_entry
 
56
        pyrex_scenario = ('dirstate_Pyrex', {'update_entry': update_entry})
 
57
        ue_scenarios.append(pyrex_scenario)
 
58
    process_entry_tests, remaining_tests = tests.split_suite_by_condition(
 
59
        remaining_tests, tests.condition_isinstance(TestUpdateEntry))
 
60
    tests.multiply_tests(process_entry_tests,
 
61
                         tests.multiply_scenarios(dir_reader_scenarios,
 
62
                                                  ue_scenarios),
 
63
                         suite)
 
64
 
 
65
    pe_scenarios = [('dirstate_Python',
 
66
                     {'_process_entry': dirstate.ProcessEntryPython})]
 
67
    if compiled_dirstate_helpers_feature.available():
 
68
        process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
 
69
        pyrex_scenario = ('dirstate_Pyrex', {'_process_entry': process_entry})
 
70
        pe_scenarios.append(pyrex_scenario)
 
71
    process_entry_tests, remaining_tests = tests.split_suite_by_condition(
 
72
        remaining_tests, tests.condition_isinstance(TestProcessEntry))
 
73
    tests.multiply_tests(process_entry_tests,
 
74
                         tests.multiply_scenarios(dir_reader_scenarios,
 
75
                                                  pe_scenarios),
 
76
                         suite)
 
77
 
 
78
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
 
79
        remaining_tests, tests.condition_isinstance(
 
80
            test_dirstate.TestCaseWithDirState))
 
81
    tests.multiply_tests(dir_reader_tests, dir_reader_scenarios, suite)
 
82
    suite.addTest(remaining_tests)
 
83
 
 
84
    return suite
68
85
 
69
86
 
70
87
class TestBisectPathMixin(object):
702
719
    implementation.
703
720
    """
704
721
 
705
 
    # inherits scenarios from test_dirstate
706
 
 
707
722
    def get_read_dirblocks(self):
708
723
        from bzrlib._dirstate_helpers_py import _read_dirblocks
709
724
        return _read_dirblocks
722
737
 
723
738
    def test_trailing_garbage(self):
724
739
        tree, state, expected = self.create_basic_dirstate()
725
 
        # On Unix, we can write extra data as long as we haven't read yet, but
 
740
        # On Linux, we can write extra data as long as we haven't read yet, but
726
741
        # on Win32, if you've opened the file with FILE_SHARE_READ, trying to
727
742
        # open it in append mode will fail.
728
743
        state.unlock()
811
826
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
812
827
    """Test the DirState.update_entry functions"""
813
828
 
814
 
    scenarios = multiply_scenarios(
815
 
        dir_reader_scenarios(), ue_scenarios)
816
 
 
817
829
    # Set by load_tests
818
830
    update_entry = None
819
831
 
831
843
 
832
844
    def test_observed_sha1_cachable(self):
833
845
        state, entry = self.get_state_with_a()
834
 
        state.save()
835
846
        atime = time.time() - 10
836
847
        self.build_tree(['a'])
837
 
        statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
838
 
        statvalue.st_mtime = statvalue.st_ctime = atime
839
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
840
 
                         state._dirblock_state)
 
848
        statvalue = os.lstat('a')
 
849
        statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
 
850
            statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
841
851
        state._observed_sha1(entry, "foo", statvalue)
842
852
        self.assertEqual('foo', entry[1][0][1])
843
853
        packed_stat = dirstate.pack_stat(statvalue)
844
854
        self.assertEqual(packed_stat, entry[1][0][4])
845
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
846
 
                         state._dirblock_state)
847
855
 
848
856
    def test_observed_sha1_not_cachable(self):
849
857
        state, entry = self.get_state_with_a()
850
 
        state.save()
851
858
        oldval = entry[1][0][1]
852
859
        oldstat = entry[1][0][4]
853
860
        self.build_tree(['a'])
854
861
        statvalue = os.lstat('a')
855
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
856
 
                         state._dirblock_state)
857
862
        state._observed_sha1(entry, "foo", statvalue)
858
863
        self.assertEqual(oldval, entry[1][0][1])
859
864
        self.assertEqual(oldstat, entry[1][0][4])
860
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
861
 
                         state._dirblock_state)
862
865
 
863
866
    def test_update_entry(self):
864
867
        state, _ = self.get_state_with_a()
889
892
                                          stat_value=stat_value)
890
893
        self.assertEqual(None, link_or_sha1)
891
894
 
892
 
        # The dirblock entry should not have computed or cached the file's
893
 
        # sha1, but it did update the files' st_size. However, this is not
894
 
        # worth writing a dirstate file for, so we leave the state UNMODIFIED
 
895
        # The dirblock entry should not have cached the file's sha1 (too new)
895
896
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
896
897
                         entry[1][0])
897
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
898
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
898
899
                         state._dirblock_state)
899
900
        mode = stat_value.st_mode
900
901
        self.assertEqual([('is_exec', mode, False)], state._log)
903
904
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
904
905
                         state._dirblock_state)
905
906
 
906
 
        # Roll the clock back so the file is guaranteed to look too new. We
907
 
        # should still not compute the sha1.
 
907
        # If we do it again right away, we don't know if the file has changed
 
908
        # so we will re-read the file. Roll the clock back so the file is
 
909
        # guaranteed to look too new.
908
910
        state.adjust_time(-10)
909
911
        del state._log[:]
910
912
 
912
914
                                          stat_value=stat_value)
913
915
        self.assertEqual([('is_exec', mode, False)], state._log)
914
916
        self.assertEqual(None, link_or_sha1)
915
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
917
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
916
918
                         state._dirblock_state)
917
919
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
918
920
                         entry[1][0])
928
930
        self.assertEqual([('is_exec', mode, False)], state._log)
929
931
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
930
932
                         entry[1][0])
931
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
932
 
                         state._dirblock_state)
933
933
 
934
934
        # If the file is no longer new, and the clock has been moved forward
935
935
        # sufficiently, it will cache the sha.
960
960
 
961
961
    def test_update_entry_symlink(self):
962
962
        """Update entry should read symlinks."""
963
 
        self.requireFeature(features.SymlinkFeature)
 
963
        self.requireFeature(tests.SymlinkFeature)
964
964
        state, entry = self.get_state_with_a()
965
965
        state.save()
966
966
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
977
977
        # Dirblock is not updated (the link is too new)
978
978
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
979
979
                         entry[1])
980
 
        # The file entry turned into a symlink, that is considered
981
 
        # HASH modified worthy.
982
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
980
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
983
981
                         state._dirblock_state)
984
982
 
985
983
        # Because the stat_value looks new, we should re-read the target
986
 
        del state._log[:]
987
984
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
988
985
                                          stat_value=stat_value)
989
986
        self.assertEqual('target', link_or_sha1)
990
 
        self.assertEqual([('read_link', 'a', '')], state._log)
 
987
        self.assertEqual([('read_link', 'a', ''),
 
988
                          ('read_link', 'a', ''),
 
989
                         ], state._log)
991
990
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
992
991
                         entry[1])
993
 
        state.save()
994
992
        state.adjust_time(+20) # Skip into the future, all files look old
995
 
        del state._log[:]
996
993
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
997
994
                                          stat_value=stat_value)
998
 
        # The symlink stayed a symlink. So while it is new enough to cache, we
999
 
        # don't bother setting the flag, because it is not really worth saving
1000
 
        # (when we stat the symlink, we'll have paged in the target.)
1001
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1002
 
                         state._dirblock_state)
1003
995
        self.assertEqual('target', link_or_sha1)
1004
996
        # We need to re-read the link because only now can we cache it
1005
 
        self.assertEqual([('read_link', 'a', '')], state._log)
 
997
        self.assertEqual([('read_link', 'a', ''),
 
998
                          ('read_link', 'a', ''),
 
999
                          ('read_link', 'a', ''),
 
1000
                         ], state._log)
1006
1001
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1007
1002
                         entry[1])
1008
1003
 
1009
 
        del state._log[:]
1010
1004
        # Another call won't re-read the link
1011
 
        self.assertEqual([], state._log)
 
1005
        self.assertEqual([('read_link', 'a', ''),
 
1006
                          ('read_link', 'a', ''),
 
1007
                          ('read_link', 'a', ''),
 
1008
                         ], state._log)
1012
1009
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1013
1010
                                          stat_value=stat_value)
1014
1011
        self.assertEqual('target', link_or_sha1)
1029
1026
        self.build_tree(['a/'])
1030
1027
        state.adjust_time(+20)
1031
1028
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1032
 
        # a/ used to be a file, but is now a directory, worth saving
1033
1029
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1034
1030
                         state._dirblock_state)
1035
1031
        state.save()
1036
1032
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1037
1033
                         state._dirblock_state)
1038
 
        # No changes to a/ means not worth saving.
1039
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1040
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1041
 
                         state._dirblock_state)
1042
 
        # Change the last-modified time for the directory
1043
 
        t = time.time() - 100.0
1044
 
        try:
1045
 
            os.utime('a', (t, t))
1046
 
        except OSError:
1047
 
            # It looks like Win32 + FAT doesn't allow to change times on a dir.
1048
 
            raise tests.TestSkipped("can't update mtime of a dir on FAT")
1049
 
        saved_packed_stat = entry[1][0][-1]
1050
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1051
 
        # We *do* go ahead and update the information in the dirblocks, but we
1052
 
        # don't bother setting IN_MEMORY_MODIFIED because it is trivial to
1053
 
        # recompute.
1054
 
        self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
 
1034
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1055
1035
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1056
1036
                         state._dirblock_state)
1057
1037
 
1157
1137
 
1158
1138
    def test_update_file_to_symlink(self):
1159
1139
        """File becomes a symlink"""
1160
 
        self.requireFeature(features.SymlinkFeature)
 
1140
        self.requireFeature(tests.SymlinkFeature)
1161
1141
        state, entry = self.get_state_with_a()
1162
1142
        # The file sha1 won't be cached unless the file is old
1163
1143
        state.adjust_time(+10)
1176
1156
 
1177
1157
    def test_update_dir_to_symlink(self):
1178
1158
        """Directory becomes a symlink"""
1179
 
        self.requireFeature(features.SymlinkFeature)
 
1159
        self.requireFeature(tests.SymlinkFeature)
1180
1160
        state, entry = self.get_state_with_a()
1181
1161
        # The symlink target won't be cached if it isn't old
1182
1162
        state.adjust_time(+10)
1186
1166
 
1187
1167
    def test_update_symlink_to_file(self):
1188
1168
        """Symlink becomes a file"""
1189
 
        self.requireFeature(features.SymlinkFeature)
 
1169
        self.requireFeature(tests.SymlinkFeature)
1190
1170
        state, entry = self.get_state_with_a()
1191
1171
        # The symlink and file info won't be cached unless old
1192
1172
        state.adjust_time(+10)
1196
1176
 
1197
1177
    def test_update_symlink_to_dir(self):
1198
1178
        """Symlink becomes a directory"""
1199
 
        self.requireFeature(features.SymlinkFeature)
 
1179
        self.requireFeature(tests.SymlinkFeature)
1200
1180
        state, entry = self.get_state_with_a()
1201
1181
        # The symlink target won't be cached if it isn't old
1202
1182
        state.adjust_time(+10)
1289
1269
 
1290
1270
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1291
1271
 
1292
 
    scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
1293
 
 
1294
1272
    # Set by load_tests
1295
1273
    _process_entry = None
1296
1274
 
1343
1321
        state._sha1_provider = UppercaseSHA1Provider()
1344
1322
        self.assertChangedFileIds(['file-id'], tree)
1345
1323
 
1346
 
 
1347
 
class TestPackStat(tests.TestCase):
1348
 
    """Check packed representaton of stat values is robust on all inputs"""
1349
 
 
1350
 
    scenarios = helper_scenarios
1351
 
 
1352
 
    def pack(self, statlike_tuple):
1353
 
        return self.helpers.pack_stat(os.stat_result(statlike_tuple))
1354
 
 
1355
 
    @staticmethod
1356
 
    def unpack_field(packed_string, stat_field):
1357
 
        return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
1358
 
 
1359
 
    def test_result(self):
1360
 
        self.assertEqual("AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
1361
 
            self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
1362
 
 
1363
 
    def test_giant_inode(self):
1364
 
        packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
1365
 
        self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
1366
 
 
1367
 
    def test_giant_size(self):
1368
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
1369
 
        self.assertEqual(4096, self.unpack_field(packed, "st_size"))
1370
 
 
1371
 
    def test_fractional_mtime(self):
1372
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
1373
 
        self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
1374
 
 
1375
 
    def test_ancient_mtime(self):
1376
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
1377
 
        self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
1378
 
 
1379
 
    def test_distant_mtime(self):
1380
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
1381
 
        self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
1382
 
 
1383
 
    def test_fractional_ctime(self):
1384
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
1385
 
        self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
1386
 
 
1387
 
    def test_ancient_ctime(self):
1388
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
1389
 
        self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
1390
 
 
1391
 
    def test_distant_ctime(self):
1392
 
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
1393
 
        self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
1394
 
 
1395
 
    def test_negative_dev(self):
1396
 
        packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
1397
 
        self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))