/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
1
# Copyright (C) 2006 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
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
17
"""Tests for the (un)lock interfaces on all working tree implemenations."""
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
18
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
19
from bzrlib import (
20
    branch,
21
    errors,
22
    lockdir,
23
    )
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
24
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
25
26
27
class TestWorkingTreeLocking(TestCaseWithWorkingTree):
28
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
29
    def test_trivial_lock_read_unlock(self):
30
        """Locking and unlocking should work trivially."""
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
31
        wt = self.make_branch_and_tree('.')
32
33
        self.assertFalse(wt.is_locked())
34
        self.assertFalse(wt.branch.is_locked())
35
        wt.lock_read()
36
        try:
37
            self.assertTrue(wt.is_locked())
38
            self.assertTrue(wt.branch.is_locked())
39
        finally:
40
            wt.unlock()
41
        self.assertFalse(wt.is_locked())
42
        self.assertFalse(wt.branch.is_locked())
43
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
44
    def test_trivial_lock_write_unlock(self):
45
        """Locking for write and unlocking should work trivially."""
46
        wt = self.make_branch_and_tree('.')
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
47
48
        self.assertFalse(wt.is_locked())
49
        self.assertFalse(wt.branch.is_locked())
50
        wt.lock_write()
51
        try:
52
            self.assertTrue(wt.is_locked())
53
            self.assertTrue(wt.branch.is_locked())
54
        finally:
55
            wt.unlock()
56
        self.assertFalse(wt.is_locked())
57
        self.assertFalse(wt.branch.is_locked())
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
58
        
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
59
    def test_trivial_lock_tree_write_unlock(self):
60
        """Locking for tree write is ok when the branch is not locked."""
61
        wt = self.make_branch_and_tree('.')
62
63
        self.assertFalse(wt.is_locked())
64
        self.assertFalse(wt.branch.is_locked())
65
        wt.lock_tree_write()
66
        try:
67
            self.assertTrue(wt.is_locked())
68
            self.assertTrue(wt.branch.is_locked())
69
        finally:
70
            wt.unlock()
71
        self.assertFalse(wt.is_locked())
72
        self.assertFalse(wt.branch.is_locked())
73
        
74
    def test_trivial_lock_tree_write_branch_read_locked(self):
75
        """It is ok to lock_tree_write when the branch is read locked."""
76
        wt = self.make_branch_and_tree('.')
77
78
        self.assertFalse(wt.is_locked())
79
        self.assertFalse(wt.branch.is_locked())
80
        wt.branch.lock_read()
81
        try:
82
            wt.lock_tree_write()
83
        except errors.ReadOnlyError:
84
            # When ReadOnlyError is raised, it indicates that the 
85
            # workingtree shares its lock with the branch, which is what
86
            # the git/hg/bzr0.6 formats do.
87
            # in this case, no lock should have been taken - but the tree
88
            # will have been locked because they share a lock. Unlocking
89
            # just the branch should make everything match again correctly.
90
            wt.branch.unlock()
91
            self.assertFalse(wt.is_locked())
92
            self.assertFalse(wt.branch.is_locked())
93
            return
94
        try:
95
            self.assertTrue(wt.is_locked())
96
            self.assertTrue(wt.branch.is_locked())
97
        finally:
98
            wt.unlock()
99
        self.assertFalse(wt.is_locked())
100
        self.assertTrue(wt.branch.is_locked())
101
        wt.branch.unlock()
102
        
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
103
    def test_unlock_branch_failures(self):
104
        """If the branch unlock fails the tree must still unlock."""
105
        # The public interface for WorkingTree requires a branch, but
106
        # does not require that the working tree use the branch - its
107
        # implementation specific how the WorkingTree, Branch, and Repository
108
        # hang together.
109
        # in order to test that implementations which *do* unlock via the branch
110
        # do so correctly, we unlock the branch after locking the working tree.
111
        # The next unlock on working tree should trigger a LockNotHeld exception
112
        # from the branch object, which must be exposed to the caller. To meet 
113
        # our object model - where locking a tree locks its branch, and
114
        # unlocking a branch does not unlock a working tree, *even* for 
115
        # all-in-one implementations like bzr 0.6, git, and hg, implementations
116
        # must have some separate counter for each object, so our explicit 
117
        # unlock should trigger some error on all implementations, and 
118
        # requiring that to be LockNotHeld seems reasonable.
119
        #
120
        # we use this approach rather than decorating the Branch, because the
121
        # public interface of WorkingTree does not permit altering the branch
