~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart.py

  • Committer: Vincent Ladeuil
  • Date: 2010-03-02 10:21:39 UTC
  • mfrom: (4797.2.24 2.1)
  • mto: This revision was merged to the branch mainline in revision 5069.
  • Revision ID: v.ladeuil+lp@free.fr-20100302102139-b5cba7h6xu13mekg
Merge 2.1 into trunk including fixes for #331095, #507557, #185103, #524184 and #369501

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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 the smart wire/domain protocol."""
18
 
 
19
 
from StringIO import StringIO
20
 
import tempfile
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the smart wire/domain protocol.
 
18
 
 
19
This module contains tests for the domain-level smart requests and responses,
 
20
such as the 'Branch.lock_write' request. Many of these use specific disk
 
21
formats to exercise calls that only make sense for formats with specific
 
22
properties.
 
23
 
 
24
Tests for low-level protocol encoding are found in test_smart_transport.
 
25
"""
 
26
 
 
27
import bz2
 
28
from cStringIO import StringIO
21
29
import tarfile
22
30
 
23
 
from bzrlib import bzrdir, errors, pack, smart, tests
24
 
from bzrlib.smart.request import SmartServerResponse
25
 
import bzrlib.smart.bzrdir
26
 
import bzrlib.smart.branch
27
 
import bzrlib.smart.repository
28
 
from bzrlib.util import bencode
29
 
 
30
 
 
31
 
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
 
31
from bzrlib import (
 
32
    bencode,
 
33
    branch as _mod_branch,
 
34
    bzrdir,
 
35
    errors,
 
36
    pack,
 
37
    tests,
 
38
    transport,
 
39
    urlutils,
 
40
    versionedfile,
 
41
    )
 
42
from bzrlib.smart import (
 
43
    branch as smart_branch,
 
44
    bzrdir as smart_dir,
 
45
    repository as smart_repo,
 
46
    packrepository as smart_packrepo,
 
47
    request as smart_req,
 
48
    server,
 
49
    vfs,
 
50
    )
 
51
from bzrlib.tests import test_server
 
52
from bzrlib.transport import (
 
53
    chroot,
 
54
    memory,
 
55
    )
 
56
 
 
57
 
 
58
def load_tests(standard_tests, module, loader):
 
59
    """Multiply tests version and protocol consistency."""
 
60
    # FindRepository tests.
 
61
    scenarios = [
 
62
        ("find_repository", {
 
63
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV1}),
 
64
        ("find_repositoryV2", {
 
65
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV2}),
 
66
        ("find_repositoryV3", {
 
67
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV3}),
 
68
        ]
 
69
    to_adapt, result = tests.split_suite_by_re(standard_tests,
 
70
        "TestSmartServerRequestFindRepository")
 
71
    v2_only, v1_and_2 = tests.split_suite_by_re(to_adapt,
 
72
        "_v2")
 
73
    tests.multiply_tests(v1_and_2, scenarios, result)
 
74
    # The first scenario is only applicable to v1 protocols, it is deleted
 
75
    # since.
 
76
    tests.multiply_tests(v2_only, scenarios[1:], result)
 
77
    return result
 
78
 
 
79
 
 
80
class TestCaseWithChrootedTransport(tests.TestCaseWithTransport):
 
81
 
 
82
    def setUp(self):
 
83
        self.vfs_transport_factory = memory.MemoryServer
 
84
        tests.TestCaseWithTransport.setUp(self)
 
85
        self._chroot_server = None
 
86
 
 
87
    def get_transport(self, relpath=None):
 
88
        if self._chroot_server is None:
 
89
            backing_transport = tests.TestCaseWithTransport.get_transport(self)
 
90
            self._chroot_server = chroot.ChrootServer(backing_transport)
 
91
            self.start_server(self._chroot_server)
 
92
        t = transport.get_transport(self._chroot_server.get_url())
 
93
        if relpath is not None:
 
94
            t = t.clone(relpath)
 
95
        return t
 
96
 
 
97
 
 
98
class TestCaseWithSmartMedium(tests.TestCaseWithMemoryTransport):
32
99
 
33
100
    def setUp(self):
34
101
        super(TestCaseWithSmartMedium, self).setUp()
36
103
        # the default or a parameterized class, but rather use the
37
104
        # TestCaseWithTransport infrastructure to set up a smart server and
38
105
        # transport.
39
 
        self.transport_server = smart.server.SmartTCPServer_for_testing
 
106
        self.transport_server = self.make_transport_server
 
107
 
 
108
    def make_transport_server(self):
 
109
        return test_server.SmartTCPServer_for_testing('-' + self.id())
40
110
 
41
111
    def get_smart_medium(self):
42
112
        """Get a smart medium to use in tests."""
43
113
        return self.get_transport().get_smart_medium()
44
114
 
45
115
 
 
116
class TestByteStreamToStream(tests.TestCase):
 
117
 
 
118
    def test_repeated_substreams_same_kind_are_one_stream(self):
 
119
        # Make a stream - an iterable of bytestrings.
 
120
        stream = [('text', [versionedfile.FulltextContentFactory(('k1',), None,
 
121
            None, 'foo')]),('text', [
 
122
            versionedfile.FulltextContentFactory(('k2',), None, None, 'bar')])]
 
123
        fmt = bzrdir.format_registry.get('pack-0.92')().repository_format
 
124
        bytes = smart_repo._stream_to_byte_stream(stream, fmt)
 
125
        streams = []
 
126
        # Iterate the resulting iterable; checking that we get only one stream
 
127
        # out.
 
128
        fmt, stream = smart_repo._byte_stream_to_stream(bytes)
 
129
        for kind, substream in stream:
 
130
            streams.append((kind, list(substream)))
 
131
        self.assertLength(1, streams)
 
132
        self.assertLength(2, streams[0][1])
 
133
 
 
134
 
46
135
class TestSmartServerResponse(tests.TestCase):
47
136
 
48
137
    def test__eq__(self):
49
 
        self.assertEqual(SmartServerResponse(('ok', )),
50
 
            SmartServerResponse(('ok', )))
51
 
        self.assertEqual(SmartServerResponse(('ok', ), 'body'),
52
 
            SmartServerResponse(('ok', ), 'body'))
53
 
        self.assertNotEqual(SmartServerResponse(('ok', )),
54
 
            SmartServerResponse(('notok', )))
55
 
        self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
56
 
            SmartServerResponse(('ok', )))
 
138
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
139
            smart_req.SmartServerResponse(('ok', )))
 
140
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
 
141
            smart_req.SmartServerResponse(('ok', ), 'body'))
 
142
        self.assertNotEqual(smart_req.SmartServerResponse(('ok', )),
 
143
            smart_req.SmartServerResponse(('notok', )))
 
144
        self.assertNotEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
 
145
            smart_req.SmartServerResponse(('ok', )))
57
146
        self.assertNotEqual(None,
58
 
            SmartServerResponse(('ok', )))
59
 
 
60
 
 
61
 
class TestSmartServerRequestFindRepository(tests.TestCaseWithTransport):
 
147
            smart_req.SmartServerResponse(('ok', )))
 
148
 
 
149
    def test__str__(self):
 
150
        """SmartServerResponses can be stringified."""
 
151
        self.assertEqual(
 
152
            "<SuccessfulSmartServerResponse args=('args',) body='body'>",
 
153
            str(smart_req.SuccessfulSmartServerResponse(('args',), 'body')))
 
154
        self.assertEqual(
 
155
            "<FailedSmartServerResponse args=('args',) body='body'>",
 
156
            str(smart_req.FailedSmartServerResponse(('args',), 'body')))
 
157
 
 
158
 
 
159
class TestSmartServerRequest(tests.TestCaseWithMemoryTransport):
 
160
 
 
161
    def test_translate_client_path(self):
 
162
        transport = self.get_transport()
 
163
        request = smart_req.SmartServerRequest(transport, 'foo/')
 
164
        self.assertEqual('./', request.translate_client_path('foo/'))
 
165
        self.assertRaises(
 
166
            errors.InvalidURLJoin, request.translate_client_path, 'foo/..')
 
167
        self.assertRaises(
 
168
            errors.PathNotChild, request.translate_client_path, '/')
 
169
        self.assertRaises(
 
170
            errors.PathNotChild, request.translate_client_path, 'bar/')
 
171
        self.assertEqual('./baz', request.translate_client_path('foo/baz'))
 
172
        e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
 
173
        self.assertEqual('./' + urlutils.escape(e_acute),
 
174
                         request.translate_client_path('foo/' + e_acute))
 
175
 
 
176
    def test_translate_client_path_vfs(self):
 
177
        """VfsRequests receive escaped paths rather than raw UTF-8."""
 
178
        transport = self.get_transport()
 
179
        request = vfs.VfsRequest(transport, 'foo/')
 
180
        e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
 
181
        escaped = urlutils.escape('foo/' + e_acute)
 
182
        self.assertEqual('./' + urlutils.escape(e_acute),
 
183
                         request.translate_client_path(escaped))
 
184
 
 
185
    def test_transport_from_client_path(self):
 
186
        transport = self.get_transport()
 
187
        request = smart_req.SmartServerRequest(transport, 'foo/')
 
188
        self.assertEqual(
 
189
            transport.base,
 
190
            request.transport_from_client_path('foo/').base)
 
191
 
 
192
 
 
193
class TestSmartServerBzrDirRequestCloningMetaDir(
 
194
    tests.TestCaseWithMemoryTransport):
 
195
    """Tests for BzrDir.cloning_metadir."""
 
196
 
 
197
    def test_cloning_metadir(self):
 
198
        """When there is a bzrdir present, the call succeeds."""
 
199
        backing = self.get_transport()
 
200
        dir = self.make_bzrdir('.')
 
201
        local_result = dir.cloning_metadir()
 
202
        request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
 
203
        request = request_class(backing)
 
204
        expected = smart_req.SuccessfulSmartServerResponse(
 
205
            (local_result.network_name(),
 
206
            local_result.repository_format.network_name(),
 
207
            ('branch', local_result.get_branch_format().network_name())))
 
208
        self.assertEqual(expected, request.execute('', 'False'))
 
209
 
 
210
    def test_cloning_metadir_reference(self):
 
211
        """The request fails when bzrdir contains a branch reference."""
 
212
        backing = self.get_transport()
 
213
        referenced_branch = self.make_branch('referenced')
 
214
        dir = self.make_bzrdir('.')
 
215
        local_result = dir.cloning_metadir()
 
216
        reference = _mod_branch.BranchReferenceFormat().initialize(
 
217
            dir, referenced_branch)
 
218
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(dir)
 
219
        # The server shouldn't try to follow the branch reference, so it's fine
 
220
        # if the referenced branch isn't reachable.
 
221
        backing.rename('referenced', 'moved')
 
222
        request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
 
223
        request = request_class(backing)
 
224
        expected = smart_req.FailedSmartServerResponse(('BranchReference',))
 
225
        self.assertEqual(expected, request.execute('', 'False'))
 
226
 
 
227
 
 
228
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
 
229
    """Tests for BzrDir.create_repository."""
 
230
 
 
231
    def test_makes_repository(self):
 
232
        """When there is a bzrdir present, the call succeeds."""
 
233
        backing = self.get_transport()
 
234
        self.make_bzrdir('.')
 
235
        request_class = smart_dir.SmartServerRequestCreateRepository
 
236
        request = request_class(backing)
 
237
        reference_bzrdir_format = bzrdir.format_registry.get('pack-0.92')()
 
238
        reference_format = reference_bzrdir_format.repository_format
 
239
        network_name = reference_format.network_name()
 
240
        expected = smart_req.SuccessfulSmartServerResponse(
 
241
            ('ok', 'no', 'no', 'no', network_name))
 
242
        self.assertEqual(expected, request.execute('', network_name, 'True'))
 
243
 
 
244
 
 
245
class TestSmartServerRequestFindRepository(tests.TestCaseWithMemoryTransport):
62
246
    """Tests for BzrDir.find_repository."""
63
247
 
64
248
    def test_no_repository(self):
65
249
        """When there is no repository to be found, ('norepository', ) is returned."""
66
250
        backing = self.get_transport()
67
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
251
        request = self._request_class(backing)
68
252
        self.make_bzrdir('.')
69
 
        self.assertEqual(SmartServerResponse(('norepository', )),
70
 
            request.execute(backing.local_abspath('')))
 
253
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
254
            request.execute(''))
71
255
 
72
256
    def test_nonshared_repository(self):
