~bzr-pqm/bzr/bzr.dev

2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
16
17
"""Tests for OS level locks."""
18
19
from bzrlib import (
2353.3.2 by John Arbash Meinel
Add a tests that multiple write locks raise the right kind of error.
20
    errors,
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
21
    osutils,
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
22
    )
23
4513.1.1 by Alexander Belchenko
improved unicode support for OS locks @ win32.
24
from bzrlib.tests import UnicodeFilenameFeature
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
25
from bzrlib.tests.per_lock import TestCaseWithLock
26
27
28
class TestLock(TestCaseWithLock):
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
29
30
    def setUp(self):
31
        super(TestLock, self).setUp()
32
        self.build_tree(['a-file'])
33
34
    def test_read_lock(self):
35
        """Smoke test for read locks."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
36
        a_lock = self.read_lock('a-file')
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
37
        self.addCleanup(a_lock.unlock)
38
        # The lock file should be opened for reading
39
        txt = a_lock.f.read()
40
        self.assertEqual('contents of a-file\n', txt)
41
42
    def test_create_if_needed_read(self):
43
        """We will create the file if it doesn't exist yet."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
44
        a_lock = self.read_lock('other-file')
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
45
        self.addCleanup(a_lock.unlock)
46
        txt = a_lock.f.read()
47
        self.assertEqual('', txt)
48
49
    def test_create_if_needed_write(self):
50
        """We will create the file if it doesn't exist yet."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
51
        a_lock = self.write_lock('other-file')
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
52
        self.addCleanup(a_lock.unlock)
53
        txt = a_lock.f.read()
54
        self.assertEqual('', txt)
2353.3.13 by John Arbash Meinel
Cleanup according to Alexander's review comments.
55
        a_lock.f.seek(0)
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
56
        a_lock.f.write('foo\n')
57
        a_lock.f.seek(0)
58
        txt = a_lock.f.read()
59
        self.assertEqual('foo\n', txt)
60
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
61
    def test_readonly_file(self):
62
        """If the file is readonly, we can take a read lock.
63
64
        But we shouldn't be able to take a write lock.
65
        """
66
        osutils.make_readonly('a-file')
67
        # Make sure the file is read-only (on all platforms)
68
        self.assertRaises(IOError, open, 'a-file', 'rb+')
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
69
        a_lock = self.read_lock('a-file')
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
70
        a_lock.unlock()
71
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
72
        self.assertRaises(errors.LockFailed, self.write_lock, 'a-file')
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
73
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
74
    def test_write_lock(self):
75
        """Smoke test for write locks."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
76
        a_lock = self.write_lock('a-file')
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
77
        self.addCleanup(a_lock.unlock)
78
        # You should be able to read and write to the lock file.
79
        txt = a_lock.f.read()
80
        self.assertEqual('contents of a-file\n', txt)
2353.3.6 by John Arbash Meinel
On Win32 if you have a file opened in read+write mode, you must call seek() when switching
81
        # Win32 requires that you call seek() when switching between a read
82
        # operation and a write operation.
83
        a_lock.f.seek(0, 2)
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
84
        a_lock.f.write('more content\n')
85
        a_lock.f.seek(0)
86
        txt = a_lock.f.read()
87
        self.assertEqual('contents of a-file\nmore content\n', txt)
88
89
    def test_multiple_read_locks(self):
90
        """You can take out more than one read lock on the same file."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
91
        a_lock = self.read_lock('a-file')
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
92
        self.addCleanup(a_lock.unlock)
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
93
        b_lock = self.read_lock('a-file')
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
94
        self.addCleanup(b_lock.unlock)
95
2353.3.2 by John Arbash Meinel
Add a tests that multiple write locks raise the right kind of error.
96
    def test_multiple_write_locks_exclude(self):
97
        """Taking out more than one write lock should fail."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
98
        a_lock = self.write_lock('a-file')
2353.3.2 by John Arbash Meinel
Add a tests that multiple write locks raise the right kind of error.
99
        self.addCleanup(a_lock.unlock)
100
        # Taking out a lock on a locked file should raise LockContention
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
101
        self.assertRaises(errors.LockContention, self.write_lock, 'a-file')
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
102
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
103
    def _disabled_test_read_then_write_excludes(self):
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
104
        """If a file is read-locked, taking out a write lock should fail."""
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
105
        a_lock = self.read_lock('a-file')
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
106
        self.addCleanup(a_lock.unlock)
107
        # Taking out a lock on a locked file should raise LockContention
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
108
        self.assertRaises(errors.LockContention, self.write_lock, 'a-file')
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
109
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
110
    def test_read_unlock_write(self):
111
        """Make sure that unlocking allows us to lock write"""
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
112
        a_lock = self.read_lock('a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
113
        a_lock.unlock()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
114
        a_lock = self.write_lock('a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
115
        a_lock.unlock()
116
2363.3.2 by John Arbash Meinel
Disable read locks blocking on write locks.
117
    # TODO: jam 20070319 fcntl read locks are not currently fully
118
    #       mutually exclusive with write locks. This will be fixed
119
    #       in the next release.
120
    def _disabled_test_write_then_read_excludes(self):
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
121
        """If a file is write-locked, taking out a read lock should fail.
122
123
        The file is exclusively owned by the write lock, so we shouldn't be
124
        able to take out a shared read lock.
125
        """
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
126
        a_lock = self.write_lock('a-file')
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
127
        self.addCleanup(a_lock.unlock)
128
        # Taking out a lock on a locked file should raise LockContention
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
129
        self.assertRaises(errors.LockContention, self.read_lock, 'a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
130
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
131
    # TODO: jam 20070319 fcntl write locks are not currently fully
132
    #       mutually exclusive with read locks. This will be fixed
133
    #       in the next release.
134
    def _disabled_test_write_unlock_read(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
135
        """If we have removed the write lock, we can grab a read lock."""
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
136
        a_lock = self.write_lock('a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
137
        a_lock.unlock()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
138
        a_lock = self.read_lock('a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
139
        a_lock.unlock()
140
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
141
    def _disabled_test_multiple_read_unlock_write(self):
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
142
        """We can only grab a write lock if all read locks are done."""
143
        a_lock = b_lock = c_lock = None
144
        try:
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
145
            a_lock = self.read_lock('a-file')
146
            b_lock = self.read_lock('a-file')
147
            self.assertRaises(errors.LockContention, self.write_lock, 'a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
148
            a_lock.unlock()
149
            a_lock = None
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
150
            self.assertRaises(errors.LockContention, self.write_lock, 'a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
151
            b_lock.unlock()
152
            b_lock = None
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
153
            c_lock = self.write_lock('a-file')
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
154
            c_lock.unlock()
155
            c_lock = None
156
        finally:
157
            # Cleanup as needed
158
            if a_lock is not None:
159
                a_lock.unlock()
160
            if b_lock is not None:
161
                b_lock.unlock()
162
            if c_lock is not None:
163
                c_lock.unlock()
4513.1.1 by Alexander Belchenko
improved unicode support for OS locks @ win32.
164
165
166
class TestLockUnicodePath(TestCaseWithLock):
167
168
    _test_needs_features = [UnicodeFilenameFeature]
169
170
    def test_read_lock(self):
171
        self.build_tree([u'\u1234'])
172
        u_lock = self.read_lock(u'\u1234')
173
        self.addCleanup(u_lock.unlock)
174
175
    def test_write_lock(self):
176
        self.build_tree([u'\u1234'])
177
        u_lock = self.write_lock(u'\u1234')
178
        self.addCleanup(u_lock.unlock)