~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_hashcache.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 04:10:52 UTC
  • mfrom: (6616.1.1 fix-en-user-guide)
  • Revision ID: pqm@pqm.ubuntu.com-20160421041052-clcye7ns1qcl2n7w
(richard-wilbur) Ensure build of English use guide always uses English text
 even when user's locale specifies a different language. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# (C) 2005 Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005-2011, 2016 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
 
18
import stat
18
19
import time
19
 
from bzrlib.selftest import TestCaseInTempDir
20
 
 
21
 
 
22
 
 
23
 
def sha1(t):
24
 
    import sha
25
 
    return sha.new(t).hexdigest()
 
20
 
 
21
from bzrlib import osutils
 
22
from bzrlib.errors import BzrError
 
23
from bzrlib.hashcache import HashCache
 
24
from bzrlib.tests import (
 
25
    TestCaseInTempDir,
 
26
    )
 
27
from bzrlib.tests.features import (
 
28
    OsFifoFeature,
 
29
    )
 
30
 
 
31
 
 
32
sha1 = osutils.sha_string
26
33
 
27
34
 
28
35
def pause():
29
 
    if False:
30
 
        return
31
 
    if os.name == 'nt':
32
 
        time.sleep(3)
33
 
        return
34
 
    # allow it to stabilize
35
 
    start = int(time.time())
36
 
    while int(time.time()) == start:
37
 
        time.sleep(0.2)
38
 
    
 
36
    time.sleep(5.0)
 
37
 
39
38
 
40
39
class TestHashCache(TestCaseInTempDir):
41
 
 
42
 
    def test_hashcache(self):
43
 
        """Functional tests for hashcache"""
44
 
        from bzrlib.hashcache import HashCache
45
 
        import os
46
 
 
 
40
    """Test the hashcache against a real directory"""
 
41
 
 
42
    def make_hashcache(self):
47
43
        # make a dummy bzr directory just to hold the cache
48
44
        os.mkdir('.bzr')
49
 
        hc = HashCache('.')
50
 
 
51
 
        file('foo', 'wb').write('hello')
52
 
        os.mkdir('subdir')
53
 
        pause()
54
 
 
55
 
        self.assertEquals(hc.get_sha1('foo'),
56
 
                          'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d')
57
 
        self.assertEquals(hc.miss_count, 1)
58
 
        self.assertEquals(hc.hit_count, 0)
59
 
 
60
 
        # check we hit without re-reading
61
 
        self.assertEquals(hc.get_sha1('foo'),
62
 
                          'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d')
63
 
        ##self.assertEquals(hc.miss_count, 1)
64
 
        ##self.assertEquals(hc.hit_count, 1)
65
 
 
66
 
        # check again without re-reading
67
 
        self.assertEquals(hc.get_sha1('foo'),
68
 
                          'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d')
69
 
        ##self.assertEquals(hc.miss_count, 1)
70
 
        ##self.assertEquals(hc.hit_count, 2)
71
 
 
72
 
        # write new file and make sure it is seen
73
 
        file('foo', 'wb').write('goodbye')
74
 
        pause()
75
 
        self.assertEquals(hc.get_sha1('foo'),
76
 
                          '3c8ec4874488f6090a157b014ce3397ca8e06d4f')
77
 
        ##self.assertEquals(hc.miss_count, 2)
78
 
 
79
 
        # quickly write new file of same size and make sure it is seen
80
 
        # this may rely on detection of timestamps that are too close
81
 
        # together to be safe
82
 
        file('foo', 'wb').write('g00dbye')
83
 
        self.assertEquals(hc.get_sha1('foo'),
84
 
                          sha1('g00dbye'))
85
 
 
86
 
        file('foo2', 'wb').write('other file')
87
 
        self.assertEquals(hc.get_sha1('foo2'), sha1('other file'))
88
 
 
89
 
        os.remove('foo2')
90
 
        self.assertEquals(hc.get_sha1('foo2'), None)
91
 
 
92
 
        file('foo2', 'wb').write('new content')
93
 
        self.assertEquals(hc.get_sha1('foo2'), sha1('new content'))
94
 
 
95
 
        self.assertEquals(hc.get_sha1('subdir'), None)
96
 
 
97
 
        # it's likely neither are cached at the moment because they 
98
 
        # changed recently, but we can't be sure
