29
29
from bzrlib.tests import (
32
from bzrlib.tests.test_osutils import dir_reader_scenarios
33
from bzrlib.tests.scenarios import (
34
load_tests_apply_scenarios,
37
from bzrlib.tests import (
42
load_tests = load_tests_apply_scenarios
45
compiled_dirstate_helpers_feature = features.ModuleAvailableFeature(
46
'bzrlib._dirstate_helpers_pyx')
49
# FIXME: we should also parametrize against SHA1Provider !
51
ue_scenarios = [('dirstate_Python',
52
{'update_entry': dirstate.py_update_entry})]
53
if compiled_dirstate_helpers_feature.available():
54
update_entry = compiled_dirstate_helpers_feature.module.update_entry
55
ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
57
pe_scenarios = [('dirstate_Python',
58
{'_process_entry': dirstate.ProcessEntryPython})]
59
if compiled_dirstate_helpers_feature.available():
60
process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
61
pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
35
from bzrlib import _dirstate_helpers_pyx
36
has_dirstate_helpers_pyx = True
38
has_dirstate_helpers_pyx = False
41
class _CompiledDirstateHelpersFeature(tests.Feature):
43
return has_dirstate_helpers_pyx
45
def feature_name(self):
46
return 'bzrlib._dirstate_helpers_pyx'
47
CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
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
55
dir_reader_scenarios = test_osutils.dir_reader_scenarios()
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,
70
pe_scenarios = [('dirstate_Python',
71
{'_process_entry': dirstate.ProcessEntryPython})]
72
if has_dirstate_helpers_pyx:
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,
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)
64
93
class TestBisectPathMixin(object):
754
781
def test_bisect_dirblock(self):
755
if compiled_dirstate_helpers_feature.available():
782
if CompiledDirstateHelpersFeature.available():
756
783
from bzrlib._dirstate_helpers_pyx import bisect_dirblock
758
785
from bzrlib._dirstate_helpers_py import bisect_dirblock
759
786
self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
761
788
def test__bisect_path_left(self):
762
if compiled_dirstate_helpers_feature.available():
789
if CompiledDirstateHelpersFeature.available():
763
790
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
765
792
from bzrlib._dirstate_helpers_py import _bisect_path_left
766
793
self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
768
795
def test__bisect_path_right(self):
769
if compiled_dirstate_helpers_feature.available():
796
if CompiledDirstateHelpersFeature.available():
770
797
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
772
799
from bzrlib._dirstate_helpers_py import _bisect_path_right
773
800
self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
775
802
def test_cmp_by_dirs(self):
776
if compiled_dirstate_helpers_feature.available():
803
if CompiledDirstateHelpersFeature.available():
777
804
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
779
806
from bzrlib._dirstate_helpers_py import cmp_by_dirs
780
807
self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
782
809
def test__read_dirblocks(self):
783
if compiled_dirstate_helpers_feature.available():
810
if CompiledDirstateHelpersFeature.available():
784
811
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
786
813
from bzrlib._dirstate_helpers_py import _read_dirblocks
787
814
self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
789
816
def test_update_entry(self):
790
if compiled_dirstate_helpers_feature.available():
817
if CompiledDirstateHelpersFeature.available():
791
818
from bzrlib._dirstate_helpers_pyx import update_entry
793
820
from bzrlib.dirstate import update_entry
794
821
self.assertIs(update_entry, dirstate.update_entry)
796
823
def test_process_entry(self):
797
if compiled_dirstate_helpers_feature.available():
824
if CompiledDirstateHelpersFeature.available():
798
825
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
799
826
self.assertIs(ProcessEntryC, dirstate._process_entry)
805
832
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
806
833
"""Test the DirState.update_entry functions"""
808
scenarios = multiply_scenarios(
809
dir_reader_scenarios(), ue_scenarios)
811
835
# Set by load_tests
812
836
update_entry = None
815
839
super(TestUpdateEntry, self).setUp()
816
self.overrideAttr(dirstate, 'update_entry', self.update_entry)
840
orig = dirstate.update_entry
842
dirstate.update_entry = orig
843
self.addCleanup(cleanup)
844
dirstate.update_entry = self.update_entry
818
846
def get_state_with_a(self):
819
847
"""Create a DirState tracking a single object named 'a'"""
826
854
def test_observed_sha1_cachable(self):
827
855
state, entry = self.get_state_with_a()
829
856
atime = time.time() - 10
830
857
self.build_tree(['a'])
831
statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
832
statvalue.st_mtime = statvalue.st_ctime = atime
833
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
834
state._dirblock_state)
858
statvalue = os.lstat('a')
859
statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
860
statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
835
861
state._observed_sha1(entry, "foo", statvalue)
836
862
self.assertEqual('foo', entry[1][0][1])
837
863
packed_stat = dirstate.pack_stat(statvalue)
838
864
self.assertEqual(packed_stat, entry[1][0][4])
839
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
840
state._dirblock_state)
842
866
def test_observed_sha1_not_cachable(self):
843
867
state, entry = self.get_state_with_a()
845
868
oldval = entry[1][0][1]
846
869
oldstat = entry[1][0][4]
847
870
self.build_tree(['a'])
848
871
statvalue = os.lstat('a')
849
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
850
state._dirblock_state)
851
872
state._observed_sha1(entry, "foo", statvalue)
852
873
self.assertEqual(oldval, entry[1][0][1])
853
874
self.assertEqual(oldstat, entry[1][0][4])
854
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
855
state._dirblock_state)
857
876
def test_update_entry(self):
858
877
state, _ = self.get_state_with_a()
883
902
stat_value=stat_value)
884
903
self.assertEqual(None, link_or_sha1)
886
# The dirblock entry should not have computed or cached the file's
887
# sha1, but it did update the files' st_size. However, this is not
888
# worth writing a dirstate file for, so we leave the state UNMODIFIED
905
# The dirblock entry should not have cached the file's sha1 (too new)
889
906
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
891
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
908
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
892
909
state._dirblock_state)
893
910
mode = stat_value.st_mode
894
911
self.assertEqual([('is_exec', mode, False)], state._log)
971
987
# Dirblock is not updated (the link is too new)
972
988
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
974
# The file entry turned into a symlink, that is considered
975
# HASH modified worthy.
976
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
990
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
977
991
state._dirblock_state)
979
993
# Because the stat_value looks new, we should re-read the target
981
994
link_or_sha1 = self.update_entry(state, entry, abspath='a',
982
995
stat_value=stat_value)
983
996
self.assertEqual('target', link_or_sha1)
984
self.assertEqual([('read_link', 'a', '')], state._log)
997
self.assertEqual([('read_link', 'a', ''),
998
('read_link', 'a', ''),
985
1000
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
988
1002
state.adjust_time(+20) # Skip into the future, all files look old
990
1003
link_or_sha1 = self.update_entry(state, entry, abspath='a',
991
1004
stat_value=stat_value)
992
# The symlink stayed a symlink. So while it is new enough to cache, we
993
# don't bother setting the flag, because it is not really worth saving
994
# (when we stat the symlink, we'll have paged in the target.)
995
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
996
state._dirblock_state)
997
1005
self.assertEqual('target', link_or_sha1)
998
1006
# We need to re-read the link because only now can we cache it
999
self.assertEqual([('read_link', 'a', '')], state._log)
1007
self.assertEqual([('read_link', 'a', ''),
1008
('read_link', 'a', ''),
1009
('read_link', 'a', ''),
1000
1011
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1004
1014
# Another call won't re-read the link
1005
self.assertEqual([], state._log)
1015
self.assertEqual([('read_link', 'a', ''),
1016
('read_link', 'a', ''),
1017
('read_link', 'a', ''),
1006
1019
link_or_sha1 = self.update_entry(state, entry, abspath='a',
1007
1020
stat_value=stat_value)
1008
1021
self.assertEqual('target', link_or_sha1)
1023
1036
self.build_tree(['a/'])
1024
1037
state.adjust_time(+20)
1025
1038
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1026
# a/ used to be a file, but is now a directory, worth saving
1027
1039
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1028
1040
state._dirblock_state)
1030
1042
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1031
1043
state._dirblock_state)
1032
# No changes to a/ means not worth saving.
1033
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1034
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1035
state._dirblock_state)
1036
# Change the last-modified time for the directory
1037
t = time.time() - 100.0
1039
os.utime('a', (t, t))
1041
# It looks like Win32 + FAT doesn't allow to change times on a dir.
1042
raise tests.TestSkipped("can't update mtime of a dir on FAT")
1043
saved_packed_stat = entry[1][0][-1]
1044
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1045
# We *do* go ahead and update the information in the dirblocks, but we
1046
# don't bother setting IN_MEMORY_MODIFIED because it is trivial to
1048
self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
1044
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1049
1045
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1050
1046
state._dirblock_state)
1284
1280
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1286
scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
1288
1282
# Set by load_tests
1289
1283
_process_entry = None
1291
1285
def setUp(self):
1292
1286
super(TestProcessEntry, self).setUp()
1293
self.overrideAttr(dirstate, '_process_entry', self._process_entry)
1287
orig = dirstate._process_entry
1289
dirstate._process_entry = orig
1290
self.addCleanup(cleanup)
1291
dirstate._process_entry = self._process_entry
1295
1293
def assertChangedFileIds(self, expected, tree):
1296
1294
tree.lock_read()
1302
1300
self.assertEqual(sorted(expected), sorted(file_ids))
1304
def test_exceptions_raised(self):
1305
# This is a direct test of bug #495023, it relies on osutils.is_inside
1306
# getting called in an inner function. Which makes it a bit brittle,
1307
# but at least it does reproduce the bug.
1308
tree = self.make_branch_and_tree('tree')
1309
self.build_tree(['tree/file', 'tree/dir/', 'tree/dir/sub',
1310
'tree/dir2/', 'tree/dir2/sub2'])
1311
tree.add(['file', 'dir', 'dir/sub', 'dir2', 'dir2/sub2'])
1312
tree.commit('first commit')
1314
self.addCleanup(tree.unlock)
1315
basis_tree = tree.basis_tree()
1316
def is_inside_raises(*args, **kwargs):
1317
raise RuntimeError('stop this')
1318
self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1319
self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1321
1302
def test_simple_changes(self):
1322
1303
tree = self.make_branch_and_tree('tree')
1323
1304
self.build_tree(['tree/file'])