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