73
 
        # nonshared repositorys only allow 'find' to return a handle when the 
74
 
        # path the repository is being searched on is the same as that that 
 
257
        # nonshared repositorys only allow 'find' to return a handle when the
 
258
        # path the repository is being searched on is the same as that that
75
259
        # the repository is at.
76
260
        backing = self.get_transport()
77
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
261
        request = self._request_class(backing)
78
262
        result = self._make_repository_and_result()
79
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
263
        self.assertEqual(result, request.execute(''))
80
264
        self.make_bzrdir('subdir')
81
 
        self.assertEqual(SmartServerResponse(('norepository', )),
82
 
            request.execute(backing.local_abspath('subdir')))
 
265
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
266
            request.execute('subdir'))
83
267
 
84
268
    def _make_repository_and_result(self, shared=False, format=None):
85
269
        """Convenience function to setup a repository.
95
279
            subtrees = 'yes'
96
280
        else:
97
281
            subtrees = 'no'
98
 
        return SmartServerResponse(('ok', '', rich_root, subtrees))
 
282
        if repo._format.supports_external_lookups:
 
283
            external = 'yes'
 
284
        else:
 
285
            external = 'no'
 
286
        if (smart_dir.SmartServerRequestFindRepositoryV3 ==
 
287
            self._request_class):
 
288
            return smart_req.SuccessfulSmartServerResponse(
 
289
                ('ok', '', rich_root, subtrees, external,
 
290
                 repo._format.network_name()))
 
291
        elif (smart_dir.SmartServerRequestFindRepositoryV2 ==
 
292
            self._request_class):
 
293
            # All tests so far are on formats, and for non-external
 
294
            # repositories.
 
295
            return smart_req.SuccessfulSmartServerResponse(
 
296
                ('ok', '', rich_root, subtrees, external))
 
297
        else:
 
298
            return smart_req.SuccessfulSmartServerResponse(
 
299
                ('ok', '', rich_root, subtrees))
99
300
 
100
301
    def test_shared_repository(self):
101
302
        """When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
102
303
        backing = self.get_transport()
103
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
304
        request = self._request_class(backing)
104
305
        result = self._make_repository_and_result(shared=True)
105
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
306
        self.assertEqual(result, request.execute(''))
106
307
        self.make_bzrdir('subdir')
107
 
        result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
 
308
        result2 = smart_req.SmartServerResponse(
 
309
            result.args[0:1] + ('..', ) + result.args[2:])
108
310
        self.assertEqual(result2,
109
 
            request.execute(backing.local_abspath('subdir')))
 
311
            request.execute('subdir'))
110
312
        self.make_bzrdir('subdir/deeper')
111
 
        result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
 
313
        result3 = smart_req.SmartServerResponse(
 
314
            result.args[0:1] + ('../..', ) + result.args[2:])
112
315
        self.assertEqual(result3,
113
 
            request.execute(backing.local_abspath('subdir/deeper')))
 
316
            request.execute('subdir/deeper'))
114
317
 
115
318
    def test_rich_root_and_subtree_encoding(self):
116
319
        """Test for the format attributes for rich root and subtree support."""
117
320
        backing = self.get_transport()
118
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
119
 
        result = self._make_repository_and_result(format='dirstate-with-subtree')
 
321
        request = self._request_class(backing)
 
322
        result = self._make_repository_and_result(
 
323
            format='dirstate-with-subtree')
120
324
        # check the test will be valid
121
325
        self.assertEqual('yes', result.args[2])
122
326
        self.assertEqual('yes', result.args[3])
123
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
124
 
 
125
 
 
126
 
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithTransport):
 
327
        self.assertEqual(result, request.execute(''))
 
328
 
 
329
    def test_supports_external_lookups_no_v2(self):
 
330
        """Test for the supports_external_lookups attribute."""
 
331
        backing = self.get_transport()
 
332
        request = self._request_class(backing)
 
333
        result = self._make_repository_and_result(
 
334
            format='dirstate-with-subtree')
 
335
        # check the test will be valid
 
336
        self.assertEqual('no', result.args[4])
 
337
        self.assertEqual(result, request.execute(''))
 
338
 
 
339
 
 
340
class TestSmartServerBzrDirRequestGetConfigFile(
 
341
    tests.TestCaseWithMemoryTransport):
 
342
    """Tests for BzrDir.get_config_file."""
 
343
 
 
344
    def test_present(self):
 
345
        backing = self.get_transport()
 
346
        dir = self.make_bzrdir('.')
 
347
        dir.get_config().set_default_stack_on("/")
 
348
        local_result = dir._get_config()._get_config_file().read()
 
349
        request_class = smart_dir.SmartServerBzrDirRequestConfigFile
 
350
        request = request_class(backing)
 
351
        expected = smart_req.SuccessfulSmartServerResponse((), local_result)
 
352
        self.assertEqual(expected, request.execute(''))
 
353
 
 
354
    def test_missing(self):
 
355
        backing = self.get_transport()
 
356
        dir = self.make_bzrdir('.')
 
357
        request_class = smart_dir.SmartServerBzrDirRequestConfigFile
 
358
        request = request_class(backing)
 
359
        expected = smart_req.SuccessfulSmartServerResponse((), '')
 
360
        self.assertEqual(expected, request.execute(''))
 
361
 
 
362
 
 
363
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithMemoryTransport):
127
364
 
128
365
    def test_empty_dir(self):
129
366
        """Initializing an empty dir should succeed and do it."""
130
367
        backing = self.get_transport()
131
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
132
 
        self.assertEqual(SmartServerResponse(('ok', )),
133
 
            request.execute(backing.local_abspath('.')))
 
368
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
 
369
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
370
            request.execute(''))
134
371
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
135
 
        # no branch, tree or repository is expected with the current 
 
372
        # no branch, tree or repository is expected with the current
136
373
        # default formart.
137
374
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
138
375
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
141
378
    def test_missing_dir(self):
142
379
        """Initializing a missing directory should fail like the bzrdir api."""
143
380
        backing = self.get_transport()
144
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
 
381
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
145
382
        self.assertRaises(errors.NoSuchFile,
146
 
            request.execute, backing.local_abspath('subdir'))
 
383
            request.execute, 'subdir')
147
384
 
148
385
    def test_initialized_dir(self):
149
386
        """Initializing an extant bzrdir should fail like the bzrdir api."""
150
387
        backing = self.get_transport()
151
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
 
388
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
152
389
        self.make_bzrdir('subdir')
153
390
        self.assertRaises(errors.FileExists,
154
 
            request.execute, backing.local_abspath('subdir'))
155
 
 
156
 
 
157
 
class TestSmartServerRequestOpenBranch(tests.TestCaseWithTransport):
 
391
            request.execute, 'subdir')
 
392
 
 
393
 
 
394
class TestSmartServerRequestBzrDirInitializeEx(
 
395
    tests.TestCaseWithMemoryTransport):
 
396
    """Basic tests for BzrDir.initialize_ex_1.16 in the smart server.
 
397
 
 
398
    The main unit tests in test_bzrdir exercise the API comprehensively.
 
399
    """
 
400
 
 
401
    def test_empty_dir(self):
 
402
        """Initializing an empty dir should succeed and do it."""
 
403
        backing = self.get_transport()
 
404
        name = self.make_bzrdir('reference')._format.network_name()
 
405
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
406
        self.assertEqual(
 
407
            smart_req.SmartServerResponse(('', '', '', '', '', '', name,
 
408
                                           'False', '', '', '')),
 
409
            request.execute(name, '', 'True', 'False', 'False', '', '', '', '',
 
410
                            'False'))
 
411
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
 
412
        # no branch, tree or repository is expected with the current
 
413
        # default format.
 
414
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
 
415
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
 
416
        self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
 
417
 
 
418
    def test_missing_dir(self):
 
419
        """Initializing a missing directory should fail like the bzrdir api."""
 
420
        backing = self.get_transport()
 
421
        name = self.make_bzrdir('reference')._format.network_name()
 
422
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
423
        self.assertRaises(errors.NoSuchFile, request.execute, name,
 
424
            'subdir/dir', 'False', 'False', 'False', '', '', '', '', 'False')
 
425
 
 
426
    def test_initialized_dir(self):
 
427
        """Initializing an extant directory should fail like the bzrdir api."""
 
428
        backing = self.get_transport()
 
429
        name = self.make_bzrdir('reference')._format.network_name()
 
430
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
431
        self.make_bzrdir('subdir')
 
432
        self.assertRaises(errors.FileExists, request.execute, name, 'subdir',
 
433
            'False', 'False', 'False', '', '', '', '', 'False')
 
434
 
 
435
 
 
436
class TestSmartServerRequestOpenBzrDir(tests.TestCaseWithMemoryTransport):
 
437
 
 
438
    def test_no_directory(self):
 
439
        backing = self.get_transport()
 
440
        request = smart_dir.SmartServerRequestOpenBzrDir(backing)
 
441
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
442
            request.execute('does-not-exist'))
 
443
 
 
444
    def test_empty_directory(self):
 
445
        backing = self.get_transport()
 
446
        backing.mkdir('empty')
 
447
        request = smart_dir.SmartServerRequestOpenBzrDir(backing)
 
448
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
449
            request.execute('empty'))
 
450
 
 
451
    def test_outside_root_client_path(self):
 
452
        backing = self.get_transport()
 
453
        request = smart_dir.SmartServerRequestOpenBzrDir(backing,
 
454
            root_client_path='root')
 
455
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
456
            request.execute('not-root'))
 
457
 
 
458
 
 
459
class TestSmartServerRequestOpenBzrDir_2_1(tests.TestCaseWithMemoryTransport):
 
460
 
 
461
    def test_no_directory(self):
 
462
        backing = self.get_transport()
 
463
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
464
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
465
            request.execute('does-not-exist'))
 
466
 
 
467
    def test_empty_directory(self):
 
468
        backing = self.get_transport()
 
469
        backing.mkdir('empty')
 
470
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
471
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
472
            request.execute('empty'))
 
473
 
 
474
    def test_present_without_workingtree(self):
 
475
        backing = self.get_transport()
 
476
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
477
        self.make_bzrdir('.')
 
478
        self.assertEqual(smart_req.SmartServerResponse(('yes', 'no')),
 
479
            request.execute(''))
 
480
 
 
481
    def test_outside_root_client_path(self):
 
482
        backing = self.get_transport()
 
483
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing,
 
484
            root_client_path='root')
 
485
        self.assertEqual(smart_req.SmartServerResponse(('no',)),
 
486
            request.execute('not-root'))
 
487
 
 
488
 
 
489
class TestSmartServerRequestOpenBzrDir_2_1_disk(TestCaseWithChrootedTransport):
 
490
 
 
491
    def test_present_with_workingtree(self):
 
492
        self.vfs_transport_factory = test_server.LocalURLServer
 
493
        backing = self.get_transport()
 
494
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
495
        bd = self.make_bzrdir('.')
 
496
        bd.create_repository()
 
497
        bd.create_branch()
 
498
        bd.create_workingtree()
 
499
        self.assertEqual(smart_req.SmartServerResponse(('yes', 'yes')),
 
500
            request.execute(''))
 
501
 
 
502
 
 
503
class TestSmartServerRequestOpenBranch(TestCaseWithChrootedTransport):
158
504
 
159
505
    def test_no_branch(self):
160
506
        """When there is no branch, ('nobranch', ) is returned."""
161
507
        backing = self.get_transport()
162
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
508
        request = smart_dir.SmartServerRequestOpenBranch(backing)
163
509
        self.make_bzrdir('.')
164
 
        self.assertEqual(SmartServerResponse(('nobranch', )),
165
 
            request.execute(backing.local_abspath('')))
 
510
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
511
            request.execute(''))
166
512
 
167
513
    def test_branch(self):
168
514
        """When there is a branch, 'ok' is returned."""
169
515
        backing = self.get_transport()
170
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
516
        request = smart_dir.SmartServerRequestOpenBranch(backing)
171
517
        self.make_branch('.')
172
 
        self.assertEqual(SmartServerResponse(('ok', '')),
173
 
            request.execute(backing.local_abspath('')))
174
 
 
175
 
    def test_branch_reference(self):
176
 
        """When there is a branch reference, the reference URL is returned."""
177
 
        backing = self.get_transport()
178
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
179
 
        branch = self.make_branch('branch')
180
 
        checkout = branch.create_checkout('reference',lightweight=True)
181
 
        # TODO: once we have an API to probe for references of any sort, we