99
 
        pause()
100
 
 
101
 
        # should now be safe to cache it if we reread them
102
 
        self.assertEquals(hc.get_sha1('foo'), sha1('g00dbye'))
103
 
        ##self.assertEquals(len(hc._cache), 1)
104
 
        self.assertEquals(hc.get_sha1('foo2'), sha1('new content'))
105
 
        ##self.assertEquals(len(hc._cache), 2)
106
 
 
107
 
        # write out, read back in and check that we don't need to
108
 
        # re-read any files
 
45
        hc = HashCache('.', '.bzr/stat-cache')
 
46
        return hc
 
47
 
 
48
    def reopen_hashcache(self):
 
49
        hc = HashCache('.', '.bzr/stat-cache')
 
50
        hc.read()
 
51
        return hc
 
52
 
 
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', 'hello')])
 
57
        self.assertEqual(hc.get_sha1('foo'),
 
58
                          'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d')
 
59
        self.assertEqual(hc.miss_count, 1)
 
60
        self.assertEqual(hc.hit_count, 0)
 
61
 
 
62
    def test_hashcache_new_file(self):
 
63
        hc = self.make_hashcache()
 
64
        self.build_tree_contents([('foo', 'goodbye')])
 
65
        # now read without pausing; it may not be possible to cache it as its
 
66
        # so new
 
67
        self.assertEqual(hc.get_sha1('foo'), sha1('goodbye'))
 
68
 
 
69
    def test_hashcache_nonexistent_file(self):
 
70
        hc = self.make_hashcache()
 
71
        self.assertEqual(hc.get_sha1('no-name-yet'), None)
 
72
 
 
73
    def test_hashcache_replaced_file(self):
 
74
        hc = self.make_hashcache()
 
75
        self.build_tree_contents([('foo', 'goodbye')])
 
76
        self.assertEqual(hc.get_sha1('foo'), sha1('goodbye'))
 
77
        os.remove('foo')
 
78
        self.assertEqual(hc.get_sha1('foo'), None)
 
79
        self.build_tree_contents([('foo', 'new content')])
 
80
        self.assertEqual(hc.get_sha1('foo'), sha1('new content'))
 
81
 
 
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)
 
86
 
 
87
    def test_hashcache_load(self):
 
88
        hc = self.make_hashcache()
 
89
        self.build_tree_contents([('foo', 'contents')])
 
90
        pause()
 
91
        self.assertEqual(hc.get_sha1('foo'), sha1('contents'))
109
92
        hc.write()
110
 
        del hc
111
 
 
112
 
        hc = HashCache('.')
113
 
        hc.read()
114
 
 
115
 
        ##self.assertEquals(len(hc._cache), 2)
116
 
        self.assertEquals(hc.get_sha1('foo'), sha1('g00dbye'))
117
 
        ##self.assertEquals(hc.hit_count, 1)
118
 
        ##self.assertEquals(hc.miss_count, 0)
119
 
        self.assertEquals(hc.get_sha1('foo2'), sha1('new content'))
 
93
        hc = self.reopen_hashcache()
 
94
        self.assertEqual(hc.get_sha1('foo'), sha1('contents'))
 
95
        self.assertEqual(hc.hit_count, 1)
 
96
 
 
97
    def test_hammer_hashcache(self):
 
98
        hc = self.make_hashcache()
 
99
        for i in xrange(10000):
 
100
            self.log('start writing at %s', time.time())
 
101
            f = file('foo', 'w')
 
102
            try:
 
103
                last_content = '%08x' % i
 
104
                f.write(last_content)
 
105
            finally:
 
106
                f.close()
 
107
            last_sha1 = sha1(last_content)
 
108
            self.log("iteration %d: %r -> %r",
 
109
                     i, last_content, last_sha1)
 
110
            got_sha1 = hc.get_sha1('foo')
 
111
            self.assertEqual(got_sha1, last_sha1)
 
112
            hc.write()
 
113
            hc = self.reopen_hashcache()
 
114
 
 
115
    def test_hashcache_raise(self):
 
116
        """check that hashcache can raise BzrError"""
 
117
        self.requireFeature(OsFifoFeature)
 
118
        hc = self.make_hashcache()
 
119
        os.mkfifo('a')
 
120
        # It's possible that the system supports fifos but the filesystem
 
