/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2006 Canonical Ltd
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
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
18
"""Tests of the bzr serve command."""
19
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
20
import os
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
21
import signal
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
22
import subprocess
23
import threading
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
24
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
25
from bzrlib import errors
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
26
from bzrlib.branch import Branch
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
27
from bzrlib.bzrdir import BzrDir
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
28
from bzrlib.errors import ParamikoNotPresent
29
from bzrlib.tests import TestCaseWithTransport, TestSkipped
2018.5.21 by Andrew Bennetts
Move bzrlib.transport.smart to bzrlib.smart
30
from bzrlib.transport import get_transport, remote
31
from bzrlib.smart import medium
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
32
33
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
34
class TestBzrServe(TestCaseWithTransport):
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
35
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
36
    def assertInetServerShutsdownCleanly(self, process):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
37
        """Shutdown the server process looking for errors."""
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
38
        # Shutdown the server: the server should shut down when it cannot read
39
        # from stdin anymore.
40
        process.stdin.close()
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
41
        # Hide stdin from the subprocess module, so it won't fail to close it.
42
        process.stdin = None
43
        result = self.finish_bzr_subprocess(process, retcode=0)
44
        self.assertEqual('', result[0])
45
        self.assertEqual('', result[1])
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
46
    
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
47
    def assertServerFinishesCleanly(self, process):
48
        """Shutdown the bzr serve instance process looking for errors."""
49
        # Shutdown the server
50
        result = self.finish_bzr_subprocess(process, retcode=3,
51
                                            send_signal=signal.SIGINT)
52
        self.assertEqual('', result[0])
53
        self.assertEqual('bzr: interrupted\n', result[1])
54
55
    def start_server_inet(self, extra_options=()):
56
        """Start a bzr server subprocess using the --inet option.
57
58
        :param extra_options: extra options to give the server.
59
        :return: a tuple with the bzr process handle for passing to
60
            finish_bzr_subprocess, a client for the server, and a transport.
61
        """
62
        # Serve from the current directory
63
        process = self.start_bzr_subprocess(['serve', '--inet'])
64
65
        # Connect to the server
66
        # We use this url because while this is no valid URL to connect to this
67
        # server instance, the transport needs a URL.
2018.5.15 by Andrew Bennetts
Tidy some imports, and bugs introduced when adding server.py
68
        client_medium = medium.SmartSimplePipesClientMedium(
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
69
            process.stdout, process.stdin)
