~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/branch_implementations/test_revision_history.py

  • Committer: Robert Collins
  • Date: 2007-07-04 08:08:13 UTC
  • mfrom: (2572 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2587.
  • Revision ID: robertc@robertcollins.net-20070704080813-wzebx0r88fvwj5rq
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Tests for Branch.revision_history."""
 
18
 
 
19
from bzrlib import branch
 
20
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
 
21
 
 
22
 
 
23
class TestRevisionHistoryCaching(TestCaseWithBranch):
 
24
    """Tests for the caching of branches' revision_history.
 
25
 
 
26
    When locked, branches should avoid regenerating or rereading
 
27
    revision_history by caching the last value of it.  This is safe because
 
28
    the branch is locked, so nothing can change the revision_history
 
29
    unexpectedly.
 
30
 
 
31
    When not locked, obviously the revision_history will need to be regenerated
 
32
    or reread each time.
 
33
 
 
34
    We test if revision_history is using the cache by instrumenting the branch's
 
35
    _gen_revision_history method, which is called by Branch.revision_history if
 
36
    the branch does not have a cache of the revision history.
 
37
    """
 
38
 
 
39
    def get_instrumented_branch(self):
 
40
        """Get a branch and monkey patch it to log calls to
 
41
        _gen_revision_history.
 
42
 
 
43
        :returns: a tuple of (the branch, list that calls will be logged to)
 
44
        """
 
45
        branch = self.get_branch()
 
46
        calls = []
 
47
        real_gen_revision_history = branch._gen_revision_history
 
48
        def fake_gen_revision_history():
 
49
            calls.append('_gen_revision_history')
 
50
            return real_gen_revision_history()
 
51
        branch._gen_revision_history = fake_gen_revision_history
 
52
        return branch, calls
 
53
 
 
54
    def test_revision_history_when_unlocked(self):
 
55
        """Repeated calls to revision history will call _gen_revision_history
 
56
        each time when the branch is not locked.
 
57
        """
 
58
        branch, calls = self.get_instrumented_branch()
 
59
        # Repeatedly call revision_history.
 
60
        branch.revision_history()
 
61
        branch.revision_history()
 
62
        self.assertEqual(
 
63
            ['_gen_revision_history', '_gen_revision_history'], calls)
 
64
 
 
65
    def test_revision_history_when_locked(self):
 
66
        """Repeated calls to revision history will only call
 
67
        _gen_revision_history once while the branch is locked.
 
68
        """
 
69
        branch, calls = self.get_instrumented_branch()
 
70
        # Lock the branch, then repeatedly call revision_history.
 
71
        branch.lock_read()
 
72
        try:
 
73
            branch.revision_history()
 
74
            branch.revision_history()
 
75
            self.assertEqual(['_gen_revision_history'], calls)
 
76
        finally:
 
77
            branch.unlock()
 
78
 
 
79
    def test_set_revision_history_when_locked(self):
 
80
        """When the branch is locked, calling set_revision_history should cache
 
81
        the revision history so that a later call to revision_history will not
 
82
        need to call _gen_revision_history.
 
83
        """
 
84
        branch, calls = self.get_instrumented_branch()
 
85
        # Lock the branch, set the revision history, then repeatedly call
 
86
        # revision_history.
 
87
        branch.lock_write()
 
88
        branch.set_revision_history([])
 
89
        try:
 
90
            branch.revision_history()
 
91
            self.assertEqual([], calls)
 
92
        finally:
 
93
            branch.unlock()
 
94
 
 
95
    def test_set_revision_history_when_unlocked(self):
 
96
        """When the branch is not locked, calling set_revision_history will not
 
97
        cause the revision history to be cached.
 
98
        """
 
99
        branch, calls = self.get_instrumented_branch()
 
100
        # Lock the branch, set the revision history, then repeatedly call
 
101
        # revision_history.
 
102
        branch.set_revision_history([])
 
103
        branch.revision_history()
 
104
        self.assertEqual(['_gen_revision_history'], calls)
 
105
 
 
106
    def test_set_last_revision_info_when_locked(self):
 
107
        """When the branch is locked, calling set_last_revision_info should
 
108
        cache the last revision info so that a later call to last_revision_info
 
109
        will not need the revision_history.  Thus the branch will not to call
 
110
        _gen_revision_history in this situation.
 
111
        """
 
112
        a_branch, calls = self.get_instrumented_branch()
 
113
        # Lock the branch, set the last revision info, then call
 
114
        # last_revision_info.
 
115
        a_branch.lock_write()
 
116
        a_branch.set_last_revision_info(0, None)
 
117
        del calls[:]
 
118
        try:
 
119
            a_branch.last_revision_info()
 
120
            self.assertEqual([], calls)
 
121
        finally:
 
122
            a_branch.unlock()
 
123
 
 
124
    def test_set_last_revision_info_uncaches_revision_history_for_format6(self):
 
125
        """On format 6 branches, set_last_revision_info invalidates the revision
 
126
        history cache.
 
127
        """
 
128
        if not isinstance(self.branch_format, branch.BzrBranchFormat6):
 
129
            return
 
130
        a_branch, calls = self.get_instrumented_branch()
 
131
        # Lock the branch, cache the revision history.
 
132
        a_branch.lock_write()
 
133
        a_branch.revision_history()
 
134
        # Set the last revision info, clearing the cache.
 
135
        a_branch.set_last_revision_info(0, None)
 
136
        del calls[:]
 
137
        try:
 
138
            a_branch.revision_history()
 
139
            self.assertEqual(['_gen_revision_history'], calls)
 
140
        finally:
 
141
            a_branch.unlock()
 
142
 
 
143
    def test_cached_revision_history_not_accidentally_mutable(self):
 
144
        """When there's a cached version of the history, revision_history
 
145
        returns a copy of the cached data so that callers cannot accidentally
 
146
        corrupt the cache.
 
147
        """
 
148
        branch = self.get_branch()
 
149
        # Lock the branch, then repeatedly call revision_history, mutating the
 
150
        # results.
 
151
        branch.lock_read()
 
152
        try:
 
153
            # The first time the data returned will not be in the cache.
 
154
            history = branch.revision_history()
 
155
            history.append('one')
 
156
            # The second time the data comes from the cache.
 
157
            history = branch.revision_history()
 
158
            history.append('two')
 
159
            # The revision_history() should still be unchanged, even though
 
160
            # we've mutated the return values from earlier calls.
 
161
            self.assertEqual([], branch.revision_history())
 
162
        finally:
 
163
            branch.unlock()
 
164
 
 
165
 
 
166