121
        # can't.  In that case we should skip at this point.  But in fact
 
122
        # such combinations don't usually occur for the filesystem where
 
123
        # people test bzr.
 
124
        self.assertRaises(BzrError, hc.get_sha1, 'a')
 
125
 
 
126
 
 
127
class FakeHashCache(HashCache):
 
128
    """Hashcache that consults a fake clock rather than the real one.
 
129
 
 
130
    This lets us examine how old or new files would be handled, without
 
131
    actually having to wait for time to pass.
 
132
    """
 
133
    def __init__(self):
 
134
        # set root and cache file name to none to make sure we won't touch the
 
135
        # real filesystem
 
136
        HashCache.__init__(self, '.', 'hashcache')
 
137
        self._files = {}
 
138
        # simulated clock running forward as operations happen
 
139
        self._clock = 0
 
140
 
 
141
    def put_file(self, filename, file_contents):
 
142
        abspath = './' + filename
 
143
        self._files[abspath] = (file_contents, self._clock)
 
144
 
 
145
    def _fingerprint(self, abspath, fs=None):
 
146
        entry = self._files[abspath]
 
147
        return (len(entry[0]),
 
148
                entry[1], entry[1],
 
149
                10, 20,
 
150
                stat.S_IFREG | 0600)
 
151
 
 
152
    def _really_sha1_file(self, abspath, filters):
 
153
        if abspath in self._files:
 
154
            return sha1(self._files[abspath][0])
 
155
        else:
 
156
            return None
 
157
 
 
158
    def _cutoff_time(self):
 
159
        return self._clock - 2
 
160
 
 
161
    def pretend_to_sleep(self, secs):
 
162
        self._clock += secs
 
163
 
 
164
 
 
165
class TestHashCacheFakeFilesystem(TestCaseInTempDir):
 
166
    """Tests the hashcache using a simulated OS.
 
167
    """
 
168
 
 
169
    def make_hashcache(self):
 
170
        return FakeHashCache()
 
171
 
 
172
    def test_hashcache_miss_new_file(self):
 
173
        """A new file gives the right sha1 but misses"""
 
174
        hc = self.make_hashcache()
 
175
        hc.put_file('foo', 'hello')
 
176
        self.assertEqual(hc.get_sha1('foo'), sha1('hello'))
 
177
        self.assertEqual(hc.miss_count, 1)
 
178
        self.assertEqual(hc.hit_count, 0)
 
179
        # if we try again it's still too new;
 
180
        self.assertEqual(hc.get_sha1('foo'), sha1('hello'))
 
181
        self.assertEqual(hc.miss_count, 2)
 
182
        self.assertEqual(hc.hit_count, 0)
 
183
 
 
184
    def test_hashcache_old_file(self):
 
185
        """An old file gives the right sha1 and hits"""
 
186
        hc = self.make_hashcache()
 
187
        hc.put_file('foo', 'hello')
 
188
        hc.pretend_to_sleep(20)
 
189
        # file is new; should get the correct hash but miss
 
190
        self.assertEqual(hc.get_sha1('foo'), sha1('hello'))
 
191
        self.assertEqual(hc.miss_count, 1)
 
192
        self.assertEqual(hc.hit_count, 0)
 
193
        # and can now be hit
 
194
        self.assertEqual(hc.get_sha1('foo'), sha1('hello'))
 
195
        self.assertEqual(hc.miss_count, 1)
 
196
        self.assertEqual(hc.hit_count, 1)
 
197
        hc.pretend_to_sleep(3)
 
198
        # and again
 
199
        self.assertEqual(hc.get_sha1('foo'), sha1('hello'))
 
200
        self.assertEqual(hc.miss_count, 1)
 
201
        self.assertEqual(hc.hit_count, 2)
 
202
 
 
203
    def test_hashcache_invalidates(self):
 
204
        hc = self.make_hashcache()
 
205
        hc.put_file('foo', 'hello')
 
206
        hc.pretend_to_sleep(20)
 
207
        hc.get_sha1('foo')
 
208
        hc.put_file('foo', 'h1llo')
 
209
        self.assertEqual(hc.get_sha1('foo'), sha1('h1llo'))
 
210
        self.assertEqual(hc.miss_count, 2)
 
211
        self.assertEqual(hc.hit_count, 0)