~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_hashcache.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-04-07 07:52:50 UTC
  • mfrom: (3340.1.1 208418-1.4)
  • Revision ID: pqm@pqm.ubuntu.com-20080407075250-phs53xnslo8boaeo
Return the correct knit serialisation method in _StreamAccess.
        (Andrew Bennetts, Martin Pool, Robert Collins)

Show diffs side-by-side

added added

removed removed

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