/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_permissions.py

  • Committer: Vincent Ladeuil
  • Date: 2008-05-09 16:40:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3422.
  • Revision ID: v.ladeuil+lp@free.fr-20080509164021-kxtz21ozxnv16ivt
Fixed as per John's review.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 Canonical Ltd
 
2
# -*- coding: utf-8 -*-
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
 
 
19
"""Tests for bzr setting permissions.
 
20
 
 
21
Files which are created underneath .bzr/ should inherit its permissions.
 
22
So if the directory is group writable, the files and subdirs should be as well.
 
23
 
 
24
In the future, when we have Repository/Branch/Checkout information, the
 
25
permissions should be inherited individually, rather than all be the same.
 
26
"""
 
27
 
 
28
# TODO: jam 20051215 There are no tests for ftp yet, because we have no ftp server
 
29
# TODO: jam 20051215 Currently the default behavior for 'bzr branch' is just 
 
30
#                    defined by the local umask. This isn't terrible, is it
 
31
#                    the truly desired behavior?
 
32
 
 
33
import os
 
34
import sys
 
35
import stat
 
36
from cStringIO import StringIO
 
37
import urllib
 
38
 
 
39
from bzrlib.branch import Branch
 
40
from bzrlib.bzrdir import BzrDir
 
41
from bzrlib.lockable_files import LockableFiles, TransportLock
 
42
from bzrlib.tests import TestCaseWithTransport, TestSkipped
 
43
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
 
44
from bzrlib.transport import get_transport
 
45
from bzrlib.workingtree import WorkingTree
 
46
 
 
47
 
 
48
def chmod_r(base, file_mode, dir_mode):
 
49
    """Recursively chmod from a base directory"""
 
50
    os.chmod(base, dir_mode)
 
51
    for root, dirs, files in os.walk(base):
 
52
        for d in dirs:
 
53
            p = os.path.join(root, d)
 
54
            os.chmod(p, dir_mode)
 
55
        for f in files:
 
56
            p = os.path.join(root, f)
 
57
            os.chmod(p, file_mode)
 
58
 
 
59
 
 
60
def check_mode_r(test, base, file_mode, dir_mode, include_base=True):
 
61
    """Check that all permissions match
 
62
 
 
63
    :param test: The TestCase being run
 
64
    :param base: The path to the root directory to check
 
65
    :param file_mode: The mode for all files
 
66
    :param dir_mode: The mode for all directories
 
67
    :param include_base: If false, only check the subdirectories
 
68
    """
 
69
    t = get_transport(".")
 
70
    if include_base:
 
71
        test.assertTransportMode(t, base, dir_mode)
 
72
    for root, dirs, files in os.walk(base):
 
73
        for d in dirs:
 
74
            p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [d]])
 
75
            test.assertTransportMode(t, p, dir_mode)
 
76
        for f in files:
 
77
            p = os.path.join(root, f)
 
78
            p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [f]])
 
79
            test.assertTransportMode(t, p, file_mode)
 
80
 
 
81
 
 
82
class TestPermissions(TestCaseWithTransport):
 
83
 
 
84
    def test_new_files(self):
 
85
        if sys.platform == 'win32':
 
86
            raise TestSkipped('chmod has no effect on win32')
 
87
 
 
88
        t = self.make_branch_and_tree('.')
 
89
        b = t.branch
 
90
        open('a', 'wb').write('foo\n')
 
91
        # ensure check_mode_r works with capital-letter file-ids like TREE_ROOT
 
92
        t.add('a', 'CAPS-ID')
 
93
        t.commit('foo')
 
94
 
 
95
        chmod_r('.bzr', 0644, 0755)
 
96
        check_mode_r(self, '.bzr', 0644, 0755)
 
97
 
 
98
        # although we are modifying the filesystem
 
99
        # underneath the objects, they are not locked, and thus it must
 
100
        # be safe for most operations. But here we want to observe a 
 
101
        # mode change in the control bits, which current do not refresh
 
102
        # when a new lock is taken out.
 
103
        t = WorkingTree.open('.')
 
104
        b = t.branch
 
105
        self.assertEqualMode(0755, b.control_files._dir_mode)
 
106
        self.assertEqualMode(0644, b.control_files._file_mode)
 
107
 
 
108
        # Modifying a file shouldn't break the permissions
 
109
        open('a', 'wb').write('foo2\n')
 
110
        t.commit('foo2')
 
