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