~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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
24
from bzrlib.tests.per_lock import TestCaseWithLock
25
26
27
class TestLock(TestCaseWithLock):
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
28
29
    def setUp(self):
30
        super(TestLock, self).setUp()
31
        self.build_tree(['a-file'])
32
33
    def test_read_lock(self):
34
        """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
35
        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.
36
        self.addCleanup(a_lock.unlock)
37
        # The lock file should be opened for reading
38
        txt = a_lock.f.read()
39
        self.assertEqual('contents of a-file\n', txt)
40
41
    def test_create_if_needed_read(self):
42
        """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
43
        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.
44
        self.addCleanup(a_lock.unlock)
45
        txt = a_lock.f.read()
46
        self.assertEqual('', txt)
47
48
    def test_create_if_needed_write(self):
49
        """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
50
        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.
51
        self.addCleanup(a_lock.unlock)
52
        txt = a_lock.f.read()
53
        self.assertEqual('', txt)
2353.3.13 by John Arbash Meinel
Cleanup according to Alexander's review comments.
54
        a_lock.f.seek(0)
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
55
        a_lock.f.write('foo\n')
56
        a_lock.f.seek(0)
57
        txt = a_lock.f.read()
58
        self.assertEqual('foo\n', txt)
59
2353.3.3 by John Arbash Meinel
Define an explicit error when trying to grab a write lock on a readonly file.
60
    def test_readonly_file(self):
61
        """If the file is readonly, we can take a read lock.
62
63
        But we shouldn't be able to take a write lock.
64
        """
65
        osutils.make_readonly('a-file')
66
        # Make sure the file is read-only (on all platforms)
67
        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
68
        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.
69
        a_lock.unlock()
70
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
71
        self.assertRaises(errors.ReadOnlyLockError, 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.
72
2353.3.1 by John Arbash Meinel
Add some basic locking tests which should currently pass on all platforms.
73
    def test_write_lock(self):
74
        """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
75
        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.
76
        self.addCleanup(a_lock.unlock)
77
        # You should be able to read and write to the lock file.
78
        txt = a_lock.f.read()
79
        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
80
        # Win32 requires that you call seek() when switching between a read
81
        # operation and a write operation.
82
        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.
83
        a_lock.f.write('more content\n')
84
        a_lock.f.seek(0)
85
        txt = a_lock.f.read()
86
        self.assertEqual('contents of a-file\nmore content\n', txt)
87
88
    def test_multiple_read_locks(self):
89
        """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
90
        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.
91
        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
92
        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.
93
        self.addCleanup(b_lock.unlock)
94
2353.3.2 by John Arbash Meinel
Add a tests that multiple write locks raise the right kind of error.
95
    def test_multiple_write_locks_exclude(self):
96
        """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
97
        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.
98
        self.addCleanup(a_lock.unlock)
99
        # 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
100
        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.
101
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
102
    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.
103
        """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
104
        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.
105
        self.addCleanup(a_lock.unlock)
106
        # 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
107
        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.
108
2353.4.1 by John Arbash Meinel
(broken) Change fcntl locks to be properly exclusive within the same process.
109
    def test_read_unlock_write(self):
110
        """Make sure that unlocking allows us to lock write"""
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
111
        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.
112
        a_lock.unlock()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
113
        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.
114
        a_lock.unlock()
115
2363.3.2 by John Arbash Meinel
Disable read locks blocking on write locks.
116
    # TODO: jam 20070319 fcntl read locks are not currently fully
117
    #       mutually exclusive with write locks. This will be fixed
118
    #       in the next release.
119
    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.
120
        """If a file is write-locked, taking out a read lock should fail.
121
122
        The file is exclusively owned by the write lock, so we shouldn't be
123
        able to take out a shared read lock.
124
        """
2353.3.9 by John Arbash Meinel
Update the lock code and test code so that if more than one
125
        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.
126
        self.addCleanup(a_lock.unlock)
127
        # 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
128
        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.
129
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
130
    # TODO: jam 20070319 fcntl write locks are not currently fully
131
    #       mutually exclusive with read locks. This will be fixed
132
    #       in the next release.
133
    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.
134
        """If we have removed the write lock, we can grab a read lock."""
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
135
        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.
136
        a_lock.unlock()
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
137
        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.
138
        a_lock.unlock()
139
2363.3.3 by John Arbash Meinel
make Write locks not block on Read locks, so that revert tests don't fail
140
    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.
141
        """We can only grab a write lock if all read locks are done."""
142
        a_lock = b_lock = c_lock = None
143
        try:
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
144
            a_lock = self.read_lock('a-file')
145
            b_lock = self.read_lock('a-file')
146
            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.
147
            a_lock.unlock()
148
            a_lock = None
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
149
            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.
150
            b_lock.unlock()
151
            b_lock = None
2353.4.2 by John Arbash Meinel
[merge] LockCleanup changes.
152
            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.
153
            c_lock.unlock()
154
            c_lock = None
155
        finally:
156
            # Cleanup as needed
157
            if a_lock is not None:
158
                a_lock.unlock()
159
            if b_lock is not None:
160
                b_lock.unlock()
161
            if c_lock is not None:
162
                c_lock.unlock()