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