2018.5.21 by Andrew Bennetts
Move bzrlib.transport.smart to bzrlib.smart
70
        transport = remote.RemoteTransport(
2018.5.15 by Andrew Bennetts
Tidy some imports, and bugs introduced when adding server.py
71
            'bzr://localhost/', medium=client_medium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
72
        return process, transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
73
74
    def start_server_port(self, extra_options=()):
75
        """Start a bzr server subprocess.
76
77
        :param extra_options: extra options to give the server.
78
        :return: a tuple with the bzr process handle for passing to
79
            finish_bzr_subprocess, and the base url for the server.
80
        """
81
        # Serve from the current directory
82
        args = ['serve', '--port', 'localhost:0']
83
        args.extend(extra_options)
84
        process = self.start_bzr_subprocess(args, skip_if_plan_to_signal=True)
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
85
        port_line = process.stdout.readline()
86
        prefix = 'listening on port: '
87
        self.assertStartsWith(port_line, prefix)
88
        port = int(port_line[len(prefix):])
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
89
        return process,'bzr://localhost:%d/' % port
90
91
    def test_bzr_serve_inet_readonly(self):
92
        """bzr server should provide a read only filesystem by default."""
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
93
        process, transport = self.start_server_inet()
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
94
        self.assertRaises(errors.TransportNotPossible, transport.mkdir, 'adir')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
95
        self.assertInetServerShutsdownCleanly(process)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
96
97
    def test_bzr_serve_inet_readwrite(self):
98
        # Make a branch
99
        self.make_branch('.')
100
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
101
        process, transport = self.start_server_inet(['--allow-writes'])
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
102
103
        # We get a working branch
104
        branch = BzrDir.open_from_transport(transport).open_branch()
105
        branch.repository.get_revision_graph()
106
        self.assertEqual(None, branch.last_revision())
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
107
        self.assertInetServerShutsdownCleanly(process)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
108
109
    def test_bzr_serve_port_readonly(self):
110
        """bzr server should provide a read only filesystem by default."""
111
        process, url = self.start_server_port()
112
        transport = get_transport(url)
113
        self.assertRaises(errors.TransportNotPossible, transport.mkdir, 'adir')
114
        self.assertServerFinishesCleanly(process)
115
116
    def test_bzr_serve_port_readwrite(self):
117
        # Make a branch
118
        self.make_branch('.')
119
120
        process, url = self.start_server_port(['--allow-writes'])
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
121
122
        # Connect to the server
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
123
        branch = Branch.open(url)
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
124
125
        # We get a working branch
126
        branch.repository.get_revision_graph()
127
        self.assertEqual(None, branch.last_revision())
128
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
129
        self.assertServerFinishesCleanly(process)
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
130
1910.19.8 by Andrew Bennetts
Give a sensible error if insufficient options are passed to 'bzr serve'.
131
    def test_bzr_serve_no_args(self):
132
        """'bzr serve' with no arguments or options should not traceback."""
133
        out, err = self.run_bzr_error(
134
            ['bzr serve requires one of --inet or --port'], 'serve')
135
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
136
    def test_bzr_connect_to_bzr_ssh(self):
2018.1.7 by Andrew Bennetts
Use bzrlib rather than a bzr subprocess in test_bzr_connect_to_bzr_ssh.
137
        """User acceptance that get_transport of a bzr+ssh:// behaves correctly.
138
139
        bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
140
        """
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
141
        try:
142
            from bzrlib.transport.sftp import SFTPServer
143
        except ParamikoNotPresent:
144
            raise TestSkipped('Paramiko not installed')
145
        from bzrlib.tests.stub_sftp import StubServer
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
146
        
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
147
        # Make a branch
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
148
        self.make_branch('a_branch')
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
149
150
        # Start an SSH server
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
151
        self.command_executed = []
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
152
        # XXX: This is horrible -- we define a really dumb SSH server that
153
        # executes commands, and manage the hooking up of stdin/out/err to the
154
        # SSH channel ourselves.  Surely this has already been implemented
155
        # elsewhere?
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
156
        class StubSSHServer(StubServer):
157
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
158
            test = self
159
160
            def check_channel_exec_request(self, channel, command):
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
161
                self.test.command_executed.append(command)
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
162
                proc = subprocess.Popen(
163
                    command, shell=True, stdin=subprocess.PIPE,
164
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
165
                
166
                # XXX: horribly inefficient, not to mention ugly.
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
167
                # Start a thread for each of stdin/out/err, and relay bytes from
168
                # the subprocess to channel and vice versa.
169
                def ferry_bytes(read, write, close):
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
170
                    while True:
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
171
                        bytes = read(1)
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
172
                        if bytes == '':
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
173
                            close()
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
174
                            break
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
175
                        write(bytes)
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
176
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
177
                file_functions = [
178
                    (channel.recv, proc.stdin.write, proc.stdin.close),
179
                    (proc.stdout.read, channel.sendall, channel.close),
180
                    (proc.stderr.read, channel.sendall_stderr, channel.close)]
181
                for read, write, close in file_functions:
182
                    t = threading.Thread(
183
                        target=ferry_bytes, args=(read, write, close))
184
                    t.start()
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
185
186
                return True
187
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
188
        ssh_server = SFTPServer(StubSSHServer)
2018.1.7 by Andrew Bennetts
Use bzrlib rather than a bzr subprocess in test_bzr_connect_to_bzr_ssh.
189
        # XXX: We *don't* want to override the default SSH vendor, so we set
190
        # _vendor to what _get_ssh_vendor returns.
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
191
        ssh_server.setUp()
192
        self.addCleanup(ssh_server.tearDown)
193
        port = ssh_server._listener.port
194
195
        # Access the branch via a bzr+ssh URL.  The BZR_REMOTE_PATH environment
196
        # variable is used to tell bzr what command to run on the remote end.
2018.1.7 by Andrew Bennetts
Use bzrlib rather than a bzr subprocess in test_bzr_connect_to_bzr_ssh.
197
        path_to_branch = os.path.abspath('a_branch')
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
198
        
2018.1.7 by Andrew Bennetts
Use bzrlib rather than a bzr subprocess in test_bzr_connect_to_bzr_ssh.
199
        orig_bzr_remote_path = os.environ.get('BZR_REMOTE_PATH')
200
        os.environ['BZR_REMOTE_PATH'] = self.get_bzr_path()
201
        try:
202
            branch = Branch.open(
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
203
                'bzr+ssh://fred:secret@localhost:%d%s' % (port, path_to_branch))
2018.1.7 by Andrew Bennetts
Use bzrlib rather than a bzr subprocess in test_bzr_connect_to_bzr_ssh.
204
            
205
            branch.repository.get_revision_graph()
206
            self.assertEqual(None, branch.last_revision())
2018.1.10 by Andrew Bennetts
Merge --allow-writes from Robert
207
            # Check we can perform write operations
208
            branch.bzrdir.root_transport.mkdir('foo')
2018.1.7 by Andrew Bennetts
Use bzrlib rather than a bzr subprocess in test_bzr_connect_to_bzr_ssh.
209
        finally:
210
            # Restore the BZR_REMOTE_PATH environment variable back to its
211
            # original state.
212
            if orig_bzr_remote_path is None:
213
                del os.environ['BZR_REMOTE_PATH']
214
            else:
215
                os.environ['BZR_REMOTE_PATH'] = orig_bzr_remote_path
216
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
217
        self.assertEqual(
2018.1.11 by Andrew Bennetts
Improvements to test_bzr_connect_to_bzr_ssh based on review comments
218
            ['%s serve --inet --directory=/ --allow-writes'
219
             % self.get_bzr_path()],
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
220
            self.command_executed)
221