1
# Copyright (C) 2005-2011, 2016 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
from .. import osutils
22
from ..errors import BzrError
23
from ..hashcache import HashCache
27
from .features import (
32
sha1 = osutils.sha_string
39
class TestHashCache(TestCaseInTempDir):
40
"""Test the hashcache against a real directory"""
42
def make_hashcache(self):
43
# make a dummy bzr directory just to hold the cache
45
hc = HashCache(u'.', '.bzr/stat-cache')
48
def reopen_hashcache(self):
49
hc = HashCache(u'.', '.bzr/stat-cache')
53
def test_hashcache_initial_miss(self):
54
"""Get correct hash from an empty hashcache"""
55
hc = self.make_hashcache()
56
self.build_tree_contents([('foo', b'hello')])
57
self.assertEqual(hc.get_sha1('foo'),
58
b'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d')
59
self.assertEqual(hc.miss_count, 1)
60
self.assertEqual(hc.hit_count, 0)
62
def test_hashcache_new_file(self):
63
hc = self.make_hashcache()
64
self.build_tree_contents([('foo', b'goodbye')])
65
# now read without pausing; it may not be possible to cache it as its
67
self.assertEqual(hc.get_sha1('foo'), sha1(b'goodbye'))
69
def test_hashcache_nonexistent_file(self):
70
hc = self.make_hashcache()
71
self.assertEqual(hc.get_sha1('no-name-yet'), None)
73
def test_hashcache_replaced_file(self):
74
hc = self.make_hashcache()
75
self.build_tree_contents([('foo', b'goodbye')])
76
self.assertEqual(hc.get_sha1('foo'), sha1(b'goodbye'))
78
self.assertEqual(hc.get_sha1('foo'), None)
79
self.build_tree_contents([('foo', b'new content')])
80
self.assertEqual(hc.get_sha1('foo'), sha1(b'new content'))
82
def test_hashcache_not_file(self):
83
hc = self.make_hashcache()
84
self.build_tree(['subdir/'])
85
self.assertEqual(hc.get_sha1('subdir'), None)
87
def test_hashcache_load(self):
88
hc = self.make_hashcache()
89
self.build_tree_contents([('foo', b'contents')])
91
self.assertEqual(hc.get_sha1('foo'), sha1(b'contents'))
93
hc = self.reopen_hashcache()
94
self.assertEqual(hc.get_sha1('foo'), sha1(b'contents'))
95
self.assertEqual(hc.hit_count, 1)
97
def test_hammer_hashcache(self):
98
hc = self.make_hashcache()
99
for i in range(10000):
100
with open('foo', 'wb') as f:
101
last_content = b'%08x' % i
102
f.write(last_content)
103
last_sha1 = sha1(last_content)
104
self.log("iteration %d: %r -> %r",
105
i, last_content, last_sha1)
106
got_sha1 = hc.get_sha1('foo')
107
self.assertEqual(got_sha1, last_sha1)
109
hc = self.reopen_hashcache()
111
def test_hashcache_raise(self):
112
"""check that hashcache can raise BzrError"""
113
self.requireFeature(OsFifoFeature)
114
hc = self.make_hashcache()
116
# It's possible that the system supports fifos but the filesystem
117
# can't. In that case we should skip at this point. But in fact
118
# such combinations don't usually occur for the filesystem where
120
self.assertRaises(BzrError, hc.get_sha1, 'a')
123
class FakeHashCache(HashCache):
124
"""Hashcache that consults a fake clock rather than the real one.
126
This lets us examine how old or new files would be handled, without
127
actually having to wait for time to pass.
130
# set root and cache file name to none to make sure we won't touch the
132
HashCache.__init__(self, u'.', 'hashcache')
134
# simulated clock running forward as operations happen
137
def put_file(self, filename, file_contents):
138
abspath = './' + filename
139
self._files[abspath] = (file_contents, self._clock)
141
def _fingerprint(self, abspath, fs=None):
142
entry = self._files[abspath]
143
return (len(entry[0]),
146
stat.S_IFREG | 0o600)
148
def _really_sha1_file(self, abspath, filters):
149
if abspath in self._files:
150
return sha1(self._files[abspath][0])
154
def _cutoff_time(self):
155
return self._clock - 2
157
def pretend_to_sleep(self, secs):
161
class TestHashCacheFakeFilesystem(TestCaseInTempDir):
162
"""Tests the hashcache using a simulated OS.
165
def make_hashcache(self):
166
return FakeHashCache()
168
def test_hashcache_miss_new_file(self):
169
"""A new file gives the right sha1 but misses"""
170
hc = self.make_hashcache()
171
hc.put_file('foo', b'hello')
172
self.assertEqual(hc.get_sha1('foo'), sha1(b'hello'))
173
self.assertEqual(hc.miss_count, 1)
174
self.assertEqual(hc.hit_count, 0)
175
# if we try again it's still too new;
176
self.assertEqual(hc.get_sha1('foo'), sha1(b'hello'))
177
self.assertEqual(hc.miss_count, 2)
178
self.assertEqual(hc.hit_count, 0)
180
def test_hashcache_old_file(self):
181
"""An old file gives the right sha1 and hits"""
182
hc = self.make_hashcache()
183
hc.put_file('foo', b'hello')
184
hc.pretend_to_sleep(20)
185
# file is new; should get the correct hash but miss
186
self.assertEqual(hc.get_sha1('foo'), sha1(b'hello'))
187
self.assertEqual(hc.miss_count, 1)
188
self.assertEqual(hc.hit_count, 0)
190
self.assertEqual(hc.get_sha1('foo'), sha1(b'hello'))
191
self.assertEqual(hc.miss_count, 1)
192
self.assertEqual(hc.hit_count, 1)
193
hc.pretend_to_sleep(3)
195
self.assertEqual(hc.get_sha1('foo'), sha1(b'hello'))
196
self.assertEqual(hc.miss_count, 1)
197
self.assertEqual(hc.hit_count, 2)
199
def test_hashcache_invalidates(self):
200
hc = self.make_hashcache()
201
hc.put_file('foo', b'hello')
202
hc.pretend_to_sleep(20)
204
hc.put_file('foo', b'h1llo')
205
self.assertEqual(hc.get_sha1('foo'), sha1(b'h1llo'))
206
self.assertEqual(hc.miss_count, 2)
207
self.assertEqual(hc.hit_count, 0)