122
        # object - and we cannot tell which attribute might allow us to 
123
        # backdoor-in and change it reliably. For implementation specific tests
124
        # we can do such skullduggery, but not for interface specific tests.
125
        # And, its simpler :)
126
        wt = self.make_branch_and_tree('.')
127
128
        self.assertFalse(wt.is_locked())
129
        self.assertFalse(wt.branch.is_locked())
130
        wt.lock_write()
131
        self.assertTrue(wt.is_locked())
132
        self.assertTrue(wt.branch.is_locked())
133
134
        # manually unlock the branch, preparing a LockNotHeld error.
135
        wt.branch.unlock()
136
        # the branch *may* still be locked here, if its an all-in-one
1852.4.6 by Robert Collins
Review feedback.
137
        # implementation because there is a single lock object with three
138
        # references on it, and unlocking the branch only drops this by two
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
139
        self.assertRaises(errors.LockNotHeld, wt.unlock)
140
        # but now, the tree must be unlocked
141
        self.assertFalse(wt.is_locked())
142
        # and the branch too.
143
        self.assertFalse(wt.branch.is_locked())
144
145
    def test_failing_to_lock_branch_does_not_lock(self):
146
        """If the branch cannot be locked, dont lock the tree."""
147
        # Many implementations treat read-locks as non-blocking, but some
148
        # treat them as blocking with writes.. Accordingly we test this by
149
        # opening the branch twice, and locking the branch for write in the
150
        # second instance.  Our lock contract requires separate instances to
151
        # mutually exclude if a lock is exclusive at all: If we get no error
152
        # locking, the test still passes.
153
        wt = self.make_branch_and_tree('.')
154
        branch_copy = branch.Branch.open('.')
155
        branch_copy.lock_write()
156
        try:
157
            try:
158
                wt.lock_read()
1852.4.5 by Robert Collins
Change bare except in working tree locking tests to catch LockError only.
159
            except errors.LockError:
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
160
                # any error here means the locks are exclusive in some 
161
                # manner
162
                self.assertFalse(wt.is_locked())
163
                self.assertFalse(wt.branch.is_locked())
164
                return
165
            else:
166
                # no error - the branch allows read locks while writes
167
                # are taken, just pass.
168
                wt.unlock()
169
        finally:
170
            branch_copy.unlock()
171
172
    def test_failing_to_lock_write_branch_does_not_lock(self):
173
        """If the branch cannot be write locked, dont lock the tree."""
174
        # all implementations of branch are required to treat write 
175
        # locks as blocking (compare to repositories which are not required
176
        # to do so).
177
        # Accordingly we test this by opening the branch twice, and locking the
178
        # branch for write in the second instance.  Our lock contract requires
179
        # separate instances to mutually exclude.
180
        wt = self.make_branch_and_tree('.')
181
        branch_copy = branch.Branch.open('.')
182
        branch_copy.lock_write()
183
        try:
184
            try:
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
185
                orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
186
                try:
187
                    lockdir._DEFAULT_TIMEOUT_SECONDS = 1
188
                    self.assertRaises(errors.LockError, wt.lock_write)
189
                finally:
190
                    lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
191
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
192
                self.assertFalse(wt.is_locked())
193
                self.assertFalse(wt.branch.is_locked())
194
            finally:
195
                if wt.is_locked():
196
                    wt.unlock()
197
        finally:
198
            branch_copy.unlock()
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
199
200
    def test_failing_to_lock_tree_write_branch_does_not_lock(self):
201
        """If the branch cannot be read locked, dont lock the tree."""
202
        # Many implementations treat read-locks as non-blocking, but some
203
        # treat them as blocking with writes.. Accordingly we test this by
204
        # opening the branch twice, and locking the branch for write in the
205
        # second instance.  Our lock contract requires separate instances to
206
        # mutually exclude if a lock is exclusive at all: If we get no error
207
        # locking, the test still passes.
208
        wt = self.make_branch_and_tree('.')
209
        branch_copy = branch.Branch.open('.')
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
210
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
211
        branch_copy.lock_write()
212
        try:
213
            try:
214
                wt.lock_tree_write()
215
            except errors.LockError:
216
                # any error here means the locks are exclusive in some 
217
                # manner
218
                self.assertFalse(wt.is_locked())
219
                self.assertFalse(wt.branch.is_locked())
220
                return
221
            else:
222
                # no error - the branch allows read locks while writes
223
                # are taken, just pass.
224
                wt.unlock()
225
        finally:
226
            branch_copy.unlock()