182
 
        # can use it here.
183
 
        reference_url = backing.abspath('branch') + '/'
184
 
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
185
 
        self.assertEqual(SmartServerResponse(('ok', reference_url)),
186
 
            request.execute(backing.local_abspath('reference')))
187
 
 
188
 
 
189
 
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithTransport):
 
518
        self.assertEqual(smart_req.SmartServerResponse(('ok', '')),
 
519
            request.execute(''))
 
520
 
 
521
    def test_branch_reference(self):
 
522
        """When there is a branch reference, the reference URL is returned."""
 
523
        self.vfs_transport_factory = test_server.LocalURLServer
 
524
        backing = self.get_transport()
 
525
        request = smart_dir.SmartServerRequestOpenBranch(backing)
 
526
        branch = self.make_branch('branch')
 
527
        checkout = branch.create_checkout('reference',lightweight=True)
 
528
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
529
            checkout.bzrdir)
 
530
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
531
        self.assertEqual(smart_req.SmartServerResponse(('ok', reference_url)),
 
532
            request.execute('reference'))
 
533
 
 
534
    def test_notification_on_branch_from_repository(self):
 
535
        """When there is a repository, the error should return details."""
 
536
        backing = self.get_transport()
 
537
        request = smart_dir.SmartServerRequestOpenBranch(backing)
 
538
        repo = self.make_repository('.')
 
539
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
540
            request.execute(''))
 
541
 
 
542
 
 
543
class TestSmartServerRequestOpenBranchV2(TestCaseWithChrootedTransport):
 
544
 
 
545
    def test_no_branch(self):
 
546
        """When there is no branch, ('nobranch', ) is returned."""
 
547
        backing = self.get_transport()
 
548
        self.make_bzrdir('.')
 
549
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
550
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
551
            request.execute(''))
 
552
 
 
553
    def test_branch(self):
 
554
        """When there is a branch, 'ok' is returned."""
 
555
        backing = self.get_transport()
 
556
        expected = self.make_branch('.')._format.network_name()
 
557
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
558
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
559
                ('branch', expected)),
 
560
                         request.execute(''))
 
561
 
 
562
    def test_branch_reference(self):
 
563
        """When there is a branch reference, the reference URL is returned."""
 
564
        self.vfs_transport_factory = test_server.LocalURLServer
 
565
        backing = self.get_transport()
 
566
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
567
        branch = self.make_branch('branch')
 
568
        checkout = branch.create_checkout('reference',lightweight=True)
 
569
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
570
            checkout.bzrdir)
 
571
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
572
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
573
                ('ref', reference_url)),
 
574
                         request.execute('reference'))
 
575
 
 
576
    def test_stacked_branch(self):
 
577
        """Opening a stacked branch does not open the stacked-on branch."""
 
578
        trunk = self.make_branch('trunk')
 
579
        feature = self.make_branch('feature')
 
580
        feature.set_stacked_on_url(trunk.base)
 
581
        opened_branches = []
 
582
        _mod_branch.Branch.hooks.install_named_hook(
 
583
            'open', opened_branches.append, None)
 
584
        backing = self.get_transport()
 
585
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
586
        request.setup_jail()
 
587
        try:
 
588
            response = request.execute('feature')
 
589
        finally:
 
590
            request.teardown_jail()
 
591
        expected_format = feature._format.network_name()
 
592
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
593
                ('branch', expected_format)),
 
594
                         response)
 
595
        self.assertLength(1, opened_branches)
 
596
 
 
597
    def test_notification_on_branch_from_repository(self):
 
598
        """When there is a repository, the error should return details."""
 
599
        backing = self.get_transport()
 
600
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
601
        repo = self.make_repository('.')
 
602
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
603
            request.execute(''))
 
604
 
 
605
 
 
606
class TestSmartServerRequestOpenBranchV3(TestCaseWithChrootedTransport):
 
607
 
 
608
    def test_no_branch(self):
 
609
        """When there is no branch, ('nobranch', ) is returned."""
 
610
        backing = self.get_transport()
 
611
        self.make_bzrdir('.')
 
612
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
613
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
614
            request.execute(''))
 
615
 
 
616
    def test_branch(self):
 
617
        """When there is a branch, 'ok' is returned."""
 
618
        backing = self.get_transport()
 
619
        expected = self.make_branch('.')._format.network_name()
 
620
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
621
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
622
                ('branch', expected)),
 
623
                         request.execute(''))
 
624
 
 
625
    def test_branch_reference(self):
 
626
        """When there is a branch reference, the reference URL is returned."""
 
627
        self.vfs_transport_factory = test_server.LocalURLServer
 
628
        backing = self.get_transport()
 
629
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
630
        branch = self.make_branch('branch')
 
631
        checkout = branch.create_checkout('reference',lightweight=True)
 
632
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
633
            checkout.bzrdir)
 
634
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
635
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
636
                ('ref', reference_url)),
 
637
                         request.execute('reference'))
 
638
 
 
639
    def test_stacked_branch(self):
 
640
        """Opening a stacked branch does not open the stacked-on branch."""
 
641
        trunk = self.make_branch('trunk')
 
642
        feature = self.make_branch('feature')
 
643
        feature.set_stacked_on_url(trunk.base)
 
644
        opened_branches = []
 
645
        _mod_branch.Branch.hooks.install_named_hook(
 
646
            'open', opened_branches.append, None)
 
647
        backing = self.get_transport()
 
648
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
649
        request.setup_jail()
 
650
        try:
 
651
            response = request.execute('feature')
 
652
        finally:
 
653
            request.teardown_jail()
 
654
        expected_format = feature._format.network_name()
 
655
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
656
                ('branch', expected_format)),
 
657
                         response)
 
658
        self.assertLength(1, opened_branches)
 
659
 
 
660
    def test_notification_on_branch_from_repository(self):
 
661
        """When there is a repository, the error should return details."""
 
662
        backing = self.get_transport()
 
663
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
664
        repo = self.make_repository('.')
 
665
        self.assertEqual(smart_req.SmartServerResponse(
 
666
                ('nobranch', 'location is a repository')),
 
667
                         request.execute(''))
 
668
 
 
669
 
 
670
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
190
671
 
191
672
    def test_empty(self):
192
673
        """For an empty branch, the body is empty."""
193
674
        backing = self.get_transport()
194
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
675
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
195
676
        self.make_branch('.')
196
 
        self.assertEqual(SmartServerResponse(('ok', ), ''),
197
 
            request.execute(backing.local_abspath('')))
 
677
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), ''),
 
678
            request.execute(''))
198
679
 
199
680
    def test_not_empty(self):
200
681
        """For a non-empty branch, the body is empty."""
201
682
        backing = self.get_transport()
202
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
683
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
203
684
        tree = self.make_branch_and_memory_tree('.')
204
685
        tree.lock_write()
205
686
        tree.add('')
207
688
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
208
689
        tree.unlock()
209
690
        self.assertEqual(
210
 
            SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
211
 
            request.execute(backing.local_abspath('')))
212
 
 
213
 
 
214
 
class TestSmartServerBranchRequest(tests.TestCaseWithTransport):
 
691
            smart_req.SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
 
692
            request.execute(''))
 
693
 
 
694
 
 
695
class TestSmartServerBranchRequest(tests.TestCaseWithMemoryTransport):
215
696
 
216
697
    def test_no_branch(self):
217
698
        """When there is a bzrdir and no branch, NotBranchError is raised."""
218
699
        backing = self.get_transport()
219
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
700
        request = smart_branch.SmartServerBranchRequest(backing)
220
701
        self.make_bzrdir('.')
221
702
        self.assertRaises(errors.NotBranchError,
222
 
            request.execute, backing.local_abspath(''))
 
703
            request.execute, '')
223
704
 
224
705
    def test_branch_reference(self):
225
706
        """When there is a branch reference, NotBranchError is raised."""
226
707
        backing = self.get_transport()
227
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
708
        request = smart_branch.SmartServerBranchRequest(backing)
228
709
        branch = self.make_branch('branch')
229
710
        checkout = branch.create_checkout('reference',lightweight=True)
230
711
        self.assertRaises(errors.NotBranchError,
231
 
            request.execute, backing.local_abspath('checkout'))
232
 
 
233
 
 
234
 
class TestSmartServerBranchRequestLastRevisionInfo(tests.TestCaseWithTransport):
 
712
            request.execute, 'checkout')
 
713
 
 
714
 
 
715
class TestSmartServerBranchRequestLastRevisionInfo(
 
716
    tests.TestCaseWithMemoryTransport):
235
717
 
236
718
    def test_empty(self):
237
719
        """For an empty branch, the result is ('ok', '0', 'null:')."""
238
720
        backing = self.get_transport()
239
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
721
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
240
722
        self.make_branch('.')
241
 
        self.assertEqual(SmartServerResponse(('ok', '0', 'null:')),
242
 
            request.execute(backing.local_abspath('')))
 
723
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0', 'null:')),
 
724
            request.execute(''))
243
725
 
244
726
    def test_not_empty(self):