111
        # The mode should be maintained after commit
 
112
        check_mode_r(self, '.bzr', 0644, 0755)
 
113
 
 
114
        # Adding a new file should maintain the permissions
 
115
        open('b', 'wb').write('new b\n')
 
116
        t.add('b')
 
117
        t.commit('new b')
 
118
        check_mode_r(self, '.bzr', 0644, 0755)
 
119
 
 
120
        # Recursively update the modes of all files
 
121
        chmod_r('.bzr', 0664, 0775)
 
122
        check_mode_r(self, '.bzr', 0664, 0775)
 
123
        t = WorkingTree.open('.')
 
124
        b = t.branch
 
125
        self.assertEqualMode(0775, b.control_files._dir_mode)
 
126
        self.assertEqualMode(0664, b.control_files._file_mode)
 
127
 
 
128
        open('a', 'wb').write('foo3\n')
 
129
        t.commit('foo3')
 
130
        check_mode_r(self, '.bzr', 0664, 0775)
 
131
 
 
132
        open('c', 'wb').write('new c\n')
 
133
        t.add('c')
 
134
        t.commit('new c')
 
135
        check_mode_r(self, '.bzr', 0664, 0775)
 
136
 
 
137
        # Test the group sticky bit
 
138
        # Recursively update the modes of all files
 
139
        chmod_r('.bzr', 0664, 02775)
 
140
        check_mode_r(self, '.bzr', 0664, 02775)
 
141
        t = WorkingTree.open('.')
 
142
        b = t.branch
 
143
        self.assertEqualMode(02775, b.control_files._dir_mode)
 
144
        self.assertEqualMode(0664, b.control_files._file_mode)
 
145
 
 
146
        open('a', 'wb').write('foo4\n')
 
147
        t.commit('foo4')
 
148
        check_mode_r(self, '.bzr', 0664, 02775)
 
149
 
 
150
        open('d', 'wb').write('new d\n')
 
151
        t.add('d')
 
152
        t.commit('new d')
 
153
        check_mode_r(self, '.bzr', 0664, 02775)
 
154
 
 
155
    def test_disable_set_mode(self):
 
156
        # TODO: jam 20051215 Ultimately, this test should probably test that
 
157
        #                    extra chmod calls aren't being made
 
158
        try:
 
159
            transport = get_transport(self.get_url())
 
160
            transport.put_bytes('my-lock', '')
 
161
            lockable = LockableFiles(transport, 'my-lock', TransportLock)
 
162
            self.assertNotEqual(None, lockable._dir_mode)
 
163
            self.assertNotEqual(None, lockable._file_mode)
 
164
 
 
165
            LockableFiles._set_dir_mode = False
 
166
            transport = get_transport('.')
 
167
            lockable = LockableFiles(transport, 'my-lock', TransportLock)
 
168
            self.assertEqual(None, lockable._dir_mode)
 
169
            self.assertNotEqual(None, lockable._file_mode)
 
170
 
 
171
            LockableFiles._set_file_mode = False
 
172
            transport = get_transport('.')
 
173
            lockable = LockableFiles(transport, 'my-lock', TransportLock)
 
174
            self.assertEqual(None, lockable._dir_mode)
 
175
            self.assertEqual(None, lockable._file_mode)
 
176
 
 
177
            LockableFiles._set_dir_mode = True
 
178
            transport = get_transport('.')
 
179
            lockable = LockableFiles(transport, 'my-lock', TransportLock)
 
180
            self.assertNotEqual(None, lockable._dir_mode)
 
181
            self.assertEqual(None, lockable._file_mode)
 
182
 
 
183
            LockableFiles._set_file_mode = True
 
184
            transport = get_transport('.')
 
185
            lockable = LockableFiles(transport, 'my-lock', TransportLock)
 
186
            self.assertNotEqual(None, lockable._dir_mode)
 
187
            self.assertNotEqual(None, lockable._file_mode)
 
188
        finally:
 
189
            LockableFiles._set_dir_mode = True
 
190
            LockableFiles._set_file_mode = True
 
191
 
 
192
 
 
193
class TestSftpPermissions(TestCaseWithSFTPServer):
 
194
 
 
195
    def test_new_files(self):
 
196
        if sys.platform == 'win32':
 
197
            raise TestSkipped('chmod has no effect on win32')
 
198
        # Though it would be nice to test that SFTP to a server
 
