##// END OF EJS Templates
filecache: explicitly test 'repofilecache'...
Pierre-Yves David -
r31284:74cbbd54 default
parent child Browse files
Show More
@@ -1,248 +1,253 b''
1 from __future__ import absolute_import, print_function
1 from __future__ import absolute_import, print_function
2 import os
2 import os
3 import subprocess
3 import subprocess
4 import sys
4 import sys
5
5
6 if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
6 if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
7 'cacheable']):
7 'cacheable']):
8 sys.exit(80)
8 sys.exit(80)
9
9
10 from mercurial import (
10 from mercurial import (
11 extensions,
11 extensions,
12 hg,
12 hg,
13 scmutil,
13 localrepo,
14 ui as uimod,
14 ui as uimod,
15 util,
15 util,
16 vfs as vfsmod,
16 vfs as vfsmod,
17 )
17 )
18
18
19 filecache = scmutil.filecache
20
21 class fakerepo(object):
19 class fakerepo(object):
22 def __init__(self):
20 def __init__(self):
23 self._filecache = {}
21 self._filecache = {}
24
22
25 def join(self, p):
23 class fakevfs(object):
26 return p
24
25 def join(self, p):
26 return p
27
28 vfs = fakevfs()
29
30 def unfiltered(self):
31 return self
27
32
28 def sjoin(self, p):
33 def sjoin(self, p):
29 return p
34 return p
30
35
31 @filecache('x', 'y')
36 @localrepo.repofilecache('x', 'y')
32 def cached(self):
37 def cached(self):
33 print('creating')
38 print('creating')
34 return 'string from function'
39 return 'string from function'
35
40
36 def invalidate(self):
41 def invalidate(self):
37 for k in self._filecache:
42 for k in self._filecache:
38 try:
43 try:
39 delattr(self, k)
44 delattr(self, k)
40 except AttributeError:
45 except AttributeError:
41 pass
46 pass
42
47
43 def basic(repo):
48 def basic(repo):
44 print("* neither file exists")
49 print("* neither file exists")
45 # calls function
50 # calls function
46 repo.cached
51 repo.cached
47
52
48 repo.invalidate()
53 repo.invalidate()
49 print("* neither file still exists")
54 print("* neither file still exists")
50 # uses cache
55 # uses cache
51 repo.cached
56 repo.cached
52
57
53 # create empty file
58 # create empty file
54 f = open('x', 'w')
59 f = open('x', 'w')
55 f.close()
60 f.close()
56 repo.invalidate()
61 repo.invalidate()
57 print("* empty file x created")
62 print("* empty file x created")
58 # should recreate the object
63 # should recreate the object
59 repo.cached
64 repo.cached
60
65
61 f = open('x', 'w')
66 f = open('x', 'w')
62 f.write('a')
67 f.write('a')
63 f.close()
68 f.close()
64 repo.invalidate()
69 repo.invalidate()
65 print("* file x changed size")
70 print("* file x changed size")
66 # should recreate the object
71 # should recreate the object
67 repo.cached
72 repo.cached
68
73
69 repo.invalidate()
74 repo.invalidate()
70 print("* nothing changed with either file")
75 print("* nothing changed with either file")
71 # stats file again, reuses object
76 # stats file again, reuses object
72 repo.cached
77 repo.cached
73
78
74 # atomic replace file, size doesn't change
79 # atomic replace file, size doesn't change
75 # hopefully st_mtime doesn't change as well so this doesn't use the cache
80 # hopefully st_mtime doesn't change as well so this doesn't use the cache
76 # because of inode change
81 # because of inode change
77 f = vfsmod.vfs('.')('x', 'w', atomictemp=True)
82 f = vfsmod.vfs('.')('x', 'w', atomictemp=True)
78 f.write('b')
83 f.write('b')
79 f.close()
84 f.close()
80
85
81 repo.invalidate()
86 repo.invalidate()
82 print("* file x changed inode")
87 print("* file x changed inode")
83 repo.cached
88 repo.cached
84
89
85 # create empty file y
90 # create empty file y
86 f = open('y', 'w')
91 f = open('y', 'w')
87 f.close()
92 f.close()
88 repo.invalidate()
93 repo.invalidate()
89 print("* empty file y created")
94 print("* empty file y created")
90 # should recreate the object
95 # should recreate the object
91 repo.cached
96 repo.cached
92
97
93 f = open('y', 'w')
98 f = open('y', 'w')
94 f.write('A')
99 f.write('A')
95 f.close()
100 f.close()
96 repo.invalidate()
101 repo.invalidate()
97 print("* file y changed size")
102 print("* file y changed size")
98 # should recreate the object
103 # should recreate the object
99 repo.cached
104 repo.cached
100
105
101 f = vfsmod.vfs('.')('y', 'w', atomictemp=True)
106 f = vfsmod.vfs('.')('y', 'w', atomictemp=True)
102 f.write('B')
107 f.write('B')
103 f.close()
108 f.close()
104
109
105 repo.invalidate()
110 repo.invalidate()
106 print("* file y changed inode")
111 print("* file y changed inode")
107 repo.cached
112 repo.cached
108
113
109 f = vfsmod.vfs('.')('x', 'w', atomictemp=True)
114 f = vfsmod.vfs('.')('x', 'w', atomictemp=True)
110 f.write('c')
115 f.write('c')
111 f.close()
116 f.close()
112 f = vfsmod.vfs('.')('y', 'w', atomictemp=True)
117 f = vfsmod.vfs('.')('y', 'w', atomictemp=True)
113 f.write('C')
118 f.write('C')
114 f.close()
119 f.close()
115
120
116 repo.invalidate()
121 repo.invalidate()
117 print("* both files changed inode")
122 print("* both files changed inode")
118 repo.cached
123 repo.cached
119
124
120 def fakeuncacheable():
125 def fakeuncacheable():
121 def wrapcacheable(orig, *args, **kwargs):
126 def wrapcacheable(orig, *args, **kwargs):
122 return False
127 return False
123
128
124 def wrapinit(orig, *args, **kwargs):
129 def wrapinit(orig, *args, **kwargs):
125 pass
130 pass
126
131
127 originit = extensions.wrapfunction(util.cachestat, '__init__', wrapinit)
132 originit = extensions.wrapfunction(util.cachestat, '__init__', wrapinit)
128 origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
133 origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
129 wrapcacheable)
134 wrapcacheable)
130
135
131 for fn in ['x', 'y']:
136 for fn in ['x', 'y']:
132 try:
137 try:
133 os.remove(fn)
138 os.remove(fn)
134 except OSError:
139 except OSError:
135 pass
140 pass
136
141
137 basic(fakerepo())
142 basic(fakerepo())
138
143
139 util.cachestat.cacheable = origcacheable
144 util.cachestat.cacheable = origcacheable
140 util.cachestat.__init__ = originit
145 util.cachestat.__init__ = originit
141
146
142 def test_filecache_synced():
147 def test_filecache_synced():
143 # test old behavior that caused filecached properties to go out of sync
148 # test old behavior that caused filecached properties to go out of sync
144 os.system('hg init && echo a >> a && hg ci -qAm.')
149 os.system('hg init && echo a >> a && hg ci -qAm.')
145 repo = hg.repository(uimod.ui.load())
150 repo = hg.repository(uimod.ui.load())
146 # first rollback clears the filecache, but changelog to stays in __dict__
151 # first rollback clears the filecache, but changelog to stays in __dict__
147 repo.rollback()
152 repo.rollback()
148 repo.commit('.')
153 repo.commit('.')
149 # second rollback comes along and touches the changelog externally
154 # second rollback comes along and touches the changelog externally
150 # (file is moved)
155 # (file is moved)
151 repo.rollback()
156 repo.rollback()
152 # but since changelog isn't under the filecache control anymore, we don't
157 # but since changelog isn't under the filecache control anymore, we don't
153 # see that it changed, and return the old changelog without reconstructing
158 # see that it changed, and return the old changelog without reconstructing
154 # it
159 # it
155 repo.commit('.')
160 repo.commit('.')
156
161
157 def setbeforeget(repo):
162 def setbeforeget(repo):
158 os.remove('x')
163 os.remove('x')
159 os.remove('y')
164 os.remove('y')
160 repo.cached = 'string set externally'
165 repo.cached = 'string set externally'
161 repo.invalidate()
166 repo.invalidate()
162 print("* neither file exists")
167 print("* neither file exists")
163 print(repo.cached)
168 print(repo.cached)
164 repo.invalidate()
169 repo.invalidate()
165 f = open('x', 'w')
170 f = open('x', 'w')
166 f.write('a')
171 f.write('a')
167 f.close()
172 f.close()
168 print("* file x created")
173 print("* file x created")
169 print(repo.cached)
174 print(repo.cached)
170
175
171 repo.cached = 'string 2 set externally'
176 repo.cached = 'string 2 set externally'
172 repo.invalidate()
177 repo.invalidate()
173 print("* string set externally again")
178 print("* string set externally again")
174 print(repo.cached)
179 print(repo.cached)
175
180
176 repo.invalidate()
181 repo.invalidate()
177 f = open('y', 'w')
182 f = open('y', 'w')
178 f.write('b')
183 f.write('b')
179 f.close()
184 f.close()
180 print("* file y created")
185 print("* file y created")
181 print(repo.cached)
186 print(repo.cached)
182
187
183 def antiambiguity():
188 def antiambiguity():
184 filename = 'ambigcheck'
189 filename = 'ambigcheck'
185
190
186 # try some times, because reproduction of ambiguity depends on
191 # try some times, because reproduction of ambiguity depends on
187 # "filesystem time"
192 # "filesystem time"
188 for i in xrange(5):
193 for i in xrange(5):
189 fp = open(filename, 'w')
194 fp = open(filename, 'w')
190 fp.write('FOO')
195 fp.write('FOO')
191 fp.close()
196 fp.close()
192
197
193 oldstat = os.stat(filename)
198 oldstat = os.stat(filename)
194 if oldstat.st_ctime != oldstat.st_mtime:
199 if oldstat.st_ctime != oldstat.st_mtime:
195 # subsequent changing never causes ambiguity
200 # subsequent changing never causes ambiguity
196 continue
201 continue
197
202
198 repetition = 3
203 repetition = 3
199
204
200 # repeat changing via checkambigatclosing, to examine whether
205 # repeat changing via checkambigatclosing, to examine whether
201 # st_mtime is advanced multiple times as expected
206 # st_mtime is advanced multiple times as expected
202 for i in xrange(repetition):
207 for i in xrange(repetition):
203 # explicit closing
208 # explicit closing
204 fp = vfsmod.checkambigatclosing(open(filename, 'a'))
209 fp = vfsmod.checkambigatclosing(open(filename, 'a'))
205 fp.write('FOO')
210 fp.write('FOO')
206 fp.close()
211 fp.close()
207
212
208 # implicit closing by "with" statement
213 # implicit closing by "with" statement
209 with vfsmod.checkambigatclosing(open(filename, 'a')) as fp:
214 with vfsmod.checkambigatclosing(open(filename, 'a')) as fp:
210 fp.write('BAR')
215 fp.write('BAR')
211
216
212 newstat = os.stat(filename)
217 newstat = os.stat(filename)
213 if oldstat.st_ctime != newstat.st_ctime:
218 if oldstat.st_ctime != newstat.st_ctime:
214 # timestamp ambiguity was naturally avoided while repetition
219 # timestamp ambiguity was naturally avoided while repetition
215 continue
220 continue
216
221
217 # st_mtime should be advanced "repetition * 2" times, because
222 # st_mtime should be advanced "repetition * 2" times, because
218 # all changes occurred at same time (in sec)
223 # all changes occurred at same time (in sec)
219 expected = (oldstat.st_mtime + repetition * 2) & 0x7fffffff
224 expected = (oldstat.st_mtime + repetition * 2) & 0x7fffffff
220 if newstat.st_mtime != expected:
225 if newstat.st_mtime != expected:
221 print("'newstat.st_mtime %s is not %s (as %s + %s * 2)" %
226 print("'newstat.st_mtime %s is not %s (as %s + %s * 2)" %
222 (newstat.st_mtime, expected, oldstat.st_mtime, repetition))
227 (newstat.st_mtime, expected, oldstat.st_mtime, repetition))
223
228
224 # no more examination is needed regardless of result
229 # no more examination is needed regardless of result
225 break
230 break
226 else:
231 else:
227 # This platform seems too slow to examine anti-ambiguity
232 # This platform seems too slow to examine anti-ambiguity
228 # of file timestamp (or test happened to be executed at
233 # of file timestamp (or test happened to be executed at
229 # bad timing). Exit silently in this case, because running
234 # bad timing). Exit silently in this case, because running
230 # on other faster platforms can detect problems
235 # on other faster platforms can detect problems
231 pass
236 pass
232
237
233 print('basic:')
238 print('basic:')
234 print()
239 print()
235 basic(fakerepo())
240 basic(fakerepo())
236 print()
241 print()
237 print('fakeuncacheable:')
242 print('fakeuncacheable:')
238 print()
243 print()
239 fakeuncacheable()
244 fakeuncacheable()
240 test_filecache_synced()
245 test_filecache_synced()
241 print()
246 print()
242 print('setbeforeget:')
247 print('setbeforeget:')
243 print()
248 print()
244 setbeforeget(fakerepo())
249 setbeforeget(fakerepo())
245 print()
250 print()
246 print('antiambiguity:')
251 print('antiambiguity:')
247 print()
252 print()
248 antiambiguity()
253 antiambiguity()
General Comments 0
You need to be logged in to leave comments. Login now