245
727
        """For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
246
728
        backing = self.get_transport()
247
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
729
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
248
730
        tree = self.make_branch_and_memory_tree('.')
249
731
        tree.lock_write()
250
732
        tree.add('')
253
735
        r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
254
736
        tree.unlock()
255
737
        self.assertEqual(
256
 
            SmartServerResponse(('ok', '2', rev_id_utf8)),
257
 
            request.execute(backing.local_abspath('')))
258
 
 
259
 
 
260
 
class TestSmartServerBranchRequestGetConfigFile(tests.TestCaseWithTransport):
 
738
            smart_req.SmartServerResponse(('ok', '2', rev_id_utf8)),
 
739
            request.execute(''))
 
740
 
 
741
 
 
742
class TestSmartServerBranchRequestGetConfigFile(
 
743
    tests.TestCaseWithMemoryTransport):
261
744
 
262
745
    def test_default(self):
263
746
        """With no file, we get empty content."""
264
747
        backing = self.get_transport()
265
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
 
748
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
266
749
        branch = self.make_branch('.')
267
750
        # there should be no file by default
268
751
        content = ''
269
 
        self.assertEqual(SmartServerResponse(('ok', ), content),
270
 
            request.execute(backing.local_abspath('')))
 
752
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), content),
 
753
            request.execute(''))
271
754
 
272
755
    def test_with_content(self):
273
756
        # SmartServerBranchGetConfigFile should return the content from
274
757
        # branch.control_files.get('branch.conf') for now - in the future it may
275
 
        # perform more complex processing. 
276
 
        backing = self.get_transport()
277
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
278
 
        branch = self.make_branch('.')
279
 
        branch.control_files.put_utf8('branch.conf', 'foo bar baz')
280
 
        self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
281
 
            request.execute(backing.local_abspath('')))
282
 
 
283
 
 
284
 
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
285
 
 
286
 
    def test_empty(self):
287
 
        backing = self.get_transport()
288
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
289
 
        b = self.make_branch('.')
290
 
        branch_token = b.lock_write()
291
 
        repo_token = b.repository.lock_write()
292
 
        b.repository.unlock()
293
 
        try:
294
 
            self.assertEqual(SmartServerResponse(('ok',)),
295
 
                request.execute(
296
 
                    backing.local_abspath(''), branch_token, repo_token,
297
 
                    'null:'))
298
 
        finally:
299
 
            b.unlock()
300
 
 
301
 
    def test_not_present_revision_id(self):
302
 
        backing = self.get_transport()
303
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
304
 
        b = self.make_branch('.')
305
 
        branch_token = b.lock_write()
306
 
        repo_token = b.repository.lock_write()
307
 
        b.repository.unlock()
308
 
        try:
309
 
            revision_id = 'non-existent revision'
310
 
            self.assertEqual(
311
 
                SmartServerResponse(('NoSuchRevision', revision_id)),
312
 
                request.execute(
313
 
                    backing.local_abspath(''), branch_token, repo_token,
314
 
                    revision_id))
315
 
        finally:
316
 
            b.unlock()
317
 
 
318
 
    def test_revision_id_present(self):
319
 
        backing = self.get_transport()
320
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
321
 
        tree = self.make_branch_and_memory_tree('.')
322
 
        tree.lock_write()
323
 
        tree.add('')
324
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
325
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
326
 
        r2 = tree.commit('2nd commit')
327
 
        tree.unlock()
328
 
        branch_token = tree.branch.lock_write()
329
 
        repo_token = tree.branch.repository.lock_write()
330
 
        tree.branch.repository.unlock()
331
 
        try:
332
 
            self.assertEqual(
333
 
                SmartServerResponse(('ok',)),
334
 
                request.execute(
335
 
                    backing.local_abspath(''), branch_token, repo_token,
336
 
                    rev_id_utf8))
337
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
338
 
        finally:
339
 
            tree.branch.unlock()
340
 
 
341
 
    def test_revision_id_present2(self):
342
 
        backing = self.get_transport()
343
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
344
 
        tree = self.make_branch_and_memory_tree('.')
345
 
        tree.lock_write()
346
 
        tree.add('')
347
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
348
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
349
 
        r2 = tree.commit('2nd commit')
350
 
        tree.unlock()
351
 
        tree.branch.set_revision_history([])
352
 
        branch_token = tree.branch.lock_write()
353
 
        repo_token = tree.branch.repository.lock_write()
354
 
        tree.branch.repository.unlock()
355
 
        try:
356
 
            self.assertEqual(
357
 
                SmartServerResponse(('ok',)),
358
 
                request.execute(
359
 
                    backing.local_abspath(''), branch_token, repo_token,
360
 
                    rev_id_utf8))
361
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
362
 
        finally:
363
 
            tree.branch.unlock()
364
 
 
365
 
 
366
 
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
367
 
 
368
 
    def setUp(self):
369
 
        tests.TestCaseWithTransport.setUp(self)
370
 
        self.reduceLockdirTimeout()
 
758
        # perform more complex processing.
 
759
        backing = self.get_transport()
 
760
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
 
761
        branch = self.make_branch('.')
 
762
        branch._transport.put_bytes('branch.conf', 'foo bar baz')
 
763
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'foo bar baz'),
 
764
            request.execute(''))
 
765
 
 
766
 
 
767
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
 
768
 
 
769
    def get_lock_tokens(self, branch):
 
770
        branch_token = branch.lock_write()
 
771
        repo_token = branch.repository.lock_write()
 
772
        branch.repository.unlock()
 
773
        return branch_token, repo_token
 
774
 
 
775
 
 
776
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
 
777
 
 
778
    def test_value_name(self):
 
779
        branch = self.make_branch('.')
 
780
        request = smart_branch.SmartServerBranchRequestSetConfigOption(
 
781
            branch.bzrdir.root_transport)
 
782
        branch_token, repo_token = self.get_lock_tokens(branch)
 
783
        config = branch._get_config()
 
784
        result = request.execute('', branch_token, repo_token, 'bar', 'foo',
 
785
            '')
 
786
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
787
        self.assertEqual('bar', config.get_option('foo'))
 
788
        # Cleanup
 
789
        branch.unlock()
 
790
 
 
791
    def test_value_name_section(self):
 
792
        branch = self.make_branch('.')
 
793
        request = smart_branch.SmartServerBranchRequestSetConfigOption(
 
794
            branch.bzrdir.root_transport)
 
795
        branch_token, repo_token = self.get_lock_tokens(branch)
 
796
        config = branch._get_config()
 
797
        result = request.execute('', branch_token, repo_token, 'bar', 'foo',
 
798
            'gam')
 
799
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
800
        self.assertEqual('bar', config.get_option('foo', 'gam'))
 
801
        # Cleanup
 
802
        branch.unlock()
 
803
 
 
804
 
 
805
class TestSmartServerBranchRequestSetTagsBytes(TestLockedBranch):
 
806
    # Only called when the branch format and tags match [yay factory
 
807
    # methods] so only need to test straight forward cases.
 
808
 
 
809
    def test_set_bytes(self):
 
810
        base_branch = self.make_branch('base')
 
811
        tag_bytes = base_branch._get_tags_bytes()
 
812
        # get_lock_tokens takes out a lock.
 
813
        branch_token, repo_token = self.get_lock_tokens(base_branch)
 
814
        request = smart_branch.SmartServerBranchSetTagsBytes(
 
815
            self.get_transport())
 
816
        response = request.execute('base', branch_token, repo_token)
 
817
        self.assertEqual(None, response)
 
818
        response = request.do_chunk(tag_bytes)
 
819
        self.assertEqual(None, response)
 
820
        response = request.do_end()
 
821
        self.assertEquals(
 
822
            smart_req.SuccessfulSmartServerResponse(()), response)
 
823
        base_branch.unlock()
 
824
 
 
825
    def test_lock_failed(self):
 
826
        base_branch = self.make_branch('base')
 
827
        base_branch.lock_write()
 
828
        tag_bytes = base_branch._get_tags_bytes()
 
829
        request = smart_branch.SmartServerBranchSetTagsBytes(
 
830
            self.get_transport())
 
831
        self.assertRaises(errors.TokenMismatch, request.execute,
 
832
            'base', 'wrong token', 'wrong token')
 
833
        # The request handler will keep processing the message parts, so even
 
834
        # if the request fails immediately do_chunk and do_end are still
 
835
        # called.
 
836
        request.do_chunk(tag_bytes)
 
837
        request.do_end()
 
838
        base_branch.unlock()
 
839
 
 
840
 
 
841
 
 
842
class SetLastRevisionTestBase(TestLockedBranch):
 
843
    """Base test case for verbs that implement set_last_revision."""
 
844
 
 
845
    def setUp(self):
 
846
        tests.TestCaseWithMemoryTransport.setUp(self)
 
847
        backing_transport = self.get_transport()
 
848
        self.request = self.request_class(backing_transport)
 
849
        self.tree = self.make_branch_and_memory_tree('.')
 
850
 
 
851
    def lock_branch(self):
 
852
        return self.get_lock_tokens(self.tree.branch)
 
853
 
 
854
    def unlock_branch(self):
 
855
        self.tree.branch.unlock()
 
856
 
 
857
    def set_last_revision(self, revision_id, revno):
 
858
        branch_token, repo_token = self.lock_branch()
 
859
        response = self._set_last_revision(
 
860
            revision_id, revno, branch_token, repo_token)
 
861
        self.unlock_branch()
 
862
        return response
 
863
 
 
864
    def assertRequestSucceeds(self, revision_id, revno):
 
865
        response = self.set_last_revision(revision_id, revno)
 
866
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
867
                         response)
 
868
 
 
869
 
 
870
class TestSetLastRevisionVerbMixin(object):
 
871
    """Mixin test case for verbs that implement set_last_revision."""
 
872
 
 
873
    def test_set_null_to_null(self):
 
874
        """An empty branch can have its last revision set to 'null:'."""
 
875
        self.assertRequestSucceeds('null:', 0)
 
876
 
 
877
    def test_NoSuchRevision(self):
 
878
        """If the revision_id is not present, the verb returns NoSuchRevision.
 
879
        """
 
880
        revision_id = 'non-existent revision'
 
881
        self.assertEqual(smart_req.FailedSmartServerResponse(('NoSuchRevision',
 
882
                                                              revision_id)),
 
883
                         self.set_last_revision(revision_id, 1))
 
884
 
 
885
    def make_tree_with_two_commits(self):
 
886
        self.tree.lock_write()
 
887
        self.tree.add('')
 
888
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
889
        r1 = self.tree.commit('1st commit', rev_id=rev_id_utf8)
 
890
        r2 = self.tree.commit('2nd commit', rev_id='rev-2')
 
891
        self.tree.unlock()
 
892
 
 
893
    def test_branch_last_revision_info_is_updated(self):
 
894
        """A branch's tip can be set to a revision that is present in its
 
895
        repository.
 
896
        """
 
897
        # Make a branch with an empty revision history, but two revisions in
 
898
        # its repository.
 
899
        self.make_tree_with_two_commits()
 
900
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
901
        self.tree.branch.set_revision_history([])
 
902
        self.assertEqual(
 
903
            (0, 'null:'), self.tree.branch.last_revision_info())
 
904
        # We can update the branch to a revision that is present in the
 
905
        # repository.
 
906
        self.assertRequestSucceeds(rev_id_utf8, 1)
 
907
        self.assertEqual(
 
908
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
909
 
 
910
    def test_branch_last_revision_info_rewind(self):
 
911
        """A branch's tip can be set to a revision that is an ancestor of the
 
912
        current tip.
 
913
        """
 
914
        self.make_tree_with_two_commits()
 
915
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
916
        self.assertEqual(
 
917
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
918
        self.assertRequestSucceeds(rev_id_utf8, 1)
 
919
        self.assertEqual(
 
920
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
921
 
 
922
    def test_TipChangeRejected(self):
 
923
        """If a pre_change_branch_tip hook raises TipChangeRejected, the verb
 
924
        returns TipChangeRejected.
 
925
        """
 
926
        rejection_message = u'rejection message\N{INTERROBANG}'
 
927
        def hook_that_rejects(params):
 
928
            raise errors.TipChangeRejected(rejection_message)
 
929
        _mod_branch.Branch.hooks.install_named_hook(
 
930
            'pre_change_branch_tip', hook_that_rejects, None)
 
931
        self.assertEqual(
 
932
            smart_req.FailedSmartServerResponse(
 
933
                ('TipChangeRejected', rejection_message.encode('utf-8'))),
 
934
            self.set_last_revision('null:', 0))
 
935
 
 
936
 
 
937
class TestSmartServerBranchRequestSetLastRevision(
 
938
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
939
    """Tests for Branch.set_last_revision verb."""
 
940
 
 
941
    request_class = smart_branch.SmartServerBranchRequestSetLastRevision
 
942
 
 
943
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
944
        return self.request.execute(
 
945
            '', branch_token, repo_token, revision_id)
 
946
 
 
947
 
 
948
class TestSmartServerBranchRequestSetLastRevisionInfo(
 
949
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
950
    """Tests for Branch.set_last_revision_info verb."""
 
951
 
 
952
    request_class = smart_branch.SmartServerBranchRequestSetLastRevisionInfo
 
953
 
 
954
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
955
        return self.request.execute(
 
956
            '', branch_token, repo_token, revno, revision_id)
 
957
 
 
958
    def test_NoSuchRevision(self):
 
959
        """Branch.set_last_revision_info does not have to return
 
960
        NoSuchRevision if the revision_id is absent.
 
961
        """
 
962
        raise tests.TestNotApplicable()
 
963
 
 
964
 
 
965
class TestSmartServerBranchRequestSetLastRevisionEx(
 
966
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
967
    """Tests for Branch.set_last_revision_ex verb."""
 
968
 
 
969
    request_class = smart_branch.SmartServerBranchRequestSetLastRevisionEx
 
970
 
 
971
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
972
        return self.request.execute(
 
973
            '', branch_token, repo_token, revision_id, 0, 0)
 
974
 
 
975
    def assertRequestSucceeds(self, revision_id, revno):
 
976
        response = self.set_last_revision(revision_id, revno)
 
977
        self.assertEqual(
 
978
            smart_req.SuccessfulSmartServerResponse(('ok', revno, revision_id)),
 
979
            response)
 
980
 
 
981
    def test_branch_last_revision_info_rewind(self):
 
982
        """A branch's tip can be set to a revision that is an ancestor of the
 
983
        current tip, but only if allow_overwrite_descendant is passed.
 
984
        """
 
985
        self.make_tree_with_two_commits()
 
986
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
987
        self.assertEqual(
 
988
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
989
        # If allow_overwrite_descendant flag is 0, then trying to set the tip
 
990
        # to an older revision ID has no effect.
 
991
        branch_token, repo_token = self.lock_branch()
 
992
        response = self.request.execute(
 
993
            '', branch_token, repo_token, rev_id_utf8, 0, 0)
 
994
        self.assertEqual(
 
995
            smart_req.SuccessfulSmartServerResponse(('ok', 2, 'rev-2')),
 
996
            response)
 
997
        self.assertEqual(
 
998
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
999
 
 
1000
        # If allow_overwrite_descendant flag is 1, then setting the tip to an
 
1001
        # ancestor works.
 
1002
        response = self.request.execute(
 
1003
            '', branch_token, repo_token, rev_id_utf8, 0, 1)
 
1004
        self.assertEqual(
 
1005
            smart_req.SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)),
 
1006
            response)
 
1007
        self.unlock_branch()
 
1008
        self.assertEqual(
 
1009
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1010
 
 
1011
    def make_branch_with_divergent_history(self):
 
1012
        """Make a branch with divergent history in its repo.
 
1013
 
 
1014
        The branch's tip will be 'child-2', and the repo will also contain
 
1015
        'child-1', which diverges from a common base revision.
 