199
        # which does support chmod has the right effect
 
200
 
 
201
        # bodge around for stubsftpserver not letting use connect
 
202
        # more than once
 
203
        _t = get_transport(self.get_url())
 
204
 
 
205
        os.mkdir('local')
 
206
        t_local = self.make_branch_and_tree('local')
 
207
        b_local = t_local.branch
 
208
        open('local/a', 'wb').write('foo\n')
 
209
        t_local.add('a')
 
210
        t_local.commit('foo')
 
211
 
 
212
        # Delete them because we are modifying the filesystem underneath them
 
213
        chmod_r('local/.bzr', 0644, 0755)
 
214
        check_mode_r(self, 'local/.bzr', 0644, 0755)
 
215
 
 
216
        t = WorkingTree.open('local')
 
217
        b_local = t.branch
 
218
        self.assertEqualMode(0755, b_local.control_files._dir_mode)
 
219
        self.assertEqualMode(0644, b_local.control_files._file_mode)
 
220
 
 
221
        os.mkdir('sftp')
 
222
        sftp_url = self.get_url('sftp')
 
223
        b_sftp = BzrDir.create_branch_and_repo(sftp_url)
 
224
 
 
225
        b_sftp.pull(b_local)
 
226
        del b_sftp
 
227
        chmod_r('sftp/.bzr', 0644, 0755)
 
228
        check_mode_r(self, 'sftp/.bzr', 0644, 0755)
 
229
 
 
230
        b_sftp = Branch.open(sftp_url)
 
231
        self.assertEqualMode(0755, b_sftp.control_files._dir_mode)
 
232
        self.assertEqualMode(0644, b_sftp.control_files._file_mode)
 
233
 
 
234
        open('local/a', 'wb').write('foo2\n')
 
235
        t_local.commit('foo2')
 
236
        b_sftp.pull(b_local)
 
237
        # The mode should be maintained after commit
 
238
        check_mode_r(self, 'sftp/.bzr', 0644, 0755)
 
239
 
 
240
        open('local/b', 'wb').write('new b\n')
 
241
        t_local.add('b')
 
242
        t_local.commit('new b')
 
243
        b_sftp.pull(b_local)
 
244
        check_mode_r(self, 'sftp/.bzr', 0644, 0755)
 
245
 
 
246
        del b_sftp
 
247
        # Recursively update the modes of all files
 
248
        chmod_r('sftp/.bzr', 0664, 0775)
 
249
        check_mode_r(self, 'sftp/.bzr', 0664, 0775)
 
250
 
 
251
        b_sftp = Branch.open(sftp_url)
 
252
        self.assertEqualMode(0775, b_sftp.control_files._dir_mode)
 
253
        self.assertEqualMode(0664, b_sftp.control_files._file_mode)
 
254
 
 
255
        open('local/a', 'wb').write('foo3\n')
 
256
        t_local.commit('foo3')
 
257
        b_sftp.pull(b_local)
 
258
        check_mode_r(self, 'sftp/.bzr', 0664, 0775)
 
259
 
 
260
        open('local/c', 'wb').write('new c\n')
 
261
        t_local.add('c')
 
262
        t_local.commit('new c')
 
263
        b_sftp.pull(b_local)
 
264
        check_mode_r(self, 'sftp/.bzr', 0664, 0775)
 
265
 
 
266
    def test_sftp_server_modes(self):
 
267
        if sys.platform == 'win32':
 
268
            raise TestSkipped('chmod has no effect on win32')
 
269
 
 
270
        umask = 0022
 
271
        original_umask = os.umask(umask)
 
272
 
 
273
        try:
 
274
            t = get_transport(self.get_url())
 
275
            # Direct access should be masked by umask
 
276
            t._sftp_open_exclusive('a', mode=0666).write('foo\n')
 
277
            self.assertTransportMode(t, 'a', 0666 &~umask)
 
278
 
 
279
            # but Transport overrides umask
 
280
            t.put_bytes('b', 'txt', mode=0666)
 
281
            self.assertTransportMode(t, 'b', 0666)
 
282
 
 
283
            t._get_sftp().mkdir('c', mode=0777)
 
284
            self.assertTransportMode(t, 'c', 0777 &~umask)
 
285
 
 
286
            t.mkdir('d', mode=0777)
 
287
            self.assertTransportMode(t, 'd', 0777)
 
288
        finally:
 
289
            os.umask(original_umask)