1016
        """
 
1017
        self.tree.lock_write()
 
1018
        self.tree.add('')
 
1019
        r1 = self.tree.commit('1st commit')
 
1020
        revno_1, revid_1 = self.tree.branch.last_revision_info()
 
1021
        r2 = self.tree.commit('2nd commit', rev_id='child-1')
 
1022
        # Undo the second commit
 
1023
        self.tree.branch.set_last_revision_info(revno_1, revid_1)
 
1024
        self.tree.set_parent_ids([revid_1])
 
1025
        # Make a new second commit, child-2.  child-2 has diverged from
 
1026
        # child-1.
 
1027
        new_r2 = self.tree.commit('2nd commit', rev_id='child-2')
 
1028
        self.tree.unlock()
 
1029
 
 
1030
    def test_not_allow_diverged(self):
 
1031
        """If allow_diverged is not passed, then setting a divergent history
 
1032
        returns a Diverged error.
 
1033
        """
 
1034
        self.make_branch_with_divergent_history()
 
1035
        self.assertEqual(
 
1036
            smart_req.FailedSmartServerResponse(('Diverged',)),
 
1037
            self.set_last_revision('child-1', 2))
 
1038
        # The branch tip was not changed.
 
1039
        self.assertEqual('child-2', self.tree.branch.last_revision())
 
1040
 
 
1041
    def test_allow_diverged(self):
 
1042
        """If allow_diverged is passed, then setting a divergent history
 
1043
        succeeds.
 
1044
        """
 
1045
        self.make_branch_with_divergent_history()
 
1046
        branch_token, repo_token = self.lock_branch()
 
1047
        response = self.request.execute(
 
1048
            '', branch_token, repo_token, 'child-1', 1, 0)
 
1049
        self.assertEqual(
 
1050
            smart_req.SuccessfulSmartServerResponse(('ok', 2, 'child-1')),
 
1051
            response)
 
1052
        self.unlock_branch()
 
1053
        # The branch tip was changed.
 
1054
        self.assertEqual('child-1', self.tree.branch.last_revision())
 
1055
 
 
1056
 
 
1057
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
 
1058
 
 
1059
    def test_get_parent_none(self):
 
1060
        base_branch = self.make_branch('base')
 
1061
        request = smart_branch.SmartServerBranchGetParent(self.get_transport())
 
1062
        response = request.execute('base')
 
1063
        self.assertEquals(
 
1064
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1065
 
 
1066
    def test_get_parent_something(self):
 
1067
        base_branch = self.make_branch('base')
 
1068
        base_branch.set_parent(self.get_url('foo'))
 
1069
        request = smart_branch.SmartServerBranchGetParent(self.get_transport())
 
1070
        response = request.execute('base')
 
1071
        self.assertEquals(
 
1072
            smart_req.SuccessfulSmartServerResponse(("../foo",)),
 
1073
            response)
 
1074
 
 
1075
 
 
1076
class TestSmartServerBranchRequestSetParent(tests.TestCaseWithMemoryTransport):
 
1077
 
 
1078
    def test_set_parent_none(self):
 
1079
        branch = self.make_branch('base', format="1.9")
 
1080
        branch.lock_write()
 
1081
        branch._set_parent_location('foo')
 
1082
        branch.unlock()
 
1083
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1084
            self.get_transport())
 
1085
        branch_token = branch.lock_write()
 
1086
        repo_token = branch.repository.lock_write()
 
1087
        try:
 
1088
            response = request.execute('base', branch_token, repo_token, '')
 
1089
        finally:
 
1090
            branch.repository.unlock()
 
1091
            branch.unlock()
 
1092
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1093
        self.assertEqual(None, branch.get_parent())
 
1094
 
 
1095
    def test_set_parent_something(self):
 
1096
        branch = self.make_branch('base', format="1.9")
 
1097
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1098
            self.get_transport())
 
1099
        branch_token = branch.lock_write()
 
1100
        repo_token = branch.repository.lock_write()
 
1101
        try:
 
1102
            response = request.execute('base', branch_token, repo_token,
 
1103
            'http://bar/')
 
1104
        finally:
 
1105
            branch.repository.unlock()
 
1106
            branch.unlock()
 
1107
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1108
        self.assertEqual('http://bar/', branch.get_parent())
 
1109
 
 
1110
 
 
1111
class TestSmartServerBranchRequestGetTagsBytes(
 
1112
    tests.TestCaseWithMemoryTransport):
 
1113
    # Only called when the branch format and tags match [yay factory
 
1114
    # methods] so only need to test straight forward cases.
 
1115
 
 
1116
    def test_get_bytes(self):
 
1117
        base_branch = self.make_branch('base')
 
1118
        request = smart_branch.SmartServerBranchGetTagsBytes(
 
1119
            self.get_transport())
 
1120
        response = request.execute('base')
 
1121
        self.assertEquals(
 
1122
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1123
 
 
1124
 
 
1125
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
 
1126
 
 
1127
    def test_get_stacked_on_url(self):
 
1128
        base_branch = self.make_branch('base', format='1.6')
 
1129
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1130
        # typically should be relative
 
1131
        stacked_branch.set_stacked_on_url('../base')
 
1132
        request = smart_branch.SmartServerBranchRequestGetStackedOnURL(
 
1133
            self.get_transport())
 
1134
        response = request.execute('stacked')
 
1135
        self.assertEquals(
 
1136
            smart_req.SmartServerResponse(('ok', '../base')),
 
1137
            response)
 
1138
 
 
1139
 
 
1140
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithMemoryTransport):
 
1141
 
 
1142
    def setUp(self):
 
1143
        tests.TestCaseWithMemoryTransport.setUp(self)
371
1144
 
372
1145
    def test_lock_write_on_unlocked_branch(self):
373
1146
        backing = self.get_transport()
374
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
375
 
        branch = self.make_branch('.')
 
1147
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1148
        branch = self.make_branch('.', format='knit')
376
1149
        repository = branch.repository
377
 
        response = request.execute(backing.local_abspath(''))
 
1150
        response = request.execute('')
378
1151
        branch_nonce = branch.control_files._lock.peek().get('nonce')
379
1152
        repository_nonce = repository.control_files._lock.peek().get('nonce')
380
 
        self.assertEqual(
381
 
            SmartServerResponse(('ok', branch_nonce, repository_nonce)),
382
 
            response)
 
1153
        self.assertEqual(smart_req.SmartServerResponse(
 
1154
                ('ok', branch_nonce, repository_nonce)),
 
1155
                         response)
383
1156
        # The branch (and associated repository) is now locked.  Verify that
384
1157
        # with a new branch object.
385
1158
        new_branch = repository.bzrdir.open_branch()
386
1159
        self.assertRaises(errors.LockContention, new_branch.lock_write)
 
1160
        # Cleanup
 
1161
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1162
        response = request.execute('', branch_nonce, repository_nonce)
387
1163
 
388
1164
    def test_lock_write_on_locked_branch(self):
389
1165
        backing = self.get_transport()
390
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1166
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
391
1167
        branch = self.make_branch('.')
392
 
        branch.lock_write()
 
1168
        branch_token = branch.lock_write()
393
1169
        branch.leave_lock_in_place()
394
1170
        branch.unlock()
395
 
        response = request.execute(backing.local_abspath(''))
 
1171
        response = request.execute('')
396
1172
        self.assertEqual(
397
 
            SmartServerResponse(('LockContention',)), response)
 
1173
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1174
        # Cleanup
 
1175
        branch.lock_write(branch_token)
 
1176
        branch.dont_leave_lock_in_place()
 
1177
        branch.unlock()
398
1178
 
399
1179
    def test_lock_write_with_tokens_on_locked_branch(self):
400
1180
        backing = self.get_transport()
401
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
402
 
        branch = self.make_branch('.')
 
1181
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1182
        branch = self.make_branch('.', format='knit')
403
1183
        branch_token = branch.lock_write()
404
1184
        repo_token = branch.repository.lock_write()
405
1185
        branch.repository.unlock()
406
1186
        branch.leave_lock_in_place()
407
1187
        branch.repository.leave_lock_in_place()
408
1188
        branch.unlock()
409
 
        response = request.execute(backing.local_abspath(''),
 
1189
        response = request.execute('',
410
1190
                                   branch_token, repo_token)
411
1191
        self.assertEqual(
412
 
            SmartServerResponse(('ok', branch_token, repo_token)), response)
 
1192
            smart_req.SmartServerResponse(('ok', branch_token, repo_token)),
 
1193
            response)
 
1194
        # Cleanup
 
1195
        branch.repository.lock_write(repo_token)
 
1196
        branch.repository.dont_leave_lock_in_place()
 
1197
        branch.repository.unlock()
 
1198
        branch.lock_write(branch_token)
 
1199
        branch.dont_leave_lock_in_place()
 
1200
        branch.unlock()
413
1201
 
414
1202
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
415
1203
        backing = self.get_transport()
416
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
417
 
        branch = self.make_branch('.')
 
1204
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1205
        branch = self.make_branch('.', format='knit')
418
1206
        branch_token = branch.lock_write()
419
1207
        repo_token = branch.repository.lock_write()
420
1208
        branch.repository.unlock()
421
1209
        branch.leave_lock_in_place()
422
1210
        branch.repository.leave_lock_in_place()
423
1211
        branch.unlock()
424
 
        response = request.execute(backing.local_abspath(''),
 
1212
        response = request.execute('',
425
1213
                                   branch_token+'xxx', repo_token)
426
1214
        self.assertEqual(
427
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1215
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1216
        # Cleanup
 
1217
        branch.repository.lock_write(repo_token)
 
1218
        branch.repository.dont_leave_lock_in_place()
 
1219
        branch.repository.unlock()
 
1220
        branch.lock_write(branch_token)
 
1221
        branch.dont_leave_lock_in_place()
 
1222
        branch.unlock()
428
1223
 
429
1224
    def test_lock_write_on_locked_repo(self):
430
1225
        backing = self.get_transport()
431
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
432
 
        branch = self.make_branch('.')
433
 
        branch.repository.lock_write()
434
 
        branch.repository.leave_lock_in_place()
435
 
        branch.repository.unlock()
436
 
        response = request.execute(backing.local_abspath(''))
 
1226
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1227
        branch = self.make_branch('.', format='knit')
 
1228
        repo = branch.repository
 
1229
        repo_token = repo.lock_write()
 
1230
        repo.leave_lock_in_place()
 
1231
        repo.unlock()
 
1232
        response = request.execute('')
437
1233
        self.assertEqual(
438
 
            SmartServerResponse(('LockContention',)), response)
 
1234
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1235
        # Cleanup
 
1236
        repo.lock_write(repo_token)
 
1237
        repo.dont_leave_lock_in_place()
 
1238
        repo.unlock()
439
1239
 
440
1240
    def test_lock_write_on_readonly_transport(self):
441
1241
        backing = self.get_readonly_transport()
442
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1242
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
443
1243
        branch = self.make_branch('.')
444
 
        response = request.execute('')
 
1244
        root = self.get_transport().clone('/')
 
1245
        path = urlutils.relative_url(root.base, self.get_transport().base)
 
1246
        response = request.execute(path)
445
1247
        error_name, lock_str, why_str = response.args
446
1248
        self.assertFalse(response.is_successful())
447
1249
        self.assertEqual('LockFailed', error_name)
448
1250
 
449
1251
 
450
 
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
 
1252
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithMemoryTransport):
451
1253
 
452
1254
    def setUp(self):
453
 
        tests.TestCaseWithTransport.setUp(self)
454
 
        self.reduceLockdirTimeout()
 
1255
        tests.TestCaseWithMemoryTransport.setUp(self)
455
1256
 
456
1257
    def test_unlock_on_locked_branch_and_repo(self):
457
1258
        backing = self.get_transport()
458
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
459
 
        branch = self.make_branch('.')
 
1259
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1260
        branch = self.make_branch('.', format='knit')
460
1261
        # Lock the branch
461
1262
        branch_token = branch.lock_write()
462
1263
        repo_token = branch.repository.lock_write()
466
1267
        branch.leave_lock_in_place()
467
1268
        branch.repository.leave_lock_in_place()
468
1269
        branch.unlock()
469
 
        response = request.execute(backing.local_abspath(''),
 
1270
        response = request.execute('',
470
1271
                                   branch_token, repo_token)
471
1272
        self.assertEqual(
472
 
            SmartServerResponse(('ok',)), response)
 
1273
            smart_req.SmartServerResponse(('ok',)), response)
473
1274
        # The branch is now unlocked.  Verify that with a new branch
474
1275
        # object.
475
1276
        new_branch = branch.bzrdir.open_branch()
478
1279
 
479
1280
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
480
1281
        backing = self.get_transport()
481
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
482
 
        branch = self.make_branch('.')
 
1282
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1283
        branch = self.make_branch('.', format='knit')
483
1284
        response = request.execute(
484
 
            backing.local_abspath(''), 'branch token', 'repo token')
 
1285
            '', 'branch token', 'repo token')
485
1286
        self.assertEqual(
486
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1287
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
487
1288
 
488
1289
    def test_unlock_on_unlocked_branch_locked_repo(self):
489
1290
        backing = self.get_transport()
490
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
491
 
        branch = self.make_branch('.')
 
1291
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1292
        branch = self.make_branch('.', format='knit')
492
1293
        # Lock the repository.
493
1294
        repo_token = branch.repository.lock_write()
494
1295
        branch.repository.leave_lock_in_place()
496
1297
        # Issue branch lock_write request on the unlocked branch (with locked
497
1298
        # repo).
498
1299
        response = request.execute(
499
 
            backing.local_abspath(''), 'branch token', repo_token)
 
1300
            '', 'branch token', repo_token)
500
1301
        self.assertEqual(
501
 
            SmartServerResponse(('TokenMismatch',)), response)
502
 
 
503
 
 
504
 
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
 
1302
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1303
        # Cleanup
 
1304
        branch.repository.lock_write(repo_token)
 
1305
        branch.repository.dont_leave_lock_in_place()
 
1306
        branch.repository.unlock()
 
1307
 
 
1308
 
 
1309
class TestSmartServerRepositoryRequest(tests.TestCaseWithMemoryTransport):
505
1310
 
506
1311
    def test_no_repository(self):
507
1312
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
510
1315
        # its the exact path being looked at and the server is not
511
1316
        # searching.
512
1317
        backing = self.get_transport()
513
 
        request = smart.repository.SmartServerRepositoryRequest(backing)
 
1318
        request = smart_repo.SmartServerRepositoryRequest(backing)
514
1319
        self.make_repository('.', shared=True)
515
1320
        self.make_bzrdir('subdir')
516
1321
        self.assertRaises(errors.NoRepositoryPresent,
517
 
            request.execute, backing.local_abspath('subdir'))
518
 
 
519
 
 
520
 
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
 
1322
            request.execute, 'subdir')
 
1323
 
 
1324
 
 
1325
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithMemoryTransport):
 
1326
 
 
1327
    def test_trivial_bzipped(self):
 
1328
        # This tests that the wire encoding is actually bzipped
 
1329
        backing = self.get_transport()
 
1330
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1331
        tree = self.make_branch_and_memory_tree('.')
 
1332
 
 
1333
        self.assertEqual(None,
 
1334
            request.execute('', 'missing-id'))
 
1335
        # Note that it returns a body that is bzipped.
 
1336
        self.assertEqual(
 
1337
            smart_req.SuccessfulSmartServerResponse(('ok', ), bz2.compress('')),
 
1338
            request.do_body('\n\n0\n'))
 
1339
 
 
1340
    def test_trivial_include_missing(self):
 
1341
        backing = self.get_transport()
 
1342
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1343
        tree = self.make_branch_and_memory_tree('.')
 
1344
 
 
1345
        self.assertEqual(None,
 
1346
            request.execute('', 'missing-id', 'include-missing:'))
 
1347
        self.assertEqual(
 
1348
            smart_req.SuccessfulSmartServerResponse(('ok', ),
 
1349
                bz2.compress('missing:missing-id')),
 
1350
            request.do_body('\n\n0\n'))
 
1351
 
 
1352
 
 
1353
class TestSmartServerRepositoryGetRevisionGraph(
 
1354
    tests.TestCaseWithMemoryTransport):
521
1355
 
522
1356
    def test_none_argument(self):
523
1357
        backing = self.get_transport()
524
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1358
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
525
1359
        tree = self.make_branch_and_memory_tree('.')
526
1360
        tree.lock_write()
527
1361
        tree.add('')
532
1366
        # the lines of revision_id->revision_parent_list has no guaranteed
533
1367
        # order coming out of a dict, so sort both our test and response
534
1368
        lines = sorted([' '.join([r2, r1]), r1])
535
 
        response = request.execute(backing.local_abspath(''), '')
 
1369
        response = request.execute('', '')
536
1370
        response.body = '\n'.join(sorted(response.body.split('\n')))
537
1371
 
538
1372
        self.assertEqual(
539
 
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
 
1373
            smart_req.SmartServerResponse(('ok', ), '\n'.join(lines)), response)
540
1374
 
541
1375
    def test_specific_revision_argument(self):
542
1376
        backing = self.get_transport()
543
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1377
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
544
1378
        tree = self.make_branch_and_memory_tree('.')
545
1379
        tree.lock_write()
546
1380
        tree.add('')
549
1383
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
550
1384
        tree.unlock()
551
1385
 
552
 
        self.assertEqual(SmartServerResponse(('ok', ), rev_id_utf8),
553
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
554
 
    
 
1386
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), rev_id_utf8),
 
1387
            request.execute('', rev_id_utf8))
 
1388
 
555
1389
    def test_no_such_revision(self):
556
1390
        backing = self.get_transport()
557
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1391
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
558
1392
        tree = self.make_branch_and_memory_tree('.')
559
1393
        tree.lock_write()
560
1394
        tree.add('')
562
1396
        tree.unlock()
563
1397
 
564
1398
        # Note that it still returns body (of zero bytes).
565
 
        self.assertEqual(
566
 
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
567
 
            request.execute(backing.local_abspath(''), 'missingrevision'))
568
 
 
569
 
 
570
 
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
 
1399
        self.assertEqual(smart_req.SmartServerResponse(
 
1400
                ('nosuchrevision', 'missingrevision', ), ''),
 
1401
                         request.execute('', 'missingrevision'))
 
1402
 
 
1403
 
 
1404
class TestSmartServerRepositoryGetRevIdForRevno(
 
1405
    tests.TestCaseWithMemoryTransport):
 
1406
 
 
1407
    def test_revno_found(self):
 
1408
        backing = self.get_transport()
 
1409
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1410
        tree = self.make_branch_and_memory_tree('.')
 
1411
        tree.lock_write()
 
1412
        tree.add('')
 
1413
        rev1_id_utf8 = u'\xc8'.encode('utf-8')
 
1414
        rev2_id_utf8 = u'\xc9'.encode('utf-8')
 
1415
        tree.commit('1st commit', rev_id=rev1_id_utf8)
 
1416
        tree.commit('2nd commit', rev_id=rev2_id_utf8)
 
1417
        tree.unlock()
 
1418
 
 
1419
        self.assertEqual(smart_req.SmartServerResponse(('ok', rev1_id_utf8)),
 
1420
            request.execute('', 1, (2, rev2_id_utf8)))
 
1421
 
 
1422
    def test_known_revid_missing(self):
 
1423
        backing = self.get_transport()
 
1424
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1425
        repo = self.make_repository('.')
 
1426
        self.assertEqual(
 
1427
            smart_req.FailedSmartServerResponse(('nosuchrevision', 'ghost')),
 
1428
            request.execute('', 1, (2, 'ghost')))
 
1429
 
 
1430
    def test_history_incomplete(self):
 
1431
        backing = self.get_transport()
 
1432
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1433
        parent = self.make_branch_and_memory_tree('parent', format='1.9')
 
1434
        parent.lock_write()
 
1435
        parent.add([''], ['TREE_ROOT'])
 
1436
        r1 = parent.commit(message='first commit')
 
1437
        r2 = parent.commit(message='second commit')
 
1438
        parent.unlock()
 
1439
        local = self.make_branch_and_memory_tree('local', format='1.9')
 
1440
        local.branch.pull(parent.branch)
 
1441
        local.set_parent_ids([r2])
 
1442
        r3 = local.commit(message='local commit')
 
1443
        local.branch.create_clone_on_transport(
 
1444
            self.get_transport('stacked'), stacked_on=self.get_url('parent'))
 
1445
        self.assertEqual(
 
1446
            smart_req.SmartServerResponse(('history-incomplete', 2, r2)),
 
1447
            request.execute('stacked', 1, (3, r3)))
 
1448
 
 
1449
 
 
1450
class TestSmartServerRepositoryGetStream(tests.TestCaseWithMemoryTransport):
 
1451
 
 
1452
    def make_two_commit_repo(self):
 
1453
        tree = self.make_branch_and_memory_tree('.')
 
1454
        tree.lock_write()
 
1455
        tree.add('')
 
1456
        r1 = tree.commit('1st commit')
 
1457
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
 
1458
        tree.unlock()
 
1459
        repo = tree.branch.repository
 
1460
        return repo, r1, r2
 
1461
 
 
1462
    def test_ancestry_of(self):
 
1463
        """The search argument may be a 'ancestry-of' some heads'."""
 
1464
        backing = self.get_transport()
 
1465
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1466
        repo, r1, r2 = self.make_two_commit_repo()
 
1467
        fetch_spec = ['ancestry-of', r2]
 
1468
        lines = '\n'.join(fetch_spec)
 
1469
        request.execute('', repo._format.network_name())
 
1470
        response = request.do_body(lines)
 
1471
        self.assertEqual(('ok',), response.args)
 
1472
        stream_bytes = ''.join(response.body_stream)
 
1473
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1474
 
 
1475
    def test_search(self):
 
1476
        """The search argument may be a 'search' of some explicit keys."""
 
1477
        backing = self.get_transport()
 
1478
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1479
        repo, r1, r2 = self.make_two_commit_repo()
 
1480
        fetch_spec = ['search', '%s %s' % (r1, r2), 'null:', '2']
 
1481
        lines = '\n'.join(fetch_spec)
 
1482
        request.execute('', repo._format.network_name())
 
1483
        response = request.do_body(lines)
 
1484
        self.assertEqual(('ok',), response.args)
 
1485
        stream_bytes = ''.join(response.body_stream)
 
1486
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1487
 
 
1488
 
 
1489
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
571
1490
 
572
1491
    def test_missing_revision(self):
573
1492
        """For a missing revision, ('no', ) is returned."""
574
1493
        backing = self.get_transport()
575
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1494
        request = smart_repo.SmartServerRequestHasRevision(backing)
576
1495
        self.make_repository('.')
577
 
        self.assertEqual(SmartServerResponse(('no', )),
578
 
            request.execute(backing.local_abspath(''), 'revid'))
 
1496
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1497
            request.execute('', 'revid'))
579
1498
 
580
1499
    def test_present_revision(self):
581
1500
        """For a present revision, ('yes', ) is returned."""
582
1501
        backing = self.get_transport()
583
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1502
        request = smart_repo.SmartServerRequestHasRevision(backing)
584
1503
        tree = self.make_branch_and_memory_tree('.')
585
1504
        tree.lock_write()
586
1505
        tree.add('')
588
1507
        r1 = tree.commit('a commit', rev_id=rev_id_utf8)
589
1508
        tree.unlock()
590
1509
        self.assertTrue(tree.branch.repository.has_revision(rev_id_utf8))
591
 
        self.assertEqual(SmartServerResponse(('yes', )),
592
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
593
 
 
594
 
 
595
 
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
 
1510
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1511
            request.execute('', rev_id_utf8))
 
1512
 
 
1513
 
 
1514
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithMemoryTransport):
596
1515
 
597
1516
    def test_empty_revid(self):
598
1517
        """With an empty revid, we get only size an number and revisions"""
599
1518
        backing = self.get_transport()
600
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1519
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
601
1520
        repository = self.make_repository('.')
602
1521
        stats = repository.gather_stats()
603
 
        size = stats['size']
604
 
        expected_body = 'revisions: 0\nsize: %d\n' % size
605
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
606
 
                         request.execute(backing.local_abspath(''), '', 'no'))
 
1522
        expected_body = 'revisions: 0\n'
 
1523
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1524
                         request.execute('', '', 'no'))
607
1525
 
608
1526
    def test_revid_with_committers(self):
609
1527
        """For a revid we get more infos."""
610
1528
        backing = self.get_transport()
611
1529
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
612
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1530
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
613
1531
        tree = self.make_branch_and_memory_tree('.')
614
1532
        tree.lock_write()
615
1533
        tree.add('')
620
1538
        tree.unlock()
621
1539
 
622
1540
        stats = tree.branch.repository.gather_stats()
623
 
        size = stats['size']
624
1541
        expected_body = ('firstrev: 123456.200 3600\n'
625
1542
                         'latestrev: 654321.400 0\n'
626
 
                         'revisions: 2\n'
627
 
                         'size: %d\n' % size)
628
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
629
 
                         request.execute(backing.local_abspath(''),
 
1543
                         'revisions: 2\n')
 
1544
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1545
                         request.execute('',
630
1546
                                         rev_id_utf8, 'no'))
631
1547
 
632
1548
    def test_not_empty_repository_with_committers(self):
633
1549
        """For a revid and requesting committers we get the whole thing."""
634
1550
        backing = self.get_transport()
635
1551
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
636
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1552
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
637
1553
        tree = self.make_branch_and_memory_tree('.')
638
1554
        tree.lock_write()
639
1555
        tree.add('')
645
1561
        tree.unlock()
646
1562
        stats = tree.branch.repository.gather_stats()
647
1563
 
648
 
        size = stats['size']
649
1564
        expected_body = ('committers: 2\n'
650
1565
                         'firstrev: 123456.200 3600\n'
651
1566
                         'latestrev: 654321.400 0\n'
652
 
                         'revisions: 2\n'
653
 
                         'size: %d\n' % size)
654
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
655
 
                         request.execute(backing.local_abspath(''),
 
1567
                         'revisions: 2\n')
 
1568
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1569
                         request.execute('',
656
1570
                                         rev_id_utf8, 'yes'))
657
1571
 
658
1572
 
659
 
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
 
1573
class TestSmartServerRepositoryIsShared(tests.TestCaseWithMemoryTransport):
660
1574
 
661
1575
    def test_is_shared(self):
662
1576
        """For a shared repository, ('yes', ) is returned."""
663
1577
        backing = self.get_transport()
664
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
1578
        request = smart_repo.SmartServerRepositoryIsShared(backing)
665
1579
        self.make_repository('.', shared=True)
666
 
        self.assertEqual(SmartServerResponse(('yes', )),
667
 
            request.execute(backing.local_abspath(''), ))
 
1580
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1581
            request.execute('', ))
668
1582
 
669
1583
    def test_is_not_shared(self):
670
1584
        """For a shared repository, ('no', ) is returned."""
671
1585
        backing = self.get_transport()
672
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
1586
        request = smart_repo.SmartServerRepositoryIsShared(backing)
673
1587
        self.make_repository('.', shared=False)
674
 
        self.assertEqual(SmartServerResponse(('no', )),
675
 
            request.execute(backing.local_abspath(''), ))
676
 
 
677
 
 
678
 
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
679
 
 
680
 
    def setUp(self):
681
 
        tests.TestCaseWithTransport.setUp(self)
682
 
        self.reduceLockdirTimeout()
 
1588
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1589
            request.execute('', ))
 
1590
 
 
1591
 
 
1592
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
683
1593
 
684
1594
    def test_lock_write_on_unlocked_repo(self):
685
1595
        backing = self.get_transport()
686
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
687
 
        repository = self.make_repository('.')
688
 
        response = request.execute(backing.local_abspath(''))
 
1596
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
1597
        repository = self.make_repository('.', format='knit')
 
1598
        response = request.execute('')
689
1599
        nonce = repository.control_files._lock.peek().get('nonce')
690
 
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
 
1600
        self.assertEqual(smart_req.SmartServerResponse(('ok', nonce)), response)
691
1601
        # The repository is now locked.  Verify that with a new repository
692
1602
        # object.
693
1603
        new_repo = repository.bzrdir.open_repository()
694
1604
        self.assertRaises(errors.LockContention, new_repo.lock_write)
 
1605
        # Cleanup
 
1606
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
1607
        response = request.execute('', nonce)
695
1608
 
696
1609
    def test_lock_write_on_locked_repo(self):
697
1610
        backing = self.get_transport()
698
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
699
 
        repository = self.make_repository('.')
700
 
        repository.lock_write()
 
1611
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
1612
        repository = self.make_repository('.', format='knit')
 
1613
        repo_token = repository.lock_write()
701
1614
        repository.leave_lock_in_place()
702
1615
        repository.unlock()
703
 
        response = request.execute(backing.local_abspath(''))
 
1616
        response = request.execute('')
704
1617
        self.assertEqual(
705
 
            SmartServerResponse(('LockContention',)), response)
 
1618
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1619
        # Cleanup
 
1620
        repository.lock_write(repo_token)
 
1621
        repository.dont_leave_lock_in_place()
 
1622
        repository.unlock()
706
1623
 
707
1624
    def test_lock_write_on_readonly_transport(self):
708
1625
        backing = self.get_readonly_transport()
709
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
710
 
        repository = self.make_repository('.')
 
1626
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
1627
        repository = self.make_repository('.', format='knit')
711
1628
        response = request.execute('')
712
1629
        self.assertFalse(response.is_successful())
713
1630
        self.assertEqual('LockFailed', response.args[0])
714
1631
 
715
1632
 
716
 
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
 
1633
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
 
1634
 
 
1635
    def make_empty_byte_stream(self, repo):
 
1636
        byte_stream = smart_repo._stream_to_byte_stream([], repo._format)
 
1637
        return ''.join(byte_stream)
 
1638
 
 
1639
 
 
1640
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
 
1641
 
 
1642
    def test_insert_stream_empty(self):
 
1643
        backing = self.get_transport()
 
1644
        request = smart_repo.SmartServerRepositoryInsertStream(backing)
 
1645
        repository = self.make_repository('.')
 
1646
        response = request.execute('', '')
 
1647
        self.assertEqual(None, response)
 
1648
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
1649
        self.assertEqual(None, response)
 
1650
        response = request.do_end()
 
1651
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
1652
 
 
1653
 
 
1654
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
 
1655
 
 
1656
    def test_insert_stream_empty(self):
 
1657
        backing = self.get_transport()
 
1658
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
1659
            backing)
 
1660
        repository = self.make_repository('.', format='knit')
 
1661
        lock_token = repository.lock_write()
 
1662
        response = request.execute('', '', lock_token)
 
1663
        self.assertEqual(None, response)
 
1664
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
1665
        self.assertEqual(None, response)
 
1666
        response = request.do_end()
 
1667
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
1668
        repository.unlock()
 
1669
 
 
1670
    def test_insert_stream_with_wrong_lock_token(self):
 
1671
        backing = self.get_transport()
 
1672
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
1673
            backing)
 
1674
        repository = self.make_repository('.', format='knit')
 
1675
        lock_token = repository.lock_write()
 
1676
        self.assertRaises(
 
1677
            errors.TokenMismatch, request.execute, '', '', 'wrong-token')
 
1678
        repository.unlock()
 
1679
 
 
1680
 
 
1681
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
717
1682
 
718
1683
    def setUp(self):
719
 
        tests.TestCaseWithTransport.setUp(self)
720
 
        self.reduceLockdirTimeout()
 
1684
        tests.TestCaseWithMemoryTransport.setUp(self)
721
1685
 
722
1686
    def test_unlock_on_locked_repo(self):
723
1687
        backing = self.get_transport()
724
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
725
 
        repository = self.make_repository('.')
 
1688
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
1689
        repository = self.make_repository('.', format='knit')
726
1690
        token = repository.lock_write()
727
1691
        repository.leave_lock_in_place()
728
1692
        repository.unlock()
729
 
        response = request.execute(backing.local_abspath(''), token)
 
1693
        response = request.execute('', token)
730
1694
        self.assertEqual(
731
 
            SmartServerResponse(('ok',)), response)
 
1695
            smart_req.SmartServerResponse(('ok',)), response)
732
1696
        # The repository is now unlocked.  Verify that with a new repository
733
1697
        # object.
734
1698
        new_repo = repository.bzrdir.open_repository()
737
1701
 
738
1702
    def test_unlock_on_unlocked_repo(self):
739
1703
        backing = self.get_transport()
740
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
741
 
        repository = self.make_repository('.')
742
 
        response = request.execute(backing.local_abspath(''), 'some token')
743
 
        self.assertEqual(
744
 
            SmartServerResponse(('TokenMismatch',)), response)
745
 
 
746
 
 
747
 
class TestSmartServerRepositoryTarball(tests.TestCaseWithTransport):
748
 
 
749
 
    def test_repository_tarball(self):
750
 
        backing = self.get_transport()
751
 
        request = smart.repository.SmartServerRepositoryTarball(backing)
752
 
        repository = self.make_repository('.')
753
 
        # make some extraneous junk in the repository directory which should
754
 
        # not be copied
755
 
        self.build_tree(['.bzr/repository/extra-junk'])
756
 
        response = request.execute(backing.local_abspath(''), 'bz2')
757
 
        self.assertEqual(('ok',), response.args)
758
 
        # body should be a tbz2
759
 
        body_file = StringIO(response.body)
760
 
        body_tar = tarfile.open('body_tar.tbz2', fileobj=body_file,
761
 
            mode='r|bz2')
762
 
        # let's make sure there are some key repository components inside it.
763
 
        # the tarfile returns directories with trailing slashes...
764
 
        names = set([n.rstrip('/') for n in body_tar.getnames()])
765
 
        self.assertTrue('.bzr/repository/lock' in names)
766
 
        self.assertTrue('.bzr/repository/format' in names)
767
 
        self.assertTrue('.bzr/repository/extra-junk' not in names,
768
 
            "extraneous file present in tar file")
769
 
 
770
 
 
771
 
class TestSmartServerRepositoryStreamKnitData(tests.TestCaseWithTransport):
772
 
 
773
 
    def test_fetch_revisions(self):
774
 
        backing = self.get_transport()
775
 
        request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
776
 
        tree = self.make_branch_and_memory_tree('.')
777
 
        tree.lock_write()
778
 
        tree.add('')
779
 
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
780
 
        rev_id2_utf8 = u'\xc9'.encode('utf-8')
781
 
        r1 = tree.commit('1st commit', rev_id=rev_id1_utf8)
782
 
        r1 = tree.commit('2nd commit', rev_id=rev_id2_utf8)
783
 
        tree.unlock()
784
 
 
785
 
        response = request.execute(backing.local_abspath(''), rev_id2_utf8)
786
 
        self.assertEqual(('ok',), response.args)
787
 
        from cStringIO import StringIO
788
 
        unpacker = pack.ContainerReader(StringIO(response.body))
789
 
        names = []
790
 
        for [name], read_bytes in unpacker.iter_records():
791
 
            names.append(name)
792
 
            bytes = read_bytes(None)
793
 
            # The bytes should be a valid bencoded string.
794
 
            bencode.bdecode(bytes)
795
 
            # XXX: assert that the bencoded knit records have the right
796
 
            # contents?
797
 
        
798
 
    def test_no_such_revision_error(self):
799
 
        backing = self.get_transport()
800
 
        request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
801
 
        repo = self.make_repository('.')
802
 
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
803
 
        response = request.execute(backing.local_abspath(''), rev_id1_utf8)
804
 
        self.assertEqual(
805
 
            SmartServerResponse(('NoSuchRevision', rev_id1_utf8)),
806
 
            response)
807
 
 
808
 
 
809
 
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
 
1704
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
1705
        repository = self.make_repository('.', format='knit')
 
1706
        response = request.execute('', 'some token')
 
1707
        self.assertEqual(
 
1708
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1709
 
 
1710
 
 
1711
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
810
1712
 
811
1713
    def test_is_readonly_no(self):
812
1714
        backing = self.get_transport()
813
 
        request = smart.request.SmartServerIsReadonly(backing)
 
1715
        request = smart_req.SmartServerIsReadonly(backing)
814
1716
        response = request.execute()
815
1717
        self.assertEqual(
816
 
            SmartServerResponse(('no',)), response)
 
1718
            smart_req.SmartServerResponse(('no',)), response)
817
1719
 
818
1720
    def test_is_readonly_yes(self):
819
1721
        backing = self.get_readonly_transport()
820
 
        request = smart.request.SmartServerIsReadonly(backing)
 
1722
        request = smart_req.SmartServerIsReadonly(backing)
821
1723
        response = request.execute()
822
1724
        self.assertEqual(
823
 
            SmartServerResponse(('yes',)), response)
 
1725
            smart_req.SmartServerResponse(('yes',)), response)
 
1726
 
 
1727
 
 
1728
class TestSmartServerRepositorySetMakeWorkingTrees(
 
1729
    tests.TestCaseWithMemoryTransport):
 
1730
 
 
1731
    def test_set_false(self):
 
1732
        backing = self.get_transport()
 
1733
        repo = self.make_repository('.', shared=True)
 
1734
        repo.set_make_working_trees(True)
 
1735
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
1736
        request = request_class(backing)
 
1737
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
1738
            request.execute('', 'False'))
 
1739
        repo = repo.bzrdir.open_repository()
 
1740
        self.assertFalse(repo.make_working_trees())
 
1741
 
 
1742
    def test_set_true(self):
 
1743
        backing = self.get_transport()
 
1744
        repo = self.make_repository('.', shared=True)
 
1745
        repo.set_make_working_trees(False)
 
1746
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
1747
        request = request_class(backing)
 
1748
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
1749
            request.execute('', 'True'))
 
1750
        repo = repo.bzrdir.open_repository()
 
1751
        self.assertTrue(repo.make_working_trees())
 
1752
 
 
1753
 
 
1754
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
 
1755
 
 
1756
    def make_repo_needing_autopacking(self, path='.'):
 
1757
        # Make a repo in need of autopacking.
 
1758
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
1759
        repo = tree.branch.repository
 
1760
        # monkey-patch the pack collection to disable autopacking
 
1761
        repo._pack_collection._max_pack_count = lambda count: count
 
1762
        for x in range(10):
 
1763
            tree.commit('commit %s' % x)
 
1764
        self.assertEqual(10, len(repo._pack_collection.names()))
 
1765
        del repo._pack_collection._max_pack_count
 
1766
        return repo
 
1767
 
 
1768
    def test_autopack_needed(self):
 
1769
        repo = self.make_repo_needing_autopacking()
 
1770
        repo.lock_write()
 
1771
        self.addCleanup(repo.unlock)
 
1772
        backing = self.get_transport()
 
1773
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
1774
            backing)
 
1775
        response = request.execute('')
 
1776
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
1777
        repo._pack_collection.reload_pack_names()
 
1778
        self.assertEqual(1, len(repo._pack_collection.names()))
 
1779
 
 
1780
    def test_autopack_not_needed(self):
 
1781
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
1782
        repo = tree.branch.repository
 
1783
        repo.lock_write()
 
1784
        self.addCleanup(repo.unlock)
 
1785
        for x in range(9):
 
1786
            tree.commit('commit %s' % x)
 
1787
        backing = self.get_transport()
 
1788
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
1789
            backing)
 
1790
        response = request.execute('')
 
1791
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
1792
        repo._pack_collection.reload_pack_names()
 
1793
        self.assertEqual(9, len(repo._pack_collection.names()))
 
1794
 
 
1795
    def test_autopack_on_nonpack_format(self):
 
1796
        """A request to autopack a non-pack repo is a no-op."""
 
1797
        repo = self.make_repository('.', format='knit')
 
1798
        backing = self.get_transport()
 
1799
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
1800
            backing)
 
1801
        response = request.execute('')
 
1802
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
1803
 
 
1804
 
 
1805
class TestSmartServerVfsGet(tests.TestCaseWithMemoryTransport):
 
1806
 
 
1807
    def test_unicode_path(self):
 
1808
        """VFS requests expect unicode paths to be escaped."""
 
1809
        filename = u'foo\N{INTERROBANG}'
 
1810
        filename_escaped = urlutils.escape(filename)
 
1811
        backing = self.get_transport()
 
1812
        request = vfs.GetRequest(backing)
 
1813
        backing.put_bytes_non_atomic(filename_escaped, 'contents')
 
1814
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'contents'),
 
1815
            request.execute(filename_escaped))
824
1816
 
825
1817
 
826
1818
class TestHandlers(tests.TestCase):
827
1819
    """Tests for the request.request_handlers object."""
828
1820
 
 
1821
    def test_all_registrations_exist(self):
 
1822
        """All registered request_handlers can be found."""
 
1823
        # If there's a typo in a register_lazy call, this loop will fail with
 
1824
        # an AttributeError.
 
1825
        for key, item in smart_req.request_handlers.iteritems():
 
1826
            pass
 
1827
 
 
1828
    def assertHandlerEqual(self, verb, handler):
 
1829
        self.assertEqual(smart_req.request_handlers.get(verb), handler)
 
1830
 
829
1831
    def test_registered_methods(self):
830
1832
        """Test that known methods are registered to the correct object."""
831
 
        self.assertEqual(
832
 
            smart.request.request_handlers.get('Branch.get_config_file'),
833
 
            smart.branch.SmartServerBranchGetConfigFile)
834
 
        self.assertEqual(
835
 
            smart.request.request_handlers.get('Branch.lock_write'),
836
 
            smart.branch.SmartServerBranchRequestLockWrite)
837
 
        self.assertEqual(
838
 
            smart.request.request_handlers.get('Branch.last_revision_info'),
839
 
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
840
 
        self.assertEqual(
841
 
            smart.request.request_handlers.get('Branch.revision_history'),
842
 
            smart.branch.SmartServerRequestRevisionHistory)
843
 
        self.assertEqual(
844
 
            smart.request.request_handlers.get('Branch.set_last_revision'),
845
 
            smart.branch.SmartServerBranchRequestSetLastRevision)
846
 
        self.assertEqual(
847
 
            smart.request.request_handlers.get('Branch.unlock'),
848
 
            smart.branch.SmartServerBranchRequestUnlock)
849
 
        self.assertEqual(
850
 
            smart.request.request_handlers.get('BzrDir.find_repository'),
851
 
            smart.bzrdir.SmartServerRequestFindRepository)
852
 
        self.assertEqual(
853
 
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
854
 
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
855
 
        self.assertEqual(
856
 
            smart.request.request_handlers.get('BzrDir.open_branch'),
857
 
            smart.bzrdir.SmartServerRequestOpenBranch)
858
 
        self.assertEqual(
859
 
            smart.request.request_handlers.get('Repository.gather_stats'),
860
 
            smart.repository.SmartServerRepositoryGatherStats)
861
 
        self.assertEqual(
862
 
            smart.request.request_handlers.get(
863
 
                'Repository.get_revision_graph'),
864
 
            smart.repository.SmartServerRepositoryGetRevisionGraph)
865
 
        self.assertEqual(
866
 
            smart.request.request_handlers.get('Repository.has_revision'),
867
 
            smart.repository.SmartServerRequestHasRevision)
868
 
        self.assertEqual(
869
 
            smart.request.request_handlers.get('Repository.is_shared'),
870
 
            smart.repository.SmartServerRepositoryIsShared)
871
 
        self.assertEqual(
872
 
            smart.request.request_handlers.get('Repository.lock_write'),
873
 
            smart.repository.SmartServerRepositoryLockWrite)
874
 
        self.assertEqual(
875
 
            smart.request.request_handlers.get(
876
 
                'Repository.stream_knit_data_for_revisions'),
877
 
            smart.repository.SmartServerRepositoryStreamKnitDataForRevisions)
878
 
        self.assertEqual(
879
 
            smart.request.request_handlers.get('Repository.tarball'),
880
 
            smart.repository.SmartServerRepositoryTarball)
881
 
        self.assertEqual(
882
 
            smart.request.request_handlers.get('Repository.unlock'),
883
 
            smart.repository.SmartServerRepositoryUnlock)
884
 
        self.assertEqual(
885
 
            smart.request.request_handlers.get('Transport.is_readonly'),
886
 
            smart.request.SmartServerIsReadonly)
 
1833
        self.assertHandlerEqual('Branch.get_config_file',
 
1834
            smart_branch.SmartServerBranchGetConfigFile)
 
1835
        self.assertHandlerEqual('Branch.get_parent',
 
1836
            smart_branch.SmartServerBranchGetParent)
 
1837
        self.assertHandlerEqual('Branch.get_tags_bytes',
 
1838
            smart_branch.SmartServerBranchGetTagsBytes)
 
1839
        self.assertHandlerEqual('Branch.lock_write',
 
1840
            smart_branch.SmartServerBranchRequestLockWrite)
 
1841
        self.assertHandlerEqual('Branch.last_revision_info',
 
1842
            smart_branch.SmartServerBranchRequestLastRevisionInfo)
 
1843
        self.assertHandlerEqual('Branch.revision_history',
 
1844
            smart_branch.SmartServerRequestRevisionHistory)
 
1845
        self.assertHandlerEqual('Branch.set_config_option',
 
1846
            smart_branch.SmartServerBranchRequestSetConfigOption)
 
1847
        self.assertHandlerEqual('Branch.set_last_revision',
 
1848
            smart_branch.SmartServerBranchRequestSetLastRevision)
 
1849
        self.assertHandlerEqual('Branch.set_last_revision_info',
 
1850
            smart_branch.SmartServerBranchRequestSetLastRevisionInfo)
 
1851
        self.assertHandlerEqual('Branch.set_last_revision_ex',
 
1852
            smart_branch.SmartServerBranchRequestSetLastRevisionEx)
 
1853
        self.assertHandlerEqual('Branch.set_parent_location',
 
1854
            smart_branch.SmartServerBranchRequestSetParentLocation)
 
1855
        self.assertHandlerEqual('Branch.unlock',
 
1856
            smart_branch.SmartServerBranchRequestUnlock)
 
1857
        self.assertHandlerEqual('BzrDir.find_repository',
 
1858
            smart_dir.SmartServerRequestFindRepositoryV1)
 
1859
        self.assertHandlerEqual('BzrDir.find_repositoryV2',
 
1860
            smart_dir.SmartServerRequestFindRepositoryV2)
 
1861
        self.assertHandlerEqual('BzrDirFormat.initialize',
 
1862
            smart_dir.SmartServerRequestInitializeBzrDir)
 
1863
        self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
 
1864
            smart_dir.SmartServerRequestBzrDirInitializeEx)
 
1865
        self.assertHandlerEqual('BzrDir.cloning_metadir',
 
1866
            smart_dir.SmartServerBzrDirRequestCloningMetaDir)
 
1867
        self.assertHandlerEqual('BzrDir.get_config_file',
 
1868
            smart_dir.SmartServerBzrDirRequestConfigFile)
 
1869
        self.assertHandlerEqual('BzrDir.open_branch',
 
1870
            smart_dir.SmartServerRequestOpenBranch)
 
1871
        self.assertHandlerEqual('BzrDir.open_branchV2',
 
1872
            smart_dir.SmartServerRequestOpenBranchV2)
 
1873
        self.assertHandlerEqual('BzrDir.open_branchV3',
 
1874
            smart_dir.SmartServerRequestOpenBranchV3)
 
1875
        self.assertHandlerEqual('PackRepository.autopack',
 
1876
            smart_packrepo.SmartServerPackRepositoryAutopack)
 
1877
        self.assertHandlerEqual('Repository.gather_stats',
 
1878
            smart_repo.SmartServerRepositoryGatherStats)
 
1879
        self.assertHandlerEqual('Repository.get_parent_map',
 
1880
            smart_repo.SmartServerRepositoryGetParentMap)
 
1881
        self.assertHandlerEqual('Repository.get_rev_id_for_revno',
 
1882
            smart_repo.SmartServerRepositoryGetRevIdForRevno)
 
1883
        self.assertHandlerEqual('Repository.get_revision_graph',
 
1884
            smart_repo.SmartServerRepositoryGetRevisionGraph)
 
1885
        self.assertHandlerEqual('Repository.get_stream',
 
1886
            smart_repo.SmartServerRepositoryGetStream)
 
1887
        self.assertHandlerEqual('Repository.has_revision',
 
1888
            smart_repo.SmartServerRequestHasRevision)
 
1889
        self.assertHandlerEqual('Repository.insert_stream',
 
1890
            smart_repo.SmartServerRepositoryInsertStream)
 
1891
        self.assertHandlerEqual('Repository.insert_stream_locked',
 
1892
            smart_repo.SmartServerRepositoryInsertStreamLocked)
 
1893
        self.assertHandlerEqual('Repository.is_shared',
 
1894
            smart_repo.SmartServerRepositoryIsShared)
 
1895
        self.assertHandlerEqual('Repository.lock_write',
 
1896
            smart_repo.SmartServerRepositoryLockWrite)
 
1897
        self.assertHandlerEqual('Repository.tarball',
 
1898
            smart_repo.SmartServerRepositoryTarball)
 
1899
        self.assertHandlerEqual('Repository.unlock',
 
1900
            smart_repo.SmartServerRepositoryUnlock)
 
1901
        self.assertHandlerEqual('Transport.is_readonly',
 
1902
            smart_req.SmartServerIsReadonly)