~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart.py

Merge bzr.dev and tree-file-ids-as-tuples.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
21
 
import tarfile
22
 
 
23
 
from bzrlib import bzrdir, errors, 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
 
 
29
 
 
30
 
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
 
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
import zlib
 
29
 
 
30
from bzrlib import (
 
31
    bencode,
 
32
    branch as _mod_branch,
 
33
    bzrdir,
 
34
    errors,
 
35
    gpg,
 
36
    inventory_delta,
 
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.testament import Testament
 
52
from bzrlib.tests import test_server
 
53
from bzrlib.transport import (
 
54
    chroot,
 
55
    memory,
 
56
    )
 
57
 
 
58
 
 
59
def load_tests(standard_tests, module, loader):
 
60
    """Multiply tests version and protocol consistency."""
 
61
    # FindRepository tests.
 
62
    scenarios = [
 
63
        ("find_repository", {
 
64
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV1}),
 
65
        ("find_repositoryV2", {
 
66
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV2}),
 
67
        ("find_repositoryV3", {
 
68
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV3}),
 
69
        ]
 
70
    to_adapt, result = tests.split_suite_by_re(standard_tests,
 
71
        "TestSmartServerRequestFindRepository")
 
72
    v2_only, v1_and_2 = tests.split_suite_by_re(to_adapt,
 
73
        "_v2")
 
74
    tests.multiply_tests(v1_and_2, scenarios, result)
 
75
    # The first scenario is only applicable to v1 protocols, it is deleted
 
76
    # since.
 
77
    tests.multiply_tests(v2_only, scenarios[1:], result)
 
78
    return result
 
79
 
 
80
 
 
81
class TestCaseWithChrootedTransport(tests.TestCaseWithTransport):
 
82
 
 
83
    def setUp(self):
 
84
        self.vfs_transport_factory = memory.MemoryServer
 
85
        tests.TestCaseWithTransport.setUp(self)
 
86
        self._chroot_server = None
 
87
 
 
88
    def get_transport(self, relpath=None):
 
89
        if self._chroot_server is None:
 
90
            backing_transport = tests.TestCaseWithTransport.get_transport(self)
 
91
            self._chroot_server = chroot.ChrootServer(backing_transport)
 
92
            self.start_server(self._chroot_server)
 
93
        t = transport.get_transport_from_url(self._chroot_server.get_url())
 
94
        if relpath is not None:
 
95
            t = t.clone(relpath)
 
96
        return t
 
97
 
 
98
 
 
99
class TestCaseWithSmartMedium(tests.TestCaseWithMemoryTransport):
31
100
 
32
101
    def setUp(self):
33
102
        super(TestCaseWithSmartMedium, self).setUp()
35
104
        # the default or a parameterized class, but rather use the
36
105
        # TestCaseWithTransport infrastructure to set up a smart server and
37
106
        # transport.
38
 
        self.transport_server = smart.server.SmartTCPServer_for_testing
 
107
        self.overrideAttr(self, "transport_server", self.make_transport_server)
 
108
 
 
109
    def make_transport_server(self):
 
110
        return test_server.SmartTCPServer_for_testing('-' + self.id())
39
111
 
40
112
    def get_smart_medium(self):
41
113
        """Get a smart medium to use in tests."""
42
114
        return self.get_transport().get_smart_medium()
43
115
 
44
116
 
 
117
class TestByteStreamToStream(tests.TestCase):
 
118
 
 
119
    def test_repeated_substreams_same_kind_are_one_stream(self):
 
120
        # Make a stream - an iterable of bytestrings.
 
121
        stream = [('text', [versionedfile.FulltextContentFactory(('k1',), None,
 
122
            None, 'foo')]),('text', [
 
123
            versionedfile.FulltextContentFactory(('k2',), None, None, 'bar')])]
 
124
        fmt = bzrdir.format_registry.get('pack-0.92')().repository_format
 
125
        bytes = smart_repo._stream_to_byte_stream(stream, fmt)
 
126
        streams = []
 
127
        # Iterate the resulting iterable; checking that we get only one stream
 
128
        # out.
 
129
        fmt, stream = smart_repo._byte_stream_to_stream(bytes)
 
130
        for kind, substream in stream:
 
131
            streams.append((kind, list(substream)))
 
132
        self.assertLength(1, streams)
 
133
        self.assertLength(2, streams[0][1])
 
134
 
 
135
 
45
136
class TestSmartServerResponse(tests.TestCase):
46
137
 
47
138
    def test__eq__(self):
48
 
        self.assertEqual(SmartServerResponse(('ok', )),
49
 
            SmartServerResponse(('ok', )))
50
 
        self.assertEqual(SmartServerResponse(('ok', ), 'body'),
51
 
            SmartServerResponse(('ok', ), 'body'))
52
 
        self.assertNotEqual(SmartServerResponse(('ok', )),
53
 
            SmartServerResponse(('notok', )))
54
 
        self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
55
 
            SmartServerResponse(('ok', )))
 
139
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
140
            smart_req.SmartServerResponse(('ok', )))
 
141
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
 
142
            smart_req.SmartServerResponse(('ok', ), 'body'))
 
143
        self.assertNotEqual(smart_req.SmartServerResponse(('ok', )),
 
144
            smart_req.SmartServerResponse(('notok', )))
 
145
        self.assertNotEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
 
146
            smart_req.SmartServerResponse(('ok', )))
56
147
        self.assertNotEqual(None,
57
 
            SmartServerResponse(('ok', )))
58
 
 
59
 
 
60
 
class TestSmartServerRequestFindRepository(tests.TestCaseWithTransport):
 
148
            smart_req.SmartServerResponse(('ok', )))
 
149
 
 
150
    def test__str__(self):
 
151
        """SmartServerResponses can be stringified."""
 
152
        self.assertEqual(
 
153
            "<SuccessfulSmartServerResponse args=('args',) body='body'>",
 
154
            str(smart_req.SuccessfulSmartServerResponse(('args',), 'body')))
 
155
        self.assertEqual(
 
156
            "<FailedSmartServerResponse args=('args',) body='body'>",
 
157
            str(smart_req.FailedSmartServerResponse(('args',), 'body')))
 
158
 
 
159
 
 
160
class TestSmartServerRequest(tests.TestCaseWithMemoryTransport):
 
161
 
 
162
    def test_translate_client_path(self):
 
163
        transport = self.get_transport()
 
164
        request = smart_req.SmartServerRequest(transport, 'foo/')
 
165
        self.assertEqual('./', request.translate_client_path('foo/'))
 
166
        self.assertRaises(
 
167
            errors.InvalidURLJoin, request.translate_client_path, 'foo/..')
 
168
        self.assertRaises(
 
169
            errors.PathNotChild, request.translate_client_path, '/')
 
170
        self.assertRaises(
 
171
            errors.PathNotChild, request.translate_client_path, 'bar/')
 
172
        self.assertEqual('./baz', request.translate_client_path('foo/baz'))
 
173
        e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
 
174
        self.assertEqual('./' + urlutils.escape(e_acute),
 
175
                         request.translate_client_path('foo/' + e_acute))
 
176
 
 
177
    def test_translate_client_path_vfs(self):
 
178
        """VfsRequests receive escaped paths rather than raw UTF-8."""
 
179
        transport = self.get_transport()
 
180
        request = vfs.VfsRequest(transport, 'foo/')
 
181
        e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
 
182
        escaped = urlutils.escape('foo/' + e_acute)
 
183
        self.assertEqual('./' + urlutils.escape(e_acute),
 
184
                         request.translate_client_path(escaped))
 
185
 
 
186
    def test_transport_from_client_path(self):
 
187
        transport = self.get_transport()
 
188
        request = smart_req.SmartServerRequest(transport, 'foo/')
 
189
        self.assertEqual(
 
190
            transport.base,
 
191
            request.transport_from_client_path('foo/').base)
 
192
 
 
193
 
 
194
class TestSmartServerBzrDirRequestCloningMetaDir(
 
195
    tests.TestCaseWithMemoryTransport):
 
196
    """Tests for BzrDir.cloning_metadir."""
 
197
 
 
198
    def test_cloning_metadir(self):
 
199
        """When there is a bzrdir present, the call succeeds."""
 
200
        backing = self.get_transport()
 
201
        dir = self.make_bzrdir('.')
 
202
        local_result = dir.cloning_metadir()
 
203
        request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
 
204
        request = request_class(backing)
 
205
        expected = smart_req.SuccessfulSmartServerResponse(
 
206
            (local_result.network_name(),
 
207
            local_result.repository_format.network_name(),
 
208
            ('branch', local_result.get_branch_format().network_name())))
 
209
        self.assertEqual(expected, request.execute('', 'False'))
 
210
 
 
211
    def test_cloning_metadir_reference(self):
 
212
        """The request fails when bzrdir contains a branch reference."""
 
213
        backing = self.get_transport()
 
214
        referenced_branch = self.make_branch('referenced')
 
215
        dir = self.make_bzrdir('.')
 
216
        local_result = dir.cloning_metadir()
 
217
        reference = _mod_branch.BranchReferenceFormat().initialize(
 
218
            dir, target_branch=referenced_branch)
 
219
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(dir)
 
220
        # The server shouldn't try to follow the branch reference, so it's fine
 
221
        # if the referenced branch isn't reachable.
 
222
        backing.rename('referenced', 'moved')
 
223
        request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
 
224
        request = request_class(backing)
 
225
        expected = smart_req.FailedSmartServerResponse(('BranchReference',))
 
226
        self.assertEqual(expected, request.execute('', 'False'))
 
227
 
 
228
 
 
229
class TestSmartServerBzrDirRequestCloningMetaDir(
 
230
    tests.TestCaseWithMemoryTransport):
 
231
    """Tests for BzrDir.checkout_metadir."""
 
232
 
 
233
    def test_checkout_metadir(self):
 
234
        backing = self.get_transport()
 
235
        request = smart_dir.SmartServerBzrDirRequestCheckoutMetaDir(
 
236
            backing)
 
237
        branch = self.make_branch('.', format='2a')
 
238
        response = request.execute('')
 
239
        self.assertEqual(
 
240
            smart_req.SmartServerResponse(
 
241
                ('Bazaar-NG meta directory, format 1\n',
 
242
                 'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
243
                 'Bazaar Branch Format 7 (needs bzr 1.6)\n')),
 
244
            response)
 
245
 
 
246
 
 
247
class TestSmartServerBzrDirRequestDestroyBranch(
 
248
    tests.TestCaseWithMemoryTransport):
 
249
    """Tests for BzrDir.destroy_branch."""
 
250
 
 
251
    def test_destroy_branch_default(self):
 
252
        """The default branch can be removed."""
 
253
        backing = self.get_transport()
 
254
        dir = self.make_branch('.').bzrdir
 
255
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
256
        request = request_class(backing)
 
257
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
258
        self.assertEqual(expected, request.execute('', None))
 
259
 
 
260
    def test_destroy_branch_named(self):
 
261
        """A named branch can be removed."""
 
262
        backing = self.get_transport()
 
263
        dir = self.make_repository('.', format="development-colo").bzrdir
 
264
        dir.create_branch(name="branchname")
 
265
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
266
        request = request_class(backing)
 
267
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
268
        self.assertEqual(expected, request.execute('', "branchname"))
 
269
 
 
270
    def test_destroy_branch_missing(self):
 
271
        """An error is raised if the branch didn't exist."""
 
272
        backing = self.get_transport()
 
273
        dir = self.make_bzrdir('.', format="development-colo")
 
274
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
275
        request = request_class(backing)
 
276
        expected = smart_req.FailedSmartServerResponse(('nobranch',), None)
 
277
        self.assertEqual(expected, request.execute('', "branchname"))
 
278
 
 
279
 
 
280
class TestSmartServerBzrDirRequestHasWorkingTree(
 
281
    tests.TestCaseWithTransport):
 
282
    """Tests for BzrDir.has_workingtree."""
 
283
 
 
284
    def test_has_workingtree_yes(self):
 
285
        """A working tree is present."""
 
286
        backing = self.get_transport()
 
287
        dir = self.make_branch_and_tree('.').bzrdir
 
288
        request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
 
289
        request = request_class(backing)
 
290
        expected = smart_req.SuccessfulSmartServerResponse(('yes',))
 
291
        self.assertEqual(expected, request.execute(''))
 
292
 
 
293
    def test_has_workingtree_no(self):
 
294
        """A working tree is missing."""
 
295
        backing = self.get_transport()
 
296
        dir = self.make_bzrdir('.')
 
297
        request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
 
298
        request = request_class(backing)
 
299
        expected = smart_req.SuccessfulSmartServerResponse(('no',))
 
300
        self.assertEqual(expected, request.execute(''))
 
301
 
 
302
 
 
303
class TestSmartServerBzrDirRequestDestroyRepository(
 
304
    tests.TestCaseWithMemoryTransport):
 
305
    """Tests for BzrDir.destroy_repository."""
 
306
 
 
307
    def test_destroy_repository_default(self):
 
308
        """The repository can be removed."""
 
309
        backing = self.get_transport()
 
310
        dir = self.make_repository('.').bzrdir
 
311
        request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
 
312
        request = request_class(backing)
 
313
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
314
        self.assertEqual(expected, request.execute(''))
 
315
 
 
316
    def test_destroy_repository_missing(self):
 
317
        """An error is raised if the repository didn't exist."""
 
318
        backing = self.get_transport()
 
319
        dir = self.make_bzrdir('.')
 
320
        request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
 
321
        request = request_class(backing)
 
322
        expected = smart_req.FailedSmartServerResponse(
 
323
            ('norepository',), None)
 
324
        self.assertEqual(expected, request.execute(''))
 
325
 
 
326
 
 
327
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
 
328
    """Tests for BzrDir.create_repository."""
 
329
 
 
330
    def test_makes_repository(self):
 
331
        """When there is a bzrdir present, the call succeeds."""
 
332
        backing = self.get_transport()
 
333
        self.make_bzrdir('.')
 
334
        request_class = smart_dir.SmartServerRequestCreateRepository
 
335
        request = request_class(backing)
 
336
        reference_bzrdir_format = bzrdir.format_registry.get('pack-0.92')()
 
337
        reference_format = reference_bzrdir_format.repository_format
 
338
        network_name = reference_format.network_name()
 
339
        expected = smart_req.SuccessfulSmartServerResponse(
 
340
            ('ok', 'no', 'no', 'no', network_name))
 
341
        self.assertEqual(expected, request.execute('', network_name, 'True'))
 
342
 
 
343
 
 
344
class TestSmartServerRequestFindRepository(tests.TestCaseWithMemoryTransport):
61
345
    """Tests for BzrDir.find_repository."""
62
346
 
63
347
    def test_no_repository(self):
64
348
        """When there is no repository to be found, ('norepository', ) is returned."""
65
349
        backing = self.get_transport()
66
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
350
        request = self._request_class(backing)
67
351
        self.make_bzrdir('.')
68
 
        self.assertEqual(SmartServerResponse(('norepository', )),
69
 
            request.execute(backing.local_abspath('')))
 
352
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
353
            request.execute(''))
70
354
 
71
355
    def test_nonshared_repository(self):
72
 
        # nonshared repositorys only allow 'find' to return a handle when the 
73
 
        # path the repository is being searched on is the same as that that 
 
356
        # nonshared repositorys only allow 'find' to return a handle when the
 
357
        # path the repository is being searched on is the same as that that
74
358
        # the repository is at.
75
359
        backing = self.get_transport()
76
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
360
        request = self._request_class(backing)
77
361
        result = self._make_repository_and_result()
78
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
362
        self.assertEqual(result, request.execute(''))
79
363
        self.make_bzrdir('subdir')
80
 
        self.assertEqual(SmartServerResponse(('norepository', )),
81
 
            request.execute(backing.local_abspath('subdir')))
 
364
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
365
            request.execute('subdir'))
82
366
 
83
367
    def _make_repository_and_result(self, shared=False, format=None):
84
368
        """Convenience function to setup a repository.
94
378
            subtrees = 'yes'
95
379
        else:
96
380
            subtrees = 'no'
97
 
        return SmartServerResponse(('ok', '', rich_root, subtrees))
 
381
        if repo._format.supports_external_lookups:
 
382
            external = 'yes'
 
383
        else:
 
384
            external = 'no'
 
385
        if (smart_dir.SmartServerRequestFindRepositoryV3 ==
 
386
            self._request_class):
 
387
            return smart_req.SuccessfulSmartServerResponse(
 
388
                ('ok', '', rich_root, subtrees, external,
 
389
                 repo._format.network_name()))
 
390
        elif (smart_dir.SmartServerRequestFindRepositoryV2 ==
 
391
            self._request_class):
 
392
            # All tests so far are on formats, and for non-external
 
393
            # repositories.
 
394
            return smart_req.SuccessfulSmartServerResponse(
 
395
                ('ok', '', rich_root, subtrees, external))
 
396
        else:
 
397
            return smart_req.SuccessfulSmartServerResponse(
 
398
                ('ok', '', rich_root, subtrees))
98
399
 
99
400
    def test_shared_repository(self):
100
401
        """When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
101
402
        backing = self.get_transport()
102
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
403
        request = self._request_class(backing)
103
404
        result = self._make_repository_and_result(shared=True)
104
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
405
        self.assertEqual(result, request.execute(''))
105
406
        self.make_bzrdir('subdir')
106
 
        result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
 
407
        result2 = smart_req.SmartServerResponse(
 
408
            result.args[0:1] + ('..', ) + result.args[2:])
107
409
        self.assertEqual(result2,
108
 
            request.execute(backing.local_abspath('subdir')))
 
410
            request.execute('subdir'))
109
411
        self.make_bzrdir('subdir/deeper')
110
 
        result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
 
412
        result3 = smart_req.SmartServerResponse(
 
413
            result.args[0:1] + ('../..', ) + result.args[2:])
111
414
        self.assertEqual(result3,
112
 
            request.execute(backing.local_abspath('subdir/deeper')))
 
415
            request.execute('subdir/deeper'))
113
416
 
114
417
    def test_rich_root_and_subtree_encoding(self):
115
418
        """Test for the format attributes for rich root and subtree support."""
116
419
        backing = self.get_transport()
117
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
118
 
        result = self._make_repository_and_result(format='dirstate-with-subtree')
 
420
        request = self._request_class(backing)
 
421
        result = self._make_repository_and_result(
 
422
            format='dirstate-with-subtree')
119
423
        # check the test will be valid
120
424
        self.assertEqual('yes', result.args[2])
121
425
        self.assertEqual('yes', result.args[3])
122
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
123
 
 
124
 
 
125
 
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithTransport):
 
426
        self.assertEqual(result, request.execute(''))
 
427
 
 
428
    def test_supports_external_lookups_no_v2(self):
 
429
        """Test for the supports_external_lookups attribute."""
 
430
        backing = self.get_transport()
 
431
        request = self._request_class(backing)
 
432
        result = self._make_repository_and_result(
 
433
            format='dirstate-with-subtree')
 
434
        # check the test will be valid
 
435
        self.assertEqual('no', result.args[4])
 
436
        self.assertEqual(result, request.execute(''))
 
437
 
 
438
 
 
439
class TestSmartServerBzrDirRequestGetConfigFile(
 
440
    tests.TestCaseWithMemoryTransport):
 
441
    """Tests for BzrDir.get_config_file."""
 
442
 
 
443
    def test_present(self):
 
444
        backing = self.get_transport()
 
445
        dir = self.make_bzrdir('.')
 
446
        dir.get_config().set_default_stack_on("/")
 
447
        local_result = dir._get_config()._get_config_file().read()
 
448
        request_class = smart_dir.SmartServerBzrDirRequestConfigFile
 
449
        request = request_class(backing)
 
450
        expected = smart_req.SuccessfulSmartServerResponse((), local_result)
 
451
        self.assertEqual(expected, request.execute(''))
 
452
 
 
453
    def test_missing(self):
 
454
        backing = self.get_transport()
 
455
        dir = self.make_bzrdir('.')
 
456
        request_class = smart_dir.SmartServerBzrDirRequestConfigFile
 
457
        request = request_class(backing)
 
458
        expected = smart_req.SuccessfulSmartServerResponse((), '')
 
459
        self.assertEqual(expected, request.execute(''))
 
460
 
 
461
 
 
462
class TestSmartServerBzrDirRequestGetBranches(
 
463
    tests.TestCaseWithMemoryTransport):
 
464
    """Tests for BzrDir.get_branches."""
 
465
 
 
466
    def test_simple(self):
 
467
        backing = self.get_transport()
 
468
        branch = self.make_branch('.')
 
469
        request_class = smart_dir.SmartServerBzrDirRequestGetBranches
 
470
        request = request_class(backing)
 
471
        local_result = bencode.bencode(
 
472
            {"": ("branch", branch._format.network_name())})
 
473
        expected = smart_req.SuccessfulSmartServerResponse(
 
474
            ("success", ), local_result)
 
475
        self.assertEqual(expected, request.execute(''))
 
476
 
 
477
    def test_empty(self):
 
478
        backing = self.get_transport()
 
479
        dir = self.make_bzrdir('.')
 
480
        request_class = smart_dir.SmartServerBzrDirRequestGetBranches
 
481
        request = request_class(backing)
 
482
        local_result = bencode.bencode({})
 
483
        expected = smart_req.SuccessfulSmartServerResponse(
 
484
            ('success',), local_result)
 
485
        self.assertEqual(expected, request.execute(''))
 
486
 
 
487
 
 
488
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithMemoryTransport):
126
489
 
127
490
    def test_empty_dir(self):
128
491
        """Initializing an empty dir should succeed and do it."""
129
492
        backing = self.get_transport()
130
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
131
 
        self.assertEqual(SmartServerResponse(('ok', )),
132
 
            request.execute(backing.local_abspath('.')))
 
493
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
 
494
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
495
            request.execute(''))
133
496
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
134
 
        # no branch, tree or repository is expected with the current 
 
497
        # no branch, tree or repository is expected with the current
135
498
        # default formart.
136
499
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
137
500
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
140
503
    def test_missing_dir(self):
141
504
        """Initializing a missing directory should fail like the bzrdir api."""
142
505
        backing = self.get_transport()
143
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
 
506
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
144
507
        self.assertRaises(errors.NoSuchFile,
145
 
            request.execute, backing.local_abspath('subdir'))
 
508
            request.execute, 'subdir')
146
509
 
147
510
    def test_initialized_dir(self):
148
511
        """Initializing an extant bzrdir should fail like the bzrdir api."""
149
512
        backing = self.get_transport()
150
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
151
 
        self.make_bzrdir('subdir')
152
 
        self.assertRaises(errors.FileExists,
153
 
            request.execute, backing.local_abspath('subdir'))
154
 
 
155
 
 
156
 
class TestSmartServerRequestOpenBranch(tests.TestCaseWithTransport):
 
513
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
 
514
        self.make_bzrdir('subdir')
 
515
        self.assertRaises(errors.AlreadyControlDirError,
 
516
            request.execute, 'subdir')
 
517
 
 
518
 
 
519
class TestSmartServerRequestBzrDirInitializeEx(
 
520
    tests.TestCaseWithMemoryTransport):
 
521
    """Basic tests for BzrDir.initialize_ex_1.16 in the smart server.
 
522
 
 
523
    The main unit tests in test_bzrdir exercise the API comprehensively.
 
524
    """
 
525
 
 
526
    def test_empty_dir(self):
 
527
        """Initializing an empty dir should succeed and do it."""
 
528
        backing = self.get_transport()
 
529
        name = self.make_bzrdir('reference')._format.network_name()
 
530
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
531
        self.assertEqual(
 
532
            smart_req.SmartServerResponse(('', '', '', '', '', '', name,
 
533
                                           'False', '', '', '')),
 
534
            request.execute(name, '', 'True', 'False', 'False', '', '', '', '',
 
535
                            'False'))
 
536
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
 
537
        # no branch, tree or repository is expected with the current
 
538
        # default format.
 
539
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
 
540
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
 
541
        self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
 
542
 
 
543
    def test_missing_dir(self):
 
544
        """Initializing a missing directory should fail like the bzrdir api."""
 
545
        backing = self.get_transport()
 
546
        name = self.make_bzrdir('reference')._format.network_name()
 
547
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
548
        self.assertRaises(errors.NoSuchFile, request.execute, name,
 
549
            'subdir/dir', 'False', 'False', 'False', '', '', '', '', 'False')
 
550
 
 
551
    def test_initialized_dir(self):
 
552
        """Initializing an extant directory should fail like the bzrdir api."""
 
553
        backing = self.get_transport()
 
554
        name = self.make_bzrdir('reference')._format.network_name()
 
555
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
556
        self.make_bzrdir('subdir')
 
557
        self.assertRaises(errors.FileExists, request.execute, name, 'subdir',
 
558
            'False', 'False', 'False', '', '', '', '', 'False')
 
559
 
 
560
 
 
561
class TestSmartServerRequestOpenBzrDir(tests.TestCaseWithMemoryTransport):
 
562
 
 
563
    def test_no_directory(self):
 
564
        backing = self.get_transport()
 
565
        request = smart_dir.SmartServerRequestOpenBzrDir(backing)
 
566
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
567
            request.execute('does-not-exist'))
 
568
 
 
569
    def test_empty_directory(self):
 
570
        backing = self.get_transport()
 
571
        backing.mkdir('empty')
 
572
        request = smart_dir.SmartServerRequestOpenBzrDir(backing)
 
573
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
574
            request.execute('empty'))
 
575
 
 
576
    def test_outside_root_client_path(self):
 
577
        backing = self.get_transport()
 
578
        request = smart_dir.SmartServerRequestOpenBzrDir(backing,
 
579
            root_client_path='root')
 
580
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
581
            request.execute('not-root'))
 
582
 
 
583
 
 
584
class TestSmartServerRequestOpenBzrDir_2_1(tests.TestCaseWithMemoryTransport):
 
585
 
 
586
    def test_no_directory(self):
 
587
        backing = self.get_transport()
 
588
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
589
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
590
            request.execute('does-not-exist'))
 
591
 
 
592
    def test_empty_directory(self):
 
593
        backing = self.get_transport()
 
594
        backing.mkdir('empty')
 
595
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
596
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
597
            request.execute('empty'))
 
598
 
 
599
    def test_present_without_workingtree(self):
 
600
        backing = self.get_transport()
 
601
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
602
        self.make_bzrdir('.')
 
603
        self.assertEqual(smart_req.SmartServerResponse(('yes', 'no')),
 
604
            request.execute(''))
 
605
 
 
606
    def test_outside_root_client_path(self):
 
607
        backing = self.get_transport()
 
608
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing,
 
609
            root_client_path='root')
 
610
        self.assertEqual(smart_req.SmartServerResponse(('no',)),
 
611
            request.execute('not-root'))
 
612
 
 
613
 
 
614
class TestSmartServerRequestOpenBzrDir_2_1_disk(TestCaseWithChrootedTransport):
 
615
 
 
616
    def test_present_with_workingtree(self):
 
617
        self.vfs_transport_factory = test_server.LocalURLServer
 
618
        backing = self.get_transport()
 
619
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
620
        bd = self.make_bzrdir('.')
 
621
        bd.create_repository()
 
622
        bd.create_branch()
 
623
        bd.create_workingtree()
 
624
        self.assertEqual(smart_req.SmartServerResponse(('yes', 'yes')),
 
625
            request.execute(''))
 
626
 
 
627
 
 
628
class TestSmartServerRequestOpenBranch(TestCaseWithChrootedTransport):
157
629
 
158
630
    def test_no_branch(self):
159
631
        """When there is no branch, ('nobranch', ) is returned."""
160
632
        backing = self.get_transport()
161
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
633
        request = smart_dir.SmartServerRequestOpenBranch(backing)
162
634
        self.make_bzrdir('.')
163
 
        self.assertEqual(SmartServerResponse(('nobranch', )),
164
 
            request.execute(backing.local_abspath('')))
 
635
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
636
            request.execute(''))
165
637
 
166
638
    def test_branch(self):
167
639
        """When there is a branch, 'ok' is returned."""
168
640
        backing = self.get_transport()
169
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
641
        request = smart_dir.SmartServerRequestOpenBranch(backing)
170
642
        self.make_branch('.')
171
 
        self.assertEqual(SmartServerResponse(('ok', '')),
172
 
            request.execute(backing.local_abspath('')))
173
 
 
174
 
    def test_branch_reference(self):
175
 
        """When there is a branch reference, the reference URL is returned."""
176
 
        backing = self.get_transport()
177
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
178
 
        branch = self.make_branch('branch')
179
 
        checkout = branch.create_checkout('reference',lightweight=True)
180
 
        # TODO: once we have an API to probe for references of any sort, we
181
 
        # can use it here.
182
 
        reference_url = backing.abspath('branch') + '/'
183
 
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
184
 
        self.assertEqual(SmartServerResponse(('ok', reference_url)),
185
 
            request.execute(backing.local_abspath('reference')))
186
 
 
187
 
 
188
 
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithTransport):
 
643
        self.assertEqual(smart_req.SmartServerResponse(('ok', '')),
 
644
            request.execute(''))
 
645
 
 
646
    def test_branch_reference(self):
 
647
        """When there is a branch reference, the reference URL is returned."""
 
648
        self.vfs_transport_factory = test_server.LocalURLServer
 
649
        backing = self.get_transport()
 
650
        request = smart_dir.SmartServerRequestOpenBranch(backing)
 
651
        branch = self.make_branch('branch')
 
652
        checkout = branch.create_checkout('reference',lightweight=True)
 
653
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
654
            checkout.bzrdir)
 
655
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
656
        self.assertEqual(smart_req.SmartServerResponse(('ok', reference_url)),
 
657
            request.execute('reference'))
 
658
 
 
659
    def test_notification_on_branch_from_repository(self):
 
660
        """When there is a repository, the error should return details."""
 
661
        backing = self.get_transport()
 
662
        request = smart_dir.SmartServerRequestOpenBranch(backing)
 
663
        repo = self.make_repository('.')
 
664
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
665
            request.execute(''))
 
666
 
 
667
 
 
668
class TestSmartServerRequestOpenBranchV2(TestCaseWithChrootedTransport):
 
669
 
 
670
    def test_no_branch(self):
 
671
        """When there is no branch, ('nobranch', ) is returned."""
 
672
        backing = self.get_transport()
 
673
        self.make_bzrdir('.')
 
674
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
675
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
676
            request.execute(''))
 
677
 
 
678
    def test_branch(self):
 
679
        """When there is a branch, 'ok' is returned."""
 
680
        backing = self.get_transport()
 
681
        expected = self.make_branch('.')._format.network_name()
 
682
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
683
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
684
                ('branch', expected)),
 
685
                         request.execute(''))
 
686
 
 
687
    def test_branch_reference(self):
 
688
        """When there is a branch reference, the reference URL is returned."""
 
689
        self.vfs_transport_factory = test_server.LocalURLServer
 
690
        backing = self.get_transport()
 
691
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
692
        branch = self.make_branch('branch')
 
693
        checkout = branch.create_checkout('reference',lightweight=True)
 
694
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
695
            checkout.bzrdir)
 
696
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
697
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
698
                ('ref', reference_url)),
 
699
                         request.execute('reference'))
 
700
 
 
701
    def test_stacked_branch(self):
 
702
        """Opening a stacked branch does not open the stacked-on branch."""
 
703
        trunk = self.make_branch('trunk')
 
704
        feature = self.make_branch('feature')
 
705
        feature.set_stacked_on_url(trunk.base)
 
706
        opened_branches = []
 
707
        _mod_branch.Branch.hooks.install_named_hook(
 
708
            'open', opened_branches.append, None)
 
709
        backing = self.get_transport()
 
710
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
711
        request.setup_jail()
 
712
        try:
 
713
            response = request.execute('feature')
 
714
        finally:
 
715
            request.teardown_jail()
 
716
        expected_format = feature._format.network_name()
 
717
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
718
                ('branch', expected_format)),
 
719
                         response)
 
720
        self.assertLength(1, opened_branches)
 
721
 
 
722
    def test_notification_on_branch_from_repository(self):
 
723
        """When there is a repository, the error should return details."""
 
724
        backing = self.get_transport()
 
725
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
726
        repo = self.make_repository('.')
 
727
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
728
            request.execute(''))
 
729
 
 
730
 
 
731
class TestSmartServerRequestOpenBranchV3(TestCaseWithChrootedTransport):
 
732
 
 
733
    def test_no_branch(self):
 
734
        """When there is no branch, ('nobranch', ) is returned."""
 
735
        backing = self.get_transport()
 
736
        self.make_bzrdir('.')
 
737
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
738
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
739
            request.execute(''))
 
740
 
 
741
    def test_branch(self):
 
742
        """When there is a branch, 'ok' is returned."""
 
743
        backing = self.get_transport()
 
744
        expected = self.make_branch('.')._format.network_name()
 
745
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
746
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
747
                ('branch', expected)),
 
748
                         request.execute(''))
 
749
 
 
750
    def test_branch_reference(self):
 
751
        """When there is a branch reference, the reference URL is returned."""
 
752
        self.vfs_transport_factory = test_server.LocalURLServer
 
753
        backing = self.get_transport()
 
754
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
755
        branch = self.make_branch('branch')
 
756
        checkout = branch.create_checkout('reference',lightweight=True)
 
757
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
758
            checkout.bzrdir)
 
759
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
760
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
761
                ('ref', reference_url)),
 
762
                         request.execute('reference'))
 
763
 
 
764
    def test_stacked_branch(self):
 
765
        """Opening a stacked branch does not open the stacked-on branch."""
 
766
        trunk = self.make_branch('trunk')
 
767
        feature = self.make_branch('feature')
 
768
        feature.set_stacked_on_url(trunk.base)
 
769
        opened_branches = []
 
770
        _mod_branch.Branch.hooks.install_named_hook(
 
771
            'open', opened_branches.append, None)
 
772
        backing = self.get_transport()
 
773
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
774
        request.setup_jail()
 
775
        try:
 
776
            response = request.execute('feature')
 
777
        finally:
 
778
            request.teardown_jail()
 
779
        expected_format = feature._format.network_name()
 
780
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
781
                ('branch', expected_format)),
 
782
                         response)
 
783
        self.assertLength(1, opened_branches)
 
784
 
 
785
    def test_notification_on_branch_from_repository(self):
 
786
        """When there is a repository, the error should return details."""
 
787
        backing = self.get_transport()
 
788
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
789
        repo = self.make_repository('.')
 
790
        self.assertEqual(smart_req.SmartServerResponse(
 
791
                ('nobranch', 'location is a repository')),
 
792
                         request.execute(''))
 
793
 
 
794
 
 
795
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
189
796
 
190
797
    def test_empty(self):
191
798
        """For an empty branch, the body is empty."""
192
799
        backing = self.get_transport()
193
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
800
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
194
801
        self.make_branch('.')
195
 
        self.assertEqual(SmartServerResponse(('ok', ), ''),
196
 
            request.execute(backing.local_abspath('')))
 
802
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), ''),
 
803
            request.execute(''))
197
804
 
198
805
    def test_not_empty(self):
199
806
        """For a non-empty branch, the body is empty."""
200
807
        backing = self.get_transport()
201
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
808
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
202
809
        tree = self.make_branch_and_memory_tree('.')
203
810
        tree.lock_write()
204
811
        tree.add('')
206
813
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
207
814
        tree.unlock()
208
815
        self.assertEqual(
209
 
            SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
210
 
            request.execute(backing.local_abspath('')))
211
 
 
212
 
 
213
 
class TestSmartServerBranchRequest(tests.TestCaseWithTransport):
 
816
            smart_req.SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
 
817
            request.execute(''))
 
818
 
 
819
 
 
820
class TestSmartServerBranchRequest(tests.TestCaseWithMemoryTransport):
214
821
 
215
822
    def test_no_branch(self):
216
823
        """When there is a bzrdir and no branch, NotBranchError is raised."""
217
824
        backing = self.get_transport()
218
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
825
        request = smart_branch.SmartServerBranchRequest(backing)
219
826
        self.make_bzrdir('.')
220
827
        self.assertRaises(errors.NotBranchError,
221
 
            request.execute, backing.local_abspath(''))
 
828
            request.execute, '')
222
829
 
223
830
    def test_branch_reference(self):
224
831
        """When there is a branch reference, NotBranchError is raised."""
225
832
        backing = self.get_transport()
226
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
833
        request = smart_branch.SmartServerBranchRequest(backing)
227
834
        branch = self.make_branch('branch')
228
835
        checkout = branch.create_checkout('reference',lightweight=True)
229
836
        self.assertRaises(errors.NotBranchError,
230
 
            request.execute, backing.local_abspath('checkout'))
231
 
 
232
 
 
233
 
class TestSmartServerBranchRequestLastRevisionInfo(tests.TestCaseWithTransport):
 
837
            request.execute, 'checkout')
 
838
 
 
839
 
 
840
class TestSmartServerBranchRequestLastRevisionInfo(
 
841
    tests.TestCaseWithMemoryTransport):
234
842
 
235
843
    def test_empty(self):
236
844
        """For an empty branch, the result is ('ok', '0', 'null:')."""
237
845
        backing = self.get_transport()
238
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
846
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
239
847
        self.make_branch('.')
240
 
        self.assertEqual(SmartServerResponse(('ok', '0', 'null:')),
241
 
            request.execute(backing.local_abspath('')))
 
848
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0', 'null:')),
 
849
            request.execute(''))
242
850
 
243
851
    def test_not_empty(self):
244
852
        """For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
245
853
        backing = self.get_transport()
246
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
854
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
247
855
        tree = self.make_branch_and_memory_tree('.')
248
856
        tree.lock_write()
249
857
        tree.add('')
252
860
        r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
253
861
        tree.unlock()
254
862
        self.assertEqual(
255
 
            SmartServerResponse(('ok', '2', rev_id_utf8)),
256
 
            request.execute(backing.local_abspath('')))
257
 
 
258
 
 
259
 
class TestSmartServerBranchRequestGetConfigFile(tests.TestCaseWithTransport):
 
863
            smart_req.SmartServerResponse(('ok', '2', rev_id_utf8)),
 
864
            request.execute(''))
 
865
 
 
866
 
 
867
class TestSmartServerBranchRequestRevisionIdToRevno(
 
868
    tests.TestCaseWithMemoryTransport):
 
869
 
 
870
    def test_null(self):
 
871
        backing = self.get_transport()
 
872
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
873
            backing)
 
874
        self.make_branch('.')
 
875
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0')),
 
876
            request.execute('', 'null:'))
 
877
 
 
878
    def test_simple(self):
 
879
        backing = self.get_transport()
 
880
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
881
            backing)
 
882
        tree = self.make_branch_and_memory_tree('.')
 
883
        tree.lock_write()
 
884
        tree.add('')
 
885
        r1 = tree.commit('1st commit')
 
886
        tree.unlock()
 
887
        self.assertEqual(
 
888
            smart_req.SmartServerResponse(('ok', '1')),
 
889
            request.execute('', r1))
 
890
 
 
891
    def test_not_found(self):
 
892
        backing = self.get_transport()
 
893
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
894
            backing)
 
895
        branch = self.make_branch('.')
 
896
        self.assertEqual(
 
897
            smart_req.FailedSmartServerResponse(
 
898
                ('NoSuchRevision', 'idontexist')),
 
899
            request.execute('', 'idontexist'))
 
900
 
 
901
 
 
902
class TestSmartServerBranchRequestGetConfigFile(
 
903
    tests.TestCaseWithMemoryTransport):
260
904
 
261
905
    def test_default(self):
262
906
        """With no file, we get empty content."""
263
907
        backing = self.get_transport()
264
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
 
908
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
265
909
        branch = self.make_branch('.')
266
910
        # there should be no file by default
267
911
        content = ''
268
 
        self.assertEqual(SmartServerResponse(('ok', ), content),
269
 
            request.execute(backing.local_abspath('')))
 
912
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), content),
 
913
            request.execute(''))
270
914
 
271
915
    def test_with_content(self):
272
916
        # SmartServerBranchGetConfigFile should return the content from
273
917
        # branch.control_files.get('branch.conf') for now - in the future it may
274
 
        # perform more complex processing. 
275
 
        backing = self.get_transport()
276
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
277
 
        branch = self.make_branch('.')
278
 
        branch.control_files.put_utf8('branch.conf', 'foo bar baz')
279
 
        self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
280
 
            request.execute(backing.local_abspath('')))
281
 
 
282
 
 
283
 
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
284
 
 
285
 
    def test_empty(self):
286
 
        backing = self.get_transport()
287
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
288
 
        b = self.make_branch('.')
289
 
        branch_token = b.lock_write()
290
 
        repo_token = b.repository.lock_write()
291
 
        b.repository.unlock()
292
 
        try:
293
 
            self.assertEqual(SmartServerResponse(('ok',)),
294
 
                request.execute(
295
 
                    backing.local_abspath(''), branch_token, repo_token,
296
 
                    'null:'))
297
 
        finally:
298
 
            b.unlock()
299
 
 
300
 
    def test_not_present_revision_id(self):
301
 
        backing = self.get_transport()
302
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
303
 
        b = self.make_branch('.')
304
 
        branch_token = b.lock_write()
305
 
        repo_token = b.repository.lock_write()
306
 
        b.repository.unlock()
307
 
        try:
308
 
            revision_id = 'non-existent revision'
309
 
            self.assertEqual(
310
 
                SmartServerResponse(('NoSuchRevision', revision_id)),
311
 
                request.execute(
312
 
                    backing.local_abspath(''), branch_token, repo_token,
313
 
                    revision_id))
314
 
        finally:
315
 
            b.unlock()
316
 
 
317
 
    def test_revision_id_present(self):
318
 
        backing = self.get_transport()
319
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
320
 
        tree = self.make_branch_and_memory_tree('.')
321
 
        tree.lock_write()
322
 
        tree.add('')
323
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
324
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
325
 
        r2 = tree.commit('2nd commit')
326
 
        tree.unlock()
327
 
        branch_token = tree.branch.lock_write()
328
 
        repo_token = tree.branch.repository.lock_write()
329
 
        tree.branch.repository.unlock()
330
 
        try:
331
 
            self.assertEqual(
332
 
                SmartServerResponse(('ok',)),
333
 
                request.execute(
334
 
                    backing.local_abspath(''), branch_token, repo_token,
335
 
                    rev_id_utf8))
336
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
337
 
        finally:
338
 
            tree.branch.unlock()
339
 
 
340
 
    def test_revision_id_present2(self):
341
 
        backing = self.get_transport()
342
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
343
 
        tree = self.make_branch_and_memory_tree('.')
344
 
        tree.lock_write()
345
 
        tree.add('')
346
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
347
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
348
 
        r2 = tree.commit('2nd commit')
349
 
        tree.unlock()
350
 
        tree.branch.set_revision_history([])
351
 
        branch_token = tree.branch.lock_write()
352
 
        repo_token = tree.branch.repository.lock_write()
353
 
        tree.branch.repository.unlock()
354
 
        try:
355
 
            self.assertEqual(
356
 
                SmartServerResponse(('ok',)),
357
 
                request.execute(
358
 
                    backing.local_abspath(''), branch_token, repo_token,
359
 
                    rev_id_utf8))
360
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
361
 
        finally:
362
 
            tree.branch.unlock()
363
 
 
364
 
 
365
 
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
366
 
 
367
 
    def setUp(self):
368
 
        tests.TestCaseWithTransport.setUp(self)
369
 
        self.reduceLockdirTimeout()
 
918
        # perform more complex processing.
 
919
        backing = self.get_transport()
 
920
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
 
921
        branch = self.make_branch('.')
 
922
        branch._transport.put_bytes('branch.conf', 'foo bar baz')
 
923
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'foo bar baz'),
 
924
            request.execute(''))
 
925
 
 
926
 
 
927
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
 
928
 
 
929
    def get_lock_tokens(self, branch):
 
930
        branch_token = branch.lock_write().branch_token
 
931
        repo_token = branch.repository.lock_write().repository_token
 
932
        branch.repository.unlock()
 
933
        return branch_token, repo_token
 
934
 
 
935
 
 
936
class TestSmartServerBranchRequestPutConfigFile(TestLockedBranch):
 
937
 
 
938
    def test_with_content(self):
 
939
        backing = self.get_transport()
 
940
        request = smart_branch.SmartServerBranchPutConfigFile(backing)
 
941
        branch = self.make_branch('.')
 
942
        branch_token, repo_token = self.get_lock_tokens(branch)
 
943
        self.assertIs(None, request.execute('', branch_token, repo_token))
 
944
        self.assertEqual(
 
945
            smart_req.SmartServerResponse(('ok', )),
 
946
            request.do_body('foo bar baz'))
 
947
        self.assertEquals(
 
948
            branch.control_transport.get_bytes('branch.conf'),
 
949
            'foo bar baz')
 
950
        branch.unlock()
 
951
 
 
952
 
 
953
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
 
954
 
 
955
    def test_value_name(self):
 
956
        branch = self.make_branch('.')
 
957
        request = smart_branch.SmartServerBranchRequestSetConfigOption(
 
958
            branch.bzrdir.root_transport)
 
959
        branch_token, repo_token = self.get_lock_tokens(branch)
 
960
        config = branch._get_config()
 
961
        result = request.execute('', branch_token, repo_token, 'bar', 'foo',
 
962
            '')
 
963
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
964
        self.assertEqual('bar', config.get_option('foo'))
 
965
        # Cleanup
 
966
        branch.unlock()
 
967
 
 
968
    def test_value_name_section(self):
 
969
        branch = self.make_branch('.')
 
970
        request = smart_branch.SmartServerBranchRequestSetConfigOption(
 
971
            branch.bzrdir.root_transport)
 
972
        branch_token, repo_token = self.get_lock_tokens(branch)
 
973
        config = branch._get_config()
 
974
        result = request.execute('', branch_token, repo_token, 'bar', 'foo',
 
975
            'gam')
 
976
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
977
        self.assertEqual('bar', config.get_option('foo', 'gam'))
 
978
        # Cleanup
 
979
        branch.unlock()
 
980
 
 
981
 
 
982
class TestSmartServerBranchRequestSetConfigOptionDict(TestLockedBranch):
 
983
 
 
984
    def setUp(self):
 
985
        TestLockedBranch.setUp(self)
 
986
        # A dict with non-ascii keys and values to exercise unicode
 
987
        # roundtripping.
 
988
        self.encoded_value_dict = (
 
989
            'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde')
 
990
        self.value_dict = {
 
991
            'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
992
 
 
993
    def test_value_name(self):
 
994
        branch = self.make_branch('.')
 
995
        request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
 
996
            branch.bzrdir.root_transport)
 
997
        branch_token, repo_token = self.get_lock_tokens(branch)
 
998
        config = branch._get_config()
 
999
        result = request.execute('', branch_token, repo_token,
 
1000
            self.encoded_value_dict, 'foo', '')
 
1001
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
1002
        self.assertEqual(self.value_dict, config.get_option('foo'))
 
1003
        # Cleanup
 
1004
        branch.unlock()
 
1005
 
 
1006
    def test_value_name_section(self):
 
1007
        branch = self.make_branch('.')
 
1008
        request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
 
1009
            branch.bzrdir.root_transport)
 
1010
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1011
        config = branch._get_config()
 
1012
        result = request.execute('', branch_token, repo_token,
 
1013
            self.encoded_value_dict, 'foo', 'gam')
 
1014
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
1015
        self.assertEqual(self.value_dict, config.get_option('foo', 'gam'))
 
1016
        # Cleanup
 
1017
        branch.unlock()
 
1018
 
 
1019
 
 
1020
class TestSmartServerBranchRequestSetTagsBytes(TestLockedBranch):
 
1021
    # Only called when the branch format and tags match [yay factory
 
1022
    # methods] so only need to test straight forward cases.
 
1023
 
 
1024
    def test_set_bytes(self):
 
1025
        base_branch = self.make_branch('base')
 
1026
        tag_bytes = base_branch._get_tags_bytes()
 
1027
        # get_lock_tokens takes out a lock.
 
1028
        branch_token, repo_token = self.get_lock_tokens(base_branch)
 
1029
        request = smart_branch.SmartServerBranchSetTagsBytes(
 
1030
            self.get_transport())
 
1031
        response = request.execute('base', branch_token, repo_token)
 
1032
        self.assertEqual(None, response)
 
1033
        response = request.do_chunk(tag_bytes)
 
1034
        self.assertEqual(None, response)
 
1035
        response = request.do_end()
 
1036
        self.assertEquals(
 
1037
            smart_req.SuccessfulSmartServerResponse(()), response)
 
1038
        base_branch.unlock()
 
1039
 
 
1040
    def test_lock_failed(self):
 
1041
        base_branch = self.make_branch('base')
 
1042
        base_branch.lock_write()
 
1043
        tag_bytes = base_branch._get_tags_bytes()
 
1044
        request = smart_branch.SmartServerBranchSetTagsBytes(
 
1045
            self.get_transport())
 
1046
        self.assertRaises(errors.TokenMismatch, request.execute,
 
1047
            'base', 'wrong token', 'wrong token')
 
1048
        # The request handler will keep processing the message parts, so even
 
1049
        # if the request fails immediately do_chunk and do_end are still
 
1050
        # called.
 
1051
        request.do_chunk(tag_bytes)
 
1052
        request.do_end()
 
1053
        base_branch.unlock()
 
1054
 
 
1055
 
 
1056
 
 
1057
class SetLastRevisionTestBase(TestLockedBranch):
 
1058
    """Base test case for verbs that implement set_last_revision."""
 
1059
 
 
1060
    def setUp(self):
 
1061
        tests.TestCaseWithMemoryTransport.setUp(self)
 
1062
        backing_transport = self.get_transport()
 
1063
        self.request = self.request_class(backing_transport)
 
1064
        self.tree = self.make_branch_and_memory_tree('.')
 
1065
 
 
1066
    def lock_branch(self):
 
1067
        return self.get_lock_tokens(self.tree.branch)
 
1068
 
 
1069
    def unlock_branch(self):
 
1070
        self.tree.branch.unlock()
 
1071
 
 
1072
    def set_last_revision(self, revision_id, revno):
 
1073
        branch_token, repo_token = self.lock_branch()
 
1074
        response = self._set_last_revision(
 
1075
            revision_id, revno, branch_token, repo_token)
 
1076
        self.unlock_branch()
 
1077
        return response
 
1078
 
 
1079
    def assertRequestSucceeds(self, revision_id, revno):
 
1080
        response = self.set_last_revision(revision_id, revno)
 
1081
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
1082
                         response)
 
1083
 
 
1084
 
 
1085
class TestSetLastRevisionVerbMixin(object):
 
1086
    """Mixin test case for verbs that implement set_last_revision."""
 
1087
 
 
1088
    def test_set_null_to_null(self):
 
1089
        """An empty branch can have its last revision set to 'null:'."""
 
1090
        self.assertRequestSucceeds('null:', 0)
 
1091
 
 
1092
    def test_NoSuchRevision(self):
 
1093
        """If the revision_id is not present, the verb returns NoSuchRevision.
 
1094
        """
 
1095
        revision_id = 'non-existent revision'
 
1096
        self.assertEqual(smart_req.FailedSmartServerResponse(('NoSuchRevision',
 
1097
                                                              revision_id)),
 
1098
                         self.set_last_revision(revision_id, 1))
 
1099
 
 
1100
    def make_tree_with_two_commits(self):
 
1101
        self.tree.lock_write()
 
1102
        self.tree.add('')
 
1103
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1104
        r1 = self.tree.commit('1st commit', rev_id=rev_id_utf8)
 
1105
        r2 = self.tree.commit('2nd commit', rev_id='rev-2')
 
1106
        self.tree.unlock()
 
1107
 
 
1108
    def test_branch_last_revision_info_is_updated(self):
 
1109
        """A branch's tip can be set to a revision that is present in its
 
1110
        repository.
 
1111
        """
 
1112
        # Make a branch with an empty revision history, but two revisions in
 
1113
        # its repository.
 
1114
        self.make_tree_with_two_commits()
 
1115
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1116
        self.tree.branch.set_last_revision_info(0, 'null:')
 
1117
        self.assertEqual(
 
1118
            (0, 'null:'), self.tree.branch.last_revision_info())
 
1119
        # We can update the branch to a revision that is present in the
 
1120
        # repository.
 
1121
        self.assertRequestSucceeds(rev_id_utf8, 1)
 
1122
        self.assertEqual(
 
1123
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1124
 
 
1125
    def test_branch_last_revision_info_rewind(self):
 
1126
        """A branch's tip can be set to a revision that is an ancestor of the
 
1127
        current tip.
 
1128
        """
 
1129
        self.make_tree_with_two_commits()
 
1130
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1131
        self.assertEqual(
 
1132
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
1133
        self.assertRequestSucceeds(rev_id_utf8, 1)
 
1134
        self.assertEqual(
 
1135
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1136
 
 
1137
    def test_TipChangeRejected(self):
 
1138
        """If a pre_change_branch_tip hook raises TipChangeRejected, the verb
 
1139
        returns TipChangeRejected.
 
1140
        """
 
1141
        rejection_message = u'rejection message\N{INTERROBANG}'
 
1142
        def hook_that_rejects(params):
 
1143
            raise errors.TipChangeRejected(rejection_message)
 
1144
        _mod_branch.Branch.hooks.install_named_hook(
 
1145
            'pre_change_branch_tip', hook_that_rejects, None)
 
1146
        self.assertEqual(
 
1147
            smart_req.FailedSmartServerResponse(
 
1148
                ('TipChangeRejected', rejection_message.encode('utf-8'))),
 
1149
            self.set_last_revision('null:', 0))
 
1150
 
 
1151
 
 
1152
class TestSmartServerBranchRequestSetLastRevision(
 
1153
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
1154
    """Tests for Branch.set_last_revision verb."""
 
1155
 
 
1156
    request_class = smart_branch.SmartServerBranchRequestSetLastRevision
 
1157
 
 
1158
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
1159
        return self.request.execute(
 
1160
            '', branch_token, repo_token, revision_id)
 
1161
 
 
1162
 
 
1163
class TestSmartServerBranchRequestSetLastRevisionInfo(
 
1164
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
1165
    """Tests for Branch.set_last_revision_info verb."""
 
1166
 
 
1167
    request_class = smart_branch.SmartServerBranchRequestSetLastRevisionInfo
 
1168
 
 
1169
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
1170
        return self.request.execute(
 
1171
            '', branch_token, repo_token, revno, revision_id)
 
1172
 
 
1173
    def test_NoSuchRevision(self):
 
1174
        """Branch.set_last_revision_info does not have to return
 
1175
        NoSuchRevision if the revision_id is absent.
 
1176
        """
 
1177
        raise tests.TestNotApplicable()
 
1178
 
 
1179
 
 
1180
class TestSmartServerBranchRequestSetLastRevisionEx(
 
1181
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
1182
    """Tests for Branch.set_last_revision_ex verb."""
 
1183
 
 
1184
    request_class = smart_branch.SmartServerBranchRequestSetLastRevisionEx
 
1185
 
 
1186
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
1187
        return self.request.execute(
 
1188
            '', branch_token, repo_token, revision_id, 0, 0)
 
1189
 
 
1190
    def assertRequestSucceeds(self, revision_id, revno):
 
1191
        response = self.set_last_revision(revision_id, revno)
 
1192
        self.assertEqual(
 
1193
            smart_req.SuccessfulSmartServerResponse(('ok', revno, revision_id)),
 
1194
            response)
 
1195
 
 
1196
    def test_branch_last_revision_info_rewind(self):
 
1197
        """A branch's tip can be set to a revision that is an ancestor of the
 
1198
        current tip, but only if allow_overwrite_descendant is passed.
 
1199
        """
 
1200
        self.make_tree_with_two_commits()
 
1201
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1202
        self.assertEqual(
 
1203
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
1204
        # If allow_overwrite_descendant flag is 0, then trying to set the tip
 
1205
        # to an older revision ID has no effect.
 
1206
        branch_token, repo_token = self.lock_branch()
 
1207
        response = self.request.execute(
 
1208
            '', branch_token, repo_token, rev_id_utf8, 0, 0)
 
1209
        self.assertEqual(
 
1210
            smart_req.SuccessfulSmartServerResponse(('ok', 2, 'rev-2')),
 
1211
            response)
 
1212
        self.assertEqual(
 
1213
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
1214
 
 
1215
        # If allow_overwrite_descendant flag is 1, then setting the tip to an
 
1216
        # ancestor works.
 
1217
        response = self.request.execute(
 
1218
            '', branch_token, repo_token, rev_id_utf8, 0, 1)
 
1219
        self.assertEqual(
 
1220
            smart_req.SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)),
 
1221
            response)
 
1222
        self.unlock_branch()
 
1223
        self.assertEqual(
 
1224
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1225
 
 
1226
    def make_branch_with_divergent_history(self):
 
1227
        """Make a branch with divergent history in its repo.
 
1228
 
 
1229
        The branch's tip will be 'child-2', and the repo will also contain
 
1230
        'child-1', which diverges from a common base revision.
 
1231
        """
 
1232
        self.tree.lock_write()
 
1233
        self.tree.add('')
 
1234
        r1 = self.tree.commit('1st commit')
 
1235
        revno_1, revid_1 = self.tree.branch.last_revision_info()
 
1236
        r2 = self.tree.commit('2nd commit', rev_id='child-1')
 
1237
        # Undo the second commit
 
1238
        self.tree.branch.set_last_revision_info(revno_1, revid_1)
 
1239
        self.tree.set_parent_ids([revid_1])
 
1240
        # Make a new second commit, child-2.  child-2 has diverged from
 
1241
        # child-1.
 
1242
        new_r2 = self.tree.commit('2nd commit', rev_id='child-2')
 
1243
        self.tree.unlock()
 
1244
 
 
1245
    def test_not_allow_diverged(self):
 
1246
        """If allow_diverged is not passed, then setting a divergent history
 
1247
        returns a Diverged error.
 
1248
        """
 
1249
        self.make_branch_with_divergent_history()
 
1250
        self.assertEqual(
 
1251
            smart_req.FailedSmartServerResponse(('Diverged',)),
 
1252
            self.set_last_revision('child-1', 2))
 
1253
        # The branch tip was not changed.
 
1254
        self.assertEqual('child-2', self.tree.branch.last_revision())
 
1255
 
 
1256
    def test_allow_diverged(self):
 
1257
        """If allow_diverged is passed, then setting a divergent history
 
1258
        succeeds.
 
1259
        """
 
1260
        self.make_branch_with_divergent_history()
 
1261
        branch_token, repo_token = self.lock_branch()
 
1262
        response = self.request.execute(
 
1263
            '', branch_token, repo_token, 'child-1', 1, 0)
 
1264
        self.assertEqual(
 
1265
            smart_req.SuccessfulSmartServerResponse(('ok', 2, 'child-1')),
 
1266
            response)
 
1267
        self.unlock_branch()
 
1268
        # The branch tip was changed.
 
1269
        self.assertEqual('child-1', self.tree.branch.last_revision())
 
1270
 
 
1271
 
 
1272
class TestSmartServerBranchBreakLock(tests.TestCaseWithMemoryTransport):
 
1273
 
 
1274
    def test_lock_to_break(self):
 
1275
        base_branch = self.make_branch('base')
 
1276
        request = smart_branch.SmartServerBranchBreakLock(
 
1277
            self.get_transport())
 
1278
        base_branch.lock_write()
 
1279
        self.assertEqual(
 
1280
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1281
            request.execute('base'))
 
1282
 
 
1283
    def test_nothing_to_break(self):
 
1284
        base_branch = self.make_branch('base')
 
1285
        request = smart_branch.SmartServerBranchBreakLock(
 
1286
            self.get_transport())
 
1287
        self.assertEqual(
 
1288
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1289
            request.execute('base'))
 
1290
 
 
1291
 
 
1292
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
 
1293
 
 
1294
    def test_get_parent_none(self):
 
1295
        base_branch = self.make_branch('base')
 
1296
        request = smart_branch.SmartServerBranchGetParent(self.get_transport())
 
1297
        response = request.execute('base')
 
1298
        self.assertEquals(
 
1299
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1300
 
 
1301
    def test_get_parent_something(self):
 
1302
        base_branch = self.make_branch('base')
 
1303
        base_branch.set_parent(self.get_url('foo'))
 
1304
        request = smart_branch.SmartServerBranchGetParent(self.get_transport())
 
1305
        response = request.execute('base')
 
1306
        self.assertEquals(
 
1307
            smart_req.SuccessfulSmartServerResponse(("../foo",)),
 
1308
            response)
 
1309
 
 
1310
 
 
1311
class TestSmartServerBranchRequestSetParent(TestLockedBranch):
 
1312
 
 
1313
    def test_set_parent_none(self):
 
1314
        branch = self.make_branch('base', format="1.9")
 
1315
        branch.lock_write()
 
1316
        branch._set_parent_location('foo')
 
1317
        branch.unlock()
 
1318
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1319
            self.get_transport())
 
1320
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1321
        try:
 
1322
            response = request.execute('base', branch_token, repo_token, '')
 
1323
        finally:
 
1324
            branch.unlock()
 
1325
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1326
        self.assertEqual(None, branch.get_parent())
 
1327
 
 
1328
    def test_set_parent_something(self):
 
1329
        branch = self.make_branch('base', format="1.9")
 
1330
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1331
            self.get_transport())
 
1332
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1333
        try:
 
1334
            response = request.execute('base', branch_token, repo_token,
 
1335
            'http://bar/')
 
1336
        finally:
 
1337
            branch.unlock()
 
1338
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1339
        self.assertEqual('http://bar/', branch.get_parent())
 
1340
 
 
1341
 
 
1342
class TestSmartServerBranchRequestGetTagsBytes(
 
1343
    tests.TestCaseWithMemoryTransport):
 
1344
    # Only called when the branch format and tags match [yay factory
 
1345
    # methods] so only need to test straight forward cases.
 
1346
 
 
1347
    def test_get_bytes(self):
 
1348
        base_branch = self.make_branch('base')
 
1349
        request = smart_branch.SmartServerBranchGetTagsBytes(
 
1350
            self.get_transport())
 
1351
        response = request.execute('base')
 
1352
        self.assertEquals(
 
1353
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1354
 
 
1355
 
 
1356
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
 
1357
 
 
1358
    def test_get_stacked_on_url(self):
 
1359
        base_branch = self.make_branch('base', format='1.6')
 
1360
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1361
        # typically should be relative
 
1362
        stacked_branch.set_stacked_on_url('../base')
 
1363
        request = smart_branch.SmartServerBranchRequestGetStackedOnURL(
 
1364
            self.get_transport())
 
1365
        response = request.execute('stacked')
 
1366
        self.assertEquals(
 
1367
            smart_req.SmartServerResponse(('ok', '../base')),
 
1368
            response)
 
1369
 
 
1370
 
 
1371
class TestSmartServerBranchRequestLockWrite(TestLockedBranch):
 
1372
 
 
1373
    def setUp(self):
 
1374
        tests.TestCaseWithMemoryTransport.setUp(self)
370
1375
 
371
1376
    def test_lock_write_on_unlocked_branch(self):
372
1377
        backing = self.get_transport()
373
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
374
 
        branch = self.make_branch('.')
 
1378
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1379
        branch = self.make_branch('.', format='knit')
375
1380
        repository = branch.repository
376
 
        response = request.execute(backing.local_abspath(''))
 
1381
        response = request.execute('')
377
1382
        branch_nonce = branch.control_files._lock.peek().get('nonce')
378
1383
        repository_nonce = repository.control_files._lock.peek().get('nonce')
379
 
        self.assertEqual(
380
 
            SmartServerResponse(('ok', branch_nonce, repository_nonce)),
381
 
            response)
 
1384
        self.assertEqual(smart_req.SmartServerResponse(
 
1385
                ('ok', branch_nonce, repository_nonce)),
 
1386
                         response)
382
1387
        # The branch (and associated repository) is now locked.  Verify that
383
1388
        # with a new branch object.
384
1389
        new_branch = repository.bzrdir.open_branch()
385
1390
        self.assertRaises(errors.LockContention, new_branch.lock_write)
 
1391
        # Cleanup
 
1392
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1393
        response = request.execute('', branch_nonce, repository_nonce)
386
1394
 
387
1395
    def test_lock_write_on_locked_branch(self):
388
1396
        backing = self.get_transport()
389
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1397
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
390
1398
        branch = self.make_branch('.')
391
 
        branch.lock_write()
 
1399
        branch_token = branch.lock_write().branch_token
392
1400
        branch.leave_lock_in_place()
393
1401
        branch.unlock()
394
 
        response = request.execute(backing.local_abspath(''))
 
1402
        response = request.execute('')
395
1403
        self.assertEqual(
396
 
            SmartServerResponse(('LockContention',)), response)
 
1404
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1405
        # Cleanup
 
1406
        branch.lock_write(branch_token)
 
1407
        branch.dont_leave_lock_in_place()
 
1408
        branch.unlock()
397
1409
 
398
1410
    def test_lock_write_with_tokens_on_locked_branch(self):
399
1411
        backing = self.get_transport()
400
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
401
 
        branch = self.make_branch('.')
402
 
        branch_token = branch.lock_write()
403
 
        repo_token = branch.repository.lock_write()
404
 
        branch.repository.unlock()
 
1412
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1413
        branch = self.make_branch('.', format='knit')
 
1414
        branch_token, repo_token = self.get_lock_tokens(branch)
405
1415
        branch.leave_lock_in_place()
406
1416
        branch.repository.leave_lock_in_place()
407
1417
        branch.unlock()
408
 
        response = request.execute(backing.local_abspath(''),
 
1418
        response = request.execute('',
409
1419
                                   branch_token, repo_token)
410
1420
        self.assertEqual(
411
 
            SmartServerResponse(('ok', branch_token, repo_token)), response)
 
1421
            smart_req.SmartServerResponse(('ok', branch_token, repo_token)),
 
1422
            response)
 
1423
        # Cleanup
 
1424
        branch.repository.lock_write(repo_token)
 
1425
        branch.repository.dont_leave_lock_in_place()
 
1426
        branch.repository.unlock()
 
1427
        branch.lock_write(branch_token)
 
1428
        branch.dont_leave_lock_in_place()
 
1429
        branch.unlock()
412
1430
 
413
1431
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
414
1432
        backing = self.get_transport()
415
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
416
 
        branch = self.make_branch('.')
417
 
        branch_token = branch.lock_write()
418
 
        repo_token = branch.repository.lock_write()
419
 
        branch.repository.unlock()
 
1433
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1434
        branch = self.make_branch('.', format='knit')
 
1435
        branch_token, repo_token = self.get_lock_tokens(branch)
420
1436
        branch.leave_lock_in_place()
421
1437
        branch.repository.leave_lock_in_place()
422
1438
        branch.unlock()
423
 
        response = request.execute(backing.local_abspath(''),
 
1439
        response = request.execute('',
424
1440
                                   branch_token+'xxx', repo_token)
425
1441
        self.assertEqual(
426
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1442
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1443
        # Cleanup
 
1444
        branch.repository.lock_write(repo_token)
 
1445
        branch.repository.dont_leave_lock_in_place()
 
1446
        branch.repository.unlock()
 
1447
        branch.lock_write(branch_token)
 
1448
        branch.dont_leave_lock_in_place()
 
1449
        branch.unlock()
427
1450
 
428
1451
    def test_lock_write_on_locked_repo(self):
429
1452
        backing = self.get_transport()
430
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
431
 
        branch = self.make_branch('.')
432
 
        branch.repository.lock_write()
433
 
        branch.repository.leave_lock_in_place()
434
 
        branch.repository.unlock()
435
 
        response = request.execute(backing.local_abspath(''))
 
1453
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1454
        branch = self.make_branch('.', format='knit')
 
1455
        repo = branch.repository
 
1456
        repo_token = repo.lock_write().repository_token
 
1457
        repo.leave_lock_in_place()
 
1458
        repo.unlock()
 
1459
        response = request.execute('')
436
1460
        self.assertEqual(
437
 
            SmartServerResponse(('LockContention',)), response)
 
1461
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1462
        # Cleanup
 
1463
        repo.lock_write(repo_token)
 
1464
        repo.dont_leave_lock_in_place()
 
1465
        repo.unlock()
438
1466
 
439
1467
    def test_lock_write_on_readonly_transport(self):
440
1468
        backing = self.get_readonly_transport()
441
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
442
 
        branch = self.make_branch('.')
443
 
        response = request.execute('')
444
 
        self.assertEqual(
445
 
            SmartServerResponse(('UnlockableTransport',)), response)
446
 
 
447
 
 
448
 
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
449
 
 
450
 
    def setUp(self):
451
 
        tests.TestCaseWithTransport.setUp(self)
452
 
        self.reduceLockdirTimeout()
 
1469
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1470
        branch = self.make_branch('.')
 
1471
        root = self.get_transport().clone('/')
 
1472
        path = urlutils.relative_url(root.base, self.get_transport().base)
 
1473
        response = request.execute(path)
 
1474
        error_name, lock_str, why_str = response.args
 
1475
        self.assertFalse(response.is_successful())
 
1476
        self.assertEqual('LockFailed', error_name)
 
1477
 
 
1478
 
 
1479
class TestSmartServerBranchRequestGetPhysicalLockStatus(TestLockedBranch):
 
1480
 
 
1481
    def setUp(self):
 
1482
        tests.TestCaseWithMemoryTransport.setUp(self)
 
1483
 
 
1484
    def test_true(self):
 
1485
        backing = self.get_transport()
 
1486
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1487
            backing)
 
1488
        branch = self.make_branch('.')
 
1489
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1490
        self.assertEquals(True, branch.get_physical_lock_status())
 
1491
        response = request.execute('')
 
1492
        self.assertEqual(
 
1493
            smart_req.SmartServerResponse(('yes',)), response)
 
1494
        branch.unlock()
 
1495
 
 
1496
    def test_false(self):
 
1497
        backing = self.get_transport()
 
1498
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1499
            backing)
 
1500
        branch = self.make_branch('.')
 
1501
        self.assertEquals(False, branch.get_physical_lock_status())
 
1502
        response = request.execute('')
 
1503
        self.assertEqual(
 
1504
            smart_req.SmartServerResponse(('no',)), response)
 
1505
 
 
1506
 
 
1507
class TestSmartServerBranchRequestUnlock(TestLockedBranch):
 
1508
 
 
1509
    def setUp(self):
 
1510
        tests.TestCaseWithMemoryTransport.setUp(self)
453
1511
 
454
1512
    def test_unlock_on_locked_branch_and_repo(self):
455
1513
        backing = self.get_transport()
456
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
457
 
        branch = self.make_branch('.')
 
1514
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1515
        branch = self.make_branch('.', format='knit')
458
1516
        # Lock the branch
459
 
        branch_token = branch.lock_write()
460
 
        repo_token = branch.repository.lock_write()
461
 
        branch.repository.unlock()
 
1517
        branch_token, repo_token = self.get_lock_tokens(branch)
462
1518
        # Unlock the branch (and repo) object, leaving the physical locks
463
1519
        # in place.
464
1520
        branch.leave_lock_in_place()
465
1521
        branch.repository.leave_lock_in_place()
466
1522
        branch.unlock()
467
 
        response = request.execute(backing.local_abspath(''),
 
1523
        response = request.execute('',
468
1524
                                   branch_token, repo_token)
469
1525
        self.assertEqual(
470
 
            SmartServerResponse(('ok',)), response)
 
1526
            smart_req.SmartServerResponse(('ok',)), response)
471
1527
        # The branch is now unlocked.  Verify that with a new branch
472
1528
        # object.
473
1529
        new_branch = branch.bzrdir.open_branch()
476
1532
 
477
1533
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
478
1534
        backing = self.get_transport()
479
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
480
 
        branch = self.make_branch('.')
 
1535
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1536
        branch = self.make_branch('.', format='knit')
481
1537
        response = request.execute(
482
 
            backing.local_abspath(''), 'branch token', 'repo token')
 
1538
            '', 'branch token', 'repo token')
483
1539
        self.assertEqual(
484
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1540
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
485
1541
 
486
1542
    def test_unlock_on_unlocked_branch_locked_repo(self):
487
1543
        backing = self.get_transport()
488
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
489
 
        branch = self.make_branch('.')
 
1544
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1545
        branch = self.make_branch('.', format='knit')
490
1546
        # Lock the repository.
491
 
        repo_token = branch.repository.lock_write()
 
1547
        repo_token = branch.repository.lock_write().repository_token
492
1548
        branch.repository.leave_lock_in_place()
493
1549
        branch.repository.unlock()
494
1550
        # Issue branch lock_write request on the unlocked branch (with locked
495
1551
        # repo).
496
 
        response = request.execute(
497
 
            backing.local_abspath(''), 'branch token', repo_token)
 
1552
        response = request.execute('', 'branch token', repo_token)
498
1553
        self.assertEqual(
499
 
            SmartServerResponse(('TokenMismatch',)), response)
500
 
 
501
 
 
502
 
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
 
1554
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1555
        # Cleanup
 
1556
        branch.repository.lock_write(repo_token)
 
1557
        branch.repository.dont_leave_lock_in_place()
 
1558
        branch.repository.unlock()
 
1559
 
 
1560
 
 
1561
class TestSmartServerRepositoryRequest(tests.TestCaseWithMemoryTransport):
503
1562
 
504
1563
    def test_no_repository(self):
505
1564
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
508
1567
        # its the exact path being looked at and the server is not
509
1568
        # searching.
510
1569
        backing = self.get_transport()
511
 
        request = smart.repository.SmartServerRepositoryRequest(backing)
 
1570
        request = smart_repo.SmartServerRepositoryRequest(backing)
512
1571
        self.make_repository('.', shared=True)
513
1572
        self.make_bzrdir('subdir')
514
1573
        self.assertRaises(errors.NoRepositoryPresent,
515
 
            request.execute, backing.local_abspath('subdir'))
516
 
 
517
 
 
518
 
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
 
1574
            request.execute, 'subdir')
 
1575
 
 
1576
 
 
1577
class TestSmartServerRepositoryAddSignatureText(tests.TestCaseWithMemoryTransport):
 
1578
 
 
1579
    def test_add_text(self):
 
1580
        backing = self.get_transport()
 
1581
        request = smart_repo.SmartServerRepositoryAddSignatureText(backing)
 
1582
        tree = self.make_branch_and_memory_tree('.')
 
1583
        write_token = tree.lock_write()
 
1584
        self.addCleanup(tree.unlock)
 
1585
        tree.add('')
 
1586
        tree.commit("Message", rev_id='rev1')
 
1587
        tree.branch.repository.start_write_group()
 
1588
        write_group_tokens = tree.branch.repository.suspend_write_group()
 
1589
        self.assertEqual(None, request.execute('', write_token,
 
1590
            'rev1', *write_group_tokens))
 
1591
        response = request.do_body('somesignature')
 
1592
        self.assertTrue(response.is_successful())
 
1593
        self.assertEqual(response.args[0], 'ok')
 
1594
        write_group_tokens = response.args[1:]
 
1595
        tree.branch.repository.resume_write_group(write_group_tokens)
 
1596
        tree.branch.repository.commit_write_group()
 
1597
        tree.unlock()
 
1598
        self.assertEqual("somesignature",
 
1599
            tree.branch.repository.get_signature_text("rev1"))
 
1600
 
 
1601
 
 
1602
class TestSmartServerRepositoryAllRevisionIds(
 
1603
    tests.TestCaseWithMemoryTransport):
 
1604
 
 
1605
    def test_empty(self):
 
1606
        """An empty body should be returned for an empty repository."""
 
1607
        backing = self.get_transport()
 
1608
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1609
        self.make_repository('.')
 
1610
        self.assertEquals(
 
1611
            smart_req.SuccessfulSmartServerResponse(("ok", ), ""),
 
1612
            request.execute(''))
 
1613
 
 
1614
    def test_some_revisions(self):
 
1615
        """An empty body should be returned for an empty repository."""
 
1616
        backing = self.get_transport()
 
1617
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1618
        tree = self.make_branch_and_memory_tree('.')
 
1619
        tree.lock_write()
 
1620
        tree.add('')
 
1621
        tree.commit(rev_id='origineel', message="message")
 
1622
        tree.commit(rev_id='nog-een-revisie', message="message")
 
1623
        tree.unlock()
 
1624
        self.assertEquals(
 
1625
            smart_req.SuccessfulSmartServerResponse(("ok", ),
 
1626
                "origineel\nnog-een-revisie"),
 
1627
            request.execute(''))
 
1628
 
 
1629
 
 
1630
class TestSmartServerRepositoryBreakLock(tests.TestCaseWithMemoryTransport):
 
1631
 
 
1632
    def test_lock_to_break(self):
 
1633
        backing = self.get_transport()
 
1634
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1635
        tree = self.make_branch_and_memory_tree('.')
 
1636
        tree.branch.repository.lock_write()
 
1637
        self.assertEqual(
 
1638
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1639
            request.execute(''))
 
1640
 
 
1641
    def test_nothing_to_break(self):
 
1642
        backing = self.get_transport()
 
1643
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1644
        tree = self.make_branch_and_memory_tree('.')
 
1645
        self.assertEqual(
 
1646
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1647
            request.execute(''))
 
1648
 
 
1649
 
 
1650
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithMemoryTransport):
 
1651
 
 
1652
    def test_trivial_bzipped(self):
 
1653
        # This tests that the wire encoding is actually bzipped
 
1654
        backing = self.get_transport()
 
1655
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1656
        tree = self.make_branch_and_memory_tree('.')
 
1657
 
 
1658
        self.assertEqual(None,
 
1659
            request.execute('', 'missing-id'))
 
1660
        # Note that it returns a body that is bzipped.
 
1661
        self.assertEqual(
 
1662
            smart_req.SuccessfulSmartServerResponse(('ok', ), bz2.compress('')),
 
1663
            request.do_body('\n\n0\n'))
 
1664
 
 
1665
    def test_trivial_include_missing(self):
 
1666
        backing = self.get_transport()
 
1667
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1668
        tree = self.make_branch_and_memory_tree('.')
 
1669
 
 
1670
        self.assertEqual(None,
 
1671
            request.execute('', 'missing-id', 'include-missing:'))
 
1672
        self.assertEqual(
 
1673
            smart_req.SuccessfulSmartServerResponse(('ok', ),
 
1674
                bz2.compress('missing:missing-id')),
 
1675
            request.do_body('\n\n0\n'))
 
1676
 
 
1677
 
 
1678
class TestSmartServerRepositoryGetRevisionGraph(
 
1679
    tests.TestCaseWithMemoryTransport):
519
1680
 
520
1681
    def test_none_argument(self):
521
1682
        backing = self.get_transport()
522
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1683
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
523
1684
        tree = self.make_branch_and_memory_tree('.')
524
1685
        tree.lock_write()
525
1686
        tree.add('')
530
1691
        # the lines of revision_id->revision_parent_list has no guaranteed
531
1692
        # order coming out of a dict, so sort both our test and response
532
1693
        lines = sorted([' '.join([r2, r1]), r1])
533
 
        response = request.execute(backing.local_abspath(''), '')
 
1694
        response = request.execute('', '')
534
1695
        response.body = '\n'.join(sorted(response.body.split('\n')))
535
1696
 
536
1697
        self.assertEqual(
537
 
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
 
1698
            smart_req.SmartServerResponse(('ok', ), '\n'.join(lines)), response)
538
1699
 
539
1700
    def test_specific_revision_argument(self):
540
1701
        backing = self.get_transport()
541
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1702
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
542
1703
        tree = self.make_branch_and_memory_tree('.')
543
1704
        tree.lock_write()
544
1705
        tree.add('')
547
1708
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
548
1709
        tree.unlock()
549
1710
 
550
 
        self.assertEqual(SmartServerResponse(('ok', ), rev_id_utf8),
551
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
552
 
    
 
1711
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), rev_id_utf8),
 
1712
            request.execute('', rev_id_utf8))
 
1713
 
553
1714
    def test_no_such_revision(self):
554
1715
        backing = self.get_transport()
555
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1716
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
556
1717
        tree = self.make_branch_and_memory_tree('.')
557
1718
        tree.lock_write()
558
1719
        tree.add('')
560
1721
        tree.unlock()
561
1722
 
562
1723
        # Note that it still returns body (of zero bytes).
563
 
        self.assertEqual(
564
 
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
565
 
            request.execute(backing.local_abspath(''), 'missingrevision'))
566
 
 
567
 
 
568
 
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
 
1724
        self.assertEqual(smart_req.SmartServerResponse(
 
1725
                ('nosuchrevision', 'missingrevision', ), ''),
 
1726
                         request.execute('', 'missingrevision'))
 
1727
 
 
1728
 
 
1729
class TestSmartServerRepositoryGetRevIdForRevno(
 
1730
    tests.TestCaseWithMemoryTransport):
 
1731
 
 
1732
    def test_revno_found(self):
 
1733
        backing = self.get_transport()
 
1734
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1735
        tree = self.make_branch_and_memory_tree('.')
 
1736
        tree.lock_write()
 
1737
        tree.add('')
 
1738
        rev1_id_utf8 = u'\xc8'.encode('utf-8')
 
1739
        rev2_id_utf8 = u'\xc9'.encode('utf-8')
 
1740
        tree.commit('1st commit', rev_id=rev1_id_utf8)
 
1741
        tree.commit('2nd commit', rev_id=rev2_id_utf8)
 
1742
        tree.unlock()
 
1743
 
 
1744
        self.assertEqual(smart_req.SmartServerResponse(('ok', rev1_id_utf8)),
 
1745
            request.execute('', 1, (2, rev2_id_utf8)))
 
1746
 
 
1747
    def test_known_revid_missing(self):
 
1748
        backing = self.get_transport()
 
1749
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1750
        repo = self.make_repository('.')
 
1751
        self.assertEqual(
 
1752
            smart_req.FailedSmartServerResponse(('nosuchrevision', 'ghost')),
 
1753
            request.execute('', 1, (2, 'ghost')))
 
1754
 
 
1755
    def test_history_incomplete(self):
 
1756
        backing = self.get_transport()
 
1757
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1758
        parent = self.make_branch_and_memory_tree('parent', format='1.9')
 
1759
        parent.lock_write()
 
1760
        parent.add([''], ['TREE_ROOT'])
 
1761
        r1 = parent.commit(message='first commit')
 
1762
        r2 = parent.commit(message='second commit')
 
1763
        parent.unlock()
 
1764
        local = self.make_branch_and_memory_tree('local', format='1.9')
 
1765
        local.branch.pull(parent.branch)
 
1766
        local.set_parent_ids([r2])
 
1767
        r3 = local.commit(message='local commit')
 
1768
        local.branch.create_clone_on_transport(
 
1769
            self.get_transport('stacked'), stacked_on=self.get_url('parent'))
 
1770
        self.assertEqual(
 
1771
            smart_req.SmartServerResponse(('history-incomplete', 2, r2)),
 
1772
            request.execute('stacked', 1, (3, r3)))
 
1773
 
 
1774
 
 
1775
class TestSmartServerRepositoryIterRevisions(
 
1776
    tests.TestCaseWithMemoryTransport):
 
1777
 
 
1778
    def test_basic(self):
 
1779
        backing = self.get_transport()
 
1780
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1781
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1782
        tree.lock_write()
 
1783
        tree.add('')
 
1784
        tree.commit('1st commit', rev_id="rev1")
 
1785
        tree.commit('2nd commit', rev_id="rev2")
 
1786
        tree.unlock()
 
1787
 
 
1788
        self.assertIs(None, request.execute(''))
 
1789
        response = request.do_body("rev1\nrev2")
 
1790
        self.assertTrue(response.is_successful())
 
1791
        # Format 2a uses serializer format 10
 
1792
        self.assertEquals(response.args, ("ok", "10"))
 
1793
 
 
1794
        self.addCleanup(tree.branch.lock_read().unlock)
 
1795
        entries = [zlib.compress(record.get_bytes_as("fulltext")) for record in
 
1796
            tree.branch.repository.revisions.get_record_stream(
 
1797
            [("rev1", ), ("rev2", )], "unordered", True)]
 
1798
 
 
1799
        contents = "".join(response.body_stream)
 
1800
        self.assertTrue(contents in (
 
1801
            "".join([entries[0], entries[1]]),
 
1802
            "".join([entries[1], entries[0]])))
 
1803
 
 
1804
    def test_missing(self):
 
1805
        backing = self.get_transport()
 
1806
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1807
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1808
 
 
1809
        self.assertIs(None, request.execute(''))
 
1810
        response = request.do_body("rev1\nrev2")
 
1811
        self.assertTrue(response.is_successful())
 
1812
        # Format 2a uses serializer format 10
 
1813
        self.assertEquals(response.args, ("ok", "10"))
 
1814
 
 
1815
        contents = "".join(response.body_stream)
 
1816
        self.assertEquals(contents, "")
 
1817
 
 
1818
 
 
1819
class GetStreamTestBase(tests.TestCaseWithMemoryTransport):
 
1820
 
 
1821
    def make_two_commit_repo(self):
 
1822
        tree = self.make_branch_and_memory_tree('.')
 
1823
        tree.lock_write()
 
1824
        tree.add('')
 
1825
        r1 = tree.commit('1st commit')
 
1826
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
 
1827
        tree.unlock()
 
1828
        repo = tree.branch.repository
 
1829
        return repo, r1, r2
 
1830
 
 
1831
 
 
1832
class TestSmartServerRepositoryGetStream(GetStreamTestBase):
 
1833
 
 
1834
    def test_ancestry_of(self):
 
1835
        """The search argument may be a 'ancestry-of' some heads'."""
 
1836
        backing = self.get_transport()
 
1837
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1838
        repo, r1, r2 = self.make_two_commit_repo()
 
1839
        fetch_spec = ['ancestry-of', r2]
 
1840
        lines = '\n'.join(fetch_spec)
 
1841
        request.execute('', repo._format.network_name())
 
1842
        response = request.do_body(lines)
 
1843
        self.assertEqual(('ok',), response.args)
 
1844
        stream_bytes = ''.join(response.body_stream)
 
1845
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1846
 
 
1847
    def test_search(self):
 
1848
        """The search argument may be a 'search' of some explicit keys."""
 
1849
        backing = self.get_transport()
 
1850
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1851
        repo, r1, r2 = self.make_two_commit_repo()
 
1852
        fetch_spec = ['search', '%s %s' % (r1, r2), 'null:', '2']
 
1853
        lines = '\n'.join(fetch_spec)
 
1854
        request.execute('', repo._format.network_name())
 
1855
        response = request.do_body(lines)
 
1856
        self.assertEqual(('ok',), response.args)
 
1857
        stream_bytes = ''.join(response.body_stream)
 
1858
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1859
 
 
1860
    def test_search_everything(self):
 
1861
        """A search of 'everything' returns a stream."""
 
1862
        backing = self.get_transport()
 
1863
        request = smart_repo.SmartServerRepositoryGetStream_1_19(backing)
 
1864
        repo, r1, r2 = self.make_two_commit_repo()
 
1865
        serialised_fetch_spec = 'everything'
 
1866
        request.execute('', repo._format.network_name())
 
1867
        response = request.do_body(serialised_fetch_spec)
 
1868
        self.assertEqual(('ok',), response.args)
 
1869
        stream_bytes = ''.join(response.body_stream)
 
1870
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1871
 
 
1872
 
 
1873
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
569
1874
 
570
1875
    def test_missing_revision(self):
571
1876
        """For a missing revision, ('no', ) is returned."""
572
1877
        backing = self.get_transport()
573
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1878
        request = smart_repo.SmartServerRequestHasRevision(backing)
574
1879
        self.make_repository('.')
575
 
        self.assertEqual(SmartServerResponse(('no', )),
576
 
            request.execute(backing.local_abspath(''), 'revid'))
 
1880
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1881
            request.execute('', 'revid'))
577
1882
 
578
1883
    def test_present_revision(self):
579
1884
        """For a present revision, ('yes', ) is returned."""
580
1885
        backing = self.get_transport()
581
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1886
        request = smart_repo.SmartServerRequestHasRevision(backing)
582
1887
        tree = self.make_branch_and_memory_tree('.')
583
1888
        tree.lock_write()
584
1889
        tree.add('')
586
1891
        r1 = tree.commit('a commit', rev_id=rev_id_utf8)
587
1892
        tree.unlock()
588
1893
        self.assertTrue(tree.branch.repository.has_revision(rev_id_utf8))
589
 
        self.assertEqual(SmartServerResponse(('yes', )),
590
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
591
 
 
592
 
 
593
 
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
 
1894
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1895
            request.execute('', rev_id_utf8))
 
1896
 
 
1897
 
 
1898
class TestSmartServerRepositoryIterFilesBytes(tests.TestCaseWithTransport):
 
1899
 
 
1900
    def test_single(self):
 
1901
        backing = self.get_transport()
 
1902
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1903
        t = self.make_branch_and_tree('.')
 
1904
        self.addCleanup(t.lock_write().unlock)
 
1905
        self.build_tree_contents([("file", "somecontents")])
 
1906
        t.add(["file"], ["thefileid"])
 
1907
        t.commit(rev_id='somerev', message="add file")
 
1908
        self.assertIs(None, request.execute(''))
 
1909
        response = request.do_body("thefileid\0somerev\n")
 
1910
        self.assertTrue(response.is_successful())
 
1911
        self.assertEquals(response.args, ("ok", ))
 
1912
        self.assertEquals("".join(response.body_stream),
 
1913
            "ok\x000\n" + zlib.compress("somecontents"))
 
1914
 
 
1915
    def test_missing(self):
 
1916
        backing = self.get_transport()
 
1917
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1918
        t = self.make_branch_and_tree('.')
 
1919
        self.addCleanup(t.lock_write().unlock)
 
1920
        self.assertIs(None, request.execute(''))
 
1921
        response = request.do_body("thefileid\0revision\n")
 
1922
        self.assertTrue(response.is_successful())
 
1923
        self.assertEquals(response.args, ("ok", ))
 
1924
        self.assertEquals("".join(response.body_stream),
 
1925
            "absent\x00thefileid\x00revision\x000\n")
 
1926
 
 
1927
 
 
1928
class TestSmartServerRequestHasSignatureForRevisionId(
 
1929
        tests.TestCaseWithMemoryTransport):
 
1930
 
 
1931
    def test_missing_revision(self):
 
1932
        """For a missing revision, NoSuchRevision is returned."""
 
1933
        backing = self.get_transport()
 
1934
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1935
            backing)
 
1936
        self.make_repository('.')
 
1937
        self.assertEqual(
 
1938
            smart_req.FailedSmartServerResponse(
 
1939
                ('nosuchrevision', 'revid'), None),
 
1940
            request.execute('', 'revid'))
 
1941
 
 
1942
    def test_missing_signature(self):
 
1943
        """For a missing signature, ('no', ) is returned."""
 
1944
        backing = self.get_transport()
 
1945
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1946
            backing)
 
1947
        tree = self.make_branch_and_memory_tree('.')
 
1948
        tree.lock_write()
 
1949
        tree.add('')
 
1950
        r1 = tree.commit('a commit', rev_id='A')
 
1951
        tree.unlock()
 
1952
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1953
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1954
            request.execute('', 'A'))
 
1955
 
 
1956
    def test_present_signature(self):
 
1957
        """For a present signature, ('yes', ) is returned."""
 
1958
        backing = self.get_transport()
 
1959
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1960
            backing)
 
1961
        strategy = gpg.LoopbackGPGStrategy(None)
 
1962
        tree = self.make_branch_and_memory_tree('.')
 
1963
        tree.lock_write()
 
1964
        tree.add('')
 
1965
        r1 = tree.commit('a commit', rev_id='A')
 
1966
        tree.branch.repository.start_write_group()
 
1967
        tree.branch.repository.sign_revision('A', strategy)
 
1968
        tree.branch.repository.commit_write_group()
 
1969
        tree.unlock()
 
1970
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1971
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1972
            request.execute('', 'A'))
 
1973
 
 
1974
 
 
1975
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithMemoryTransport):
594
1976
 
595
1977
    def test_empty_revid(self):
596
1978
        """With an empty revid, we get only size an number and revisions"""
597
1979
        backing = self.get_transport()
598
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1980
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
599
1981
        repository = self.make_repository('.')
600
1982
        stats = repository.gather_stats()
601
 
        size = stats['size']
602
 
        expected_body = 'revisions: 0\nsize: %d\n' % size
603
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
604
 
                         request.execute(backing.local_abspath(''), '', 'no'))
 
1983
        expected_body = 'revisions: 0\n'
 
1984
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1985
                         request.execute('', '', 'no'))
605
1986
 
606
1987
    def test_revid_with_committers(self):
607
1988
        """For a revid we get more infos."""
608
1989
        backing = self.get_transport()
609
1990
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
610
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1991
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
611
1992
        tree = self.make_branch_and_memory_tree('.')
612
1993
        tree.lock_write()
613
1994
        tree.add('')
618
1999
        tree.unlock()
619
2000
 
620
2001
        stats = tree.branch.repository.gather_stats()
621
 
        size = stats['size']
622
2002
        expected_body = ('firstrev: 123456.200 3600\n'
623
2003
                         'latestrev: 654321.400 0\n'
624
 
                         'revisions: 2\n'
625
 
                         'size: %d\n' % size)
626
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
627
 
                         request.execute(backing.local_abspath(''),
 
2004
                         'revisions: 2\n')
 
2005
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
2006
                         request.execute('',
628
2007
                                         rev_id_utf8, 'no'))
629
2008
 
630
2009
    def test_not_empty_repository_with_committers(self):
631
2010
        """For a revid and requesting committers we get the whole thing."""
632
2011
        backing = self.get_transport()
633
2012
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
634
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
2013
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
635
2014
        tree = self.make_branch_and_memory_tree('.')
636
2015
        tree.lock_write()
637
2016
        tree.add('')
643
2022
        tree.unlock()
644
2023
        stats = tree.branch.repository.gather_stats()
645
2024
 
646
 
        size = stats['size']
647
2025
        expected_body = ('committers: 2\n'
648
2026
                         'firstrev: 123456.200 3600\n'
649
2027
                         'latestrev: 654321.400 0\n'
650
 
                         'revisions: 2\n'
651
 
                         'size: %d\n' % size)
652
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
653
 
                         request.execute(backing.local_abspath(''),
 
2028
                         'revisions: 2\n')
 
2029
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
2030
                         request.execute('',
654
2031
                                         rev_id_utf8, 'yes'))
655
2032
 
656
 
 
657
 
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
 
2033
    def test_unknown_revid(self):
 
2034
        """An unknown revision id causes a 'nosuchrevision' error."""
 
2035
        backing = self.get_transport()
 
2036
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
 
2037
        repository = self.make_repository('.')
 
2038
        expected_body = 'revisions: 0\n'
 
2039
        self.assertEqual(
 
2040
            smart_req.FailedSmartServerResponse(
 
2041
                ('nosuchrevision', 'mia'), None),
 
2042
            request.execute('', 'mia', 'yes'))
 
2043
 
 
2044
 
 
2045
class TestSmartServerRepositoryIsShared(tests.TestCaseWithMemoryTransport):
658
2046
 
659
2047
    def test_is_shared(self):
660
2048
        """For a shared repository, ('yes', ) is returned."""
661
2049
        backing = self.get_transport()
662
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
2050
        request = smart_repo.SmartServerRepositoryIsShared(backing)
663
2051
        self.make_repository('.', shared=True)
664
 
        self.assertEqual(SmartServerResponse(('yes', )),
665
 
            request.execute(backing.local_abspath(''), ))
 
2052
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2053
            request.execute('', ))
666
2054
 
667
2055
    def test_is_not_shared(self):
668
2056
        """For a shared repository, ('no', ) is returned."""
669
2057
        backing = self.get_transport()
670
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
2058
        request = smart_repo.SmartServerRepositoryIsShared(backing)
671
2059
        self.make_repository('.', shared=False)
672
 
        self.assertEqual(SmartServerResponse(('no', )),
673
 
            request.execute(backing.local_abspath(''), ))
674
 
 
675
 
 
676
 
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
677
 
 
678
 
    def setUp(self):
679
 
        tests.TestCaseWithTransport.setUp(self)
680
 
        self.reduceLockdirTimeout()
 
2060
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2061
            request.execute('', ))
 
2062
 
 
2063
 
 
2064
class TestSmartServerRepositoryGetRevisionSignatureText(
 
2065
        tests.TestCaseWithMemoryTransport):
 
2066
 
 
2067
    def test_get_signature(self):
 
2068
        backing = self.get_transport()
 
2069
        request = smart_repo.SmartServerRepositoryGetRevisionSignatureText(
 
2070
            backing)
 
2071
        bb = self.make_branch_builder('.')
 
2072
        bb.build_commit(rev_id='A')
 
2073
        repo = bb.get_branch().repository
 
2074
        strategy = gpg.LoopbackGPGStrategy(None)
 
2075
        self.addCleanup(repo.lock_write().unlock)
 
2076
        repo.start_write_group()
 
2077
        repo.sign_revision('A', strategy)
 
2078
        repo.commit_write_group()
 
2079
        expected_body = (
 
2080
            '-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
 
2081
            Testament.from_revision(repo, 'A').as_short_text() +
 
2082
            '-----END PSEUDO-SIGNED CONTENT-----\n')
 
2083
        self.assertEqual(
 
2084
            smart_req.SmartServerResponse(('ok', ), expected_body),
 
2085
            request.execute('', 'A'))
 
2086
 
 
2087
 
 
2088
class TestSmartServerRepositoryMakeWorkingTrees(
 
2089
        tests.TestCaseWithMemoryTransport):
 
2090
 
 
2091
    def test_make_working_trees(self):
 
2092
        """For a repository with working trees, ('yes', ) is returned."""
 
2093
        backing = self.get_transport()
 
2094
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2095
        r = self.make_repository('.')
 
2096
        r.set_make_working_trees(True)
 
2097
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2098
            request.execute('', ))
 
2099
 
 
2100
    def test_is_not_shared(self):
 
2101
        """For a repository with working trees, ('no', ) is returned."""
 
2102
        backing = self.get_transport()
 
2103
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2104
        r = self.make_repository('.')
 
2105
        r.set_make_working_trees(False)
 
2106
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2107
            request.execute('', ))
 
2108
 
 
2109
 
 
2110
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
681
2111
 
682
2112
    def test_lock_write_on_unlocked_repo(self):
683
2113
        backing = self.get_transport()
684
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
685
 
        repository = self.make_repository('.')
686
 
        response = request.execute(backing.local_abspath(''))
 
2114
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
2115
        repository = self.make_repository('.', format='knit')
 
2116
        response = request.execute('')
687
2117
        nonce = repository.control_files._lock.peek().get('nonce')
688
 
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
 
2118
        self.assertEqual(smart_req.SmartServerResponse(('ok', nonce)), response)
689
2119
        # The repository is now locked.  Verify that with a new repository
690
2120
        # object.
691
2121
        new_repo = repository.bzrdir.open_repository()
692
2122
        self.assertRaises(errors.LockContention, new_repo.lock_write)
 
2123
        # Cleanup
 
2124
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2125
        response = request.execute('', nonce)
693
2126
 
694
2127
    def test_lock_write_on_locked_repo(self):
695
2128
        backing = self.get_transport()
696
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
697
 
        repository = self.make_repository('.')
698
 
        repository.lock_write()
 
2129
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
2130
        repository = self.make_repository('.', format='knit')
 
2131
        repo_token = repository.lock_write().repository_token
699
2132
        repository.leave_lock_in_place()
700
2133
        repository.unlock()
701
 
        response = request.execute(backing.local_abspath(''))
 
2134
        response = request.execute('')
702
2135
        self.assertEqual(
703
 
            SmartServerResponse(('LockContention',)), response)
 
2136
            smart_req.SmartServerResponse(('LockContention',)), response)
 
2137
        # Cleanup
 
2138
        repository.lock_write(repo_token)
 
2139
        repository.dont_leave_lock_in_place()
 
2140
        repository.unlock()
704
2141
 
705
2142
    def test_lock_write_on_readonly_transport(self):
706
2143
        backing = self.get_readonly_transport()
707
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
 
2144
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
2145
        repository = self.make_repository('.', format='knit')
 
2146
        response = request.execute('')
 
2147
        self.assertFalse(response.is_successful())
 
2148
        self.assertEqual('LockFailed', response.args[0])
 
2149
 
 
2150
 
 
2151
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
 
2152
 
 
2153
    def make_empty_byte_stream(self, repo):
 
2154
        byte_stream = smart_repo._stream_to_byte_stream([], repo._format)
 
2155
        return ''.join(byte_stream)
 
2156
 
 
2157
 
 
2158
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
 
2159
 
 
2160
    def test_insert_stream_empty(self):
 
2161
        backing = self.get_transport()
 
2162
        request = smart_repo.SmartServerRepositoryInsertStream(backing)
708
2163
        repository = self.make_repository('.')
709
 
        response = request.execute('')
710
 
        self.assertEqual(
711
 
            SmartServerResponse(('UnlockableTransport',)), response)
712
 
 
713
 
 
714
 
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
 
2164
        response = request.execute('', '')
 
2165
        self.assertEqual(None, response)
 
2166
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
2167
        self.assertEqual(None, response)
 
2168
        response = request.do_end()
 
2169
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
2170
 
 
2171
 
 
2172
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
 
2173
 
 
2174
    def test_insert_stream_empty(self):
 
2175
        backing = self.get_transport()
 
2176
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
2177
            backing)
 
2178
        repository = self.make_repository('.', format='knit')
 
2179
        lock_token = repository.lock_write().repository_token
 
2180
        response = request.execute('', '', lock_token)
 
2181
        self.assertEqual(None, response)
 
2182
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
2183
        self.assertEqual(None, response)
 
2184
        response = request.do_end()
 
2185
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
2186
        repository.unlock()
 
2187
 
 
2188
    def test_insert_stream_with_wrong_lock_token(self):
 
2189
        backing = self.get_transport()
 
2190
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
2191
            backing)
 
2192
        repository = self.make_repository('.', format='knit')
 
2193
        lock_token = repository.lock_write().repository_token
 
2194
        self.assertRaises(
 
2195
            errors.TokenMismatch, request.execute, '', '', 'wrong-token')
 
2196
        repository.unlock()
 
2197
 
 
2198
 
 
2199
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
715
2200
 
716
2201
    def setUp(self):
717
 
        tests.TestCaseWithTransport.setUp(self)
718
 
        self.reduceLockdirTimeout()
 
2202
        tests.TestCaseWithMemoryTransport.setUp(self)
719
2203
 
720
2204
    def test_unlock_on_locked_repo(self):
721
2205
        backing = self.get_transport()
722
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
723
 
        repository = self.make_repository('.')
724
 
        token = repository.lock_write()
 
2206
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2207
        repository = self.make_repository('.', format='knit')
 
2208
        token = repository.lock_write().repository_token
725
2209
        repository.leave_lock_in_place()
726
2210
        repository.unlock()
727
 
        response = request.execute(backing.local_abspath(''), token)
 
2211
        response = request.execute('', token)
728
2212
        self.assertEqual(
729
 
            SmartServerResponse(('ok',)), response)
 
2213
            smart_req.SmartServerResponse(('ok',)), response)
730
2214
        # The repository is now unlocked.  Verify that with a new repository
731
2215
        # object.
732
2216
        new_repo = repository.bzrdir.open_repository()
735
2219
 
736
2220
    def test_unlock_on_unlocked_repo(self):
737
2221
        backing = self.get_transport()
738
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
739
 
        repository = self.make_repository('.')
740
 
        response = request.execute(backing.local_abspath(''), 'some token')
 
2222
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2223
        repository = self.make_repository('.', format='knit')
 
2224
        response = request.execute('', 'some token')
741
2225
        self.assertEqual(
742
 
            SmartServerResponse(('TokenMismatch',)), response)
743
 
 
744
 
 
745
 
class TestSmartServerRepositoryTarball(tests.TestCaseWithTransport):
746
 
 
747
 
    def test_repository_tarball(self):
748
 
        backing = self.get_transport()
749
 
        request = smart.repository.SmartServerRepositoryTarball(backing)
750
 
        repository = self.make_repository('.')
751
 
        # make some extraneous junk in the repository directory which should
752
 
        # not be copied
753
 
        self.build_tree(['.bzr/repository/extra-junk'])
754
 
        response = request.execute(backing.local_abspath(''), 'bz2')
755
 
        self.assertEqual(('ok',), response.args)
756
 
        # body should be a tbz2
757
 
        body_file = StringIO(response.body)
758
 
        body_tar = tarfile.open('body_tar.tbz2', fileobj=body_file,
759
 
            mode='r|bz2')
760
 
        # let's make sure there are some key repository components inside it.
761
 
        # the tarfile returns directories with trailing slashes...
762
 
        names = set([n.rstrip('/') for n in body_tar.getnames()])
763
 
        self.assertTrue('.bzr/repository/lock' in names)
764
 
        self.assertTrue('.bzr/repository/format' in names)
765
 
        self.assertTrue('.bzr/repository/extra-junk' not in names,
766
 
            "extraneous file present in tar file")
767
 
 
768
 
 
769
 
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
 
2226
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
2227
 
 
2228
 
 
2229
class TestSmartServerRepositoryGetPhysicalLockStatus(
 
2230
    tests.TestCaseWithTransport):
 
2231
 
 
2232
    def test_with_write_lock(self):
 
2233
        backing = self.get_transport()
 
2234
        repo = self.make_repository('.')
 
2235
        self.addCleanup(repo.lock_write().unlock)
 
2236
        # lock_write() doesn't necessarily actually take a physical
 
2237
        # lock out.
 
2238
        if repo.get_physical_lock_status():
 
2239
            expected = 'yes'
 
2240
        else:
 
2241
            expected = 'no'
 
2242
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2243
        request = request_class(backing)
 
2244
        self.assertEqual(smart_req.SuccessfulSmartServerResponse((expected,)),
 
2245
            request.execute('', ))
 
2246
 
 
2247
    def test_without_write_lock(self):
 
2248
        backing = self.get_transport()
 
2249
        repo = self.make_repository('.')
 
2250
        self.assertEquals(False, repo.get_physical_lock_status())
 
2251
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2252
        request = request_class(backing)
 
2253
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('no',)),
 
2254
            request.execute('', ))
 
2255
 
 
2256
 
 
2257
class TestSmartServerRepositoryReconcile(tests.TestCaseWithTransport):
 
2258
 
 
2259
    def test_reconcile(self):
 
2260
        backing = self.get_transport()
 
2261
        repo = self.make_repository('.')
 
2262
        token = repo.lock_write().repository_token
 
2263
        self.addCleanup(repo.unlock)
 
2264
        request_class = smart_repo.SmartServerRepositoryReconcile
 
2265
        request = request_class(backing)
 
2266
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
2267
            ('ok', ),
 
2268
             'garbage_inventories: 0\n'
 
2269
             'inconsistent_parents: 0\n'),
 
2270
            request.execute('', token))
 
2271
 
 
2272
 
 
2273
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
770
2274
 
771
2275
    def test_is_readonly_no(self):
772
2276
        backing = self.get_transport()
773
 
        request = smart.request.SmartServerIsReadonly(backing)
 
2277
        request = smart_req.SmartServerIsReadonly(backing)
774
2278
        response = request.execute()
775
2279
        self.assertEqual(
776
 
            SmartServerResponse(('no',)), response)
 
2280
            smart_req.SmartServerResponse(('no',)), response)
777
2281
 
778
2282
    def test_is_readonly_yes(self):
779
2283
        backing = self.get_readonly_transport()
780
 
        request = smart.request.SmartServerIsReadonly(backing)
 
2284
        request = smart_req.SmartServerIsReadonly(backing)
781
2285
        response = request.execute()
782
2286
        self.assertEqual(
783
 
            SmartServerResponse(('yes',)), response)
 
2287
            smart_req.SmartServerResponse(('yes',)), response)
 
2288
 
 
2289
 
 
2290
class TestSmartServerRepositorySetMakeWorkingTrees(
 
2291
    tests.TestCaseWithMemoryTransport):
 
2292
 
 
2293
    def test_set_false(self):
 
2294
        backing = self.get_transport()
 
2295
        repo = self.make_repository('.', shared=True)
 
2296
        repo.set_make_working_trees(True)
 
2297
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
2298
        request = request_class(backing)
 
2299
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2300
            request.execute('', 'False'))
 
2301
        repo = repo.bzrdir.open_repository()
 
2302
        self.assertFalse(repo.make_working_trees())
 
2303
 
 
2304
    def test_set_true(self):
 
2305
        backing = self.get_transport()
 
2306
        repo = self.make_repository('.', shared=True)
 
2307
        repo.set_make_working_trees(False)
 
2308
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
2309
        request = request_class(backing)
 
2310
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2311
            request.execute('', 'True'))
 
2312
        repo = repo.bzrdir.open_repository()
 
2313
        self.assertTrue(repo.make_working_trees())
 
2314
 
 
2315
 
 
2316
class TestSmartServerRepositoryGetSerializerFormat(
 
2317
    tests.TestCaseWithMemoryTransport):
 
2318
 
 
2319
    def test_get_serializer_format(self):
 
2320
        backing = self.get_transport()
 
2321
        repo = self.make_repository('.', format='2a')
 
2322
        request_class = smart_repo.SmartServerRepositoryGetSerializerFormat
 
2323
        request = request_class(backing)
 
2324
        self.assertEqual(
 
2325
            smart_req.SuccessfulSmartServerResponse(('ok', '10')),
 
2326
            request.execute(''))
 
2327
 
 
2328
 
 
2329
class TestSmartServerRepositoryWriteGroup(
 
2330
    tests.TestCaseWithMemoryTransport):
 
2331
 
 
2332
    def test_start_write_group(self):
 
2333
        backing = self.get_transport()
 
2334
        repo = self.make_repository('.')
 
2335
        lock_token = repo.lock_write().repository_token
 
2336
        self.addCleanup(repo.unlock)
 
2337
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2338
        request = request_class(backing)
 
2339
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok', [])),
 
2340
            request.execute('', lock_token))
 
2341
 
 
2342
    def test_start_write_group_unsuspendable(self):
 
2343
        backing = self.get_transport()
 
2344
        repo = self.make_repository('.', format='knit')
 
2345
        lock_token = repo.lock_write().repository_token
 
2346
        self.addCleanup(repo.unlock)
 
2347
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2348
        request = request_class(backing)
 
2349
        self.assertEqual(
 
2350
            smart_req.FailedSmartServerResponse(('UnsuspendableWriteGroup',)),
 
2351
            request.execute('', lock_token))
 
2352
 
 
2353
    def test_commit_write_group(self):
 
2354
        backing = self.get_transport()
 
2355
        repo = self.make_repository('.')
 
2356
        lock_token = repo.lock_write().repository_token
 
2357
        self.addCleanup(repo.unlock)
 
2358
        repo.start_write_group()
 
2359
        tokens = repo.suspend_write_group()
 
2360
        request_class = smart_repo.SmartServerRepositoryCommitWriteGroup
 
2361
        request = request_class(backing)
 
2362
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2363
            request.execute('', lock_token, tokens))
 
2364
 
 
2365
    def test_abort_write_group(self):
 
2366
        backing = self.get_transport()
 
2367
        repo = self.make_repository('.')
 
2368
        lock_token = repo.lock_write().repository_token
 
2369
        repo.start_write_group()
 
2370
        tokens = repo.suspend_write_group()
 
2371
        self.addCleanup(repo.unlock)
 
2372
        request_class = smart_repo.SmartServerRepositoryAbortWriteGroup
 
2373
        request = request_class(backing)
 
2374
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2375
            request.execute('', lock_token, tokens))
 
2376
 
 
2377
    def test_check_write_group(self):
 
2378
        backing = self.get_transport()
 
2379
        repo = self.make_repository('.')
 
2380
        lock_token = repo.lock_write().repository_token
 
2381
        repo.start_write_group()
 
2382
        tokens = repo.suspend_write_group()
 
2383
        self.addCleanup(repo.unlock)
 
2384
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2385
        request = request_class(backing)
 
2386
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2387
            request.execute('', lock_token, tokens))
 
2388
 
 
2389
    def test_check_write_group_invalid(self):
 
2390
        backing = self.get_transport()
 
2391
        repo = self.make_repository('.')
 
2392
        lock_token = repo.lock_write().repository_token
 
2393
        self.addCleanup(repo.unlock)
 
2394
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2395
        request = request_class(backing)
 
2396
        self.assertEqual(smart_req.FailedSmartServerResponse(
 
2397
            ('UnresumableWriteGroup', ['random'],
 
2398
                'Malformed write group token')),
 
2399
            request.execute('', lock_token, ["random"]))
 
2400
 
 
2401
 
 
2402
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
 
2403
 
 
2404
    def make_repo_needing_autopacking(self, path='.'):
 
2405
        # Make a repo in need of autopacking.
 
2406
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
2407
        repo = tree.branch.repository
 
2408
        # monkey-patch the pack collection to disable autopacking
 
2409
        repo._pack_collection._max_pack_count = lambda count: count
 
2410
        for x in range(10):
 
2411
            tree.commit('commit %s' % x)
 
2412
        self.assertEqual(10, len(repo._pack_collection.names()))
 
2413
        del repo._pack_collection._max_pack_count
 
2414
        return repo
 
2415
 
 
2416
    def test_autopack_needed(self):
 
2417
        repo = self.make_repo_needing_autopacking()
 
2418
        repo.lock_write()
 
2419
        self.addCleanup(repo.unlock)
 
2420
        backing = self.get_transport()
 
2421
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2422
            backing)
 
2423
        response = request.execute('')
 
2424
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2425
        repo._pack_collection.reload_pack_names()
 
2426
        self.assertEqual(1, len(repo._pack_collection.names()))
 
2427
 
 
2428
    def test_autopack_not_needed(self):
 
2429
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
2430
        repo = tree.branch.repository
 
2431
        repo.lock_write()
 
2432
        self.addCleanup(repo.unlock)
 
2433
        for x in range(9):
 
2434
            tree.commit('commit %s' % x)
 
2435
        backing = self.get_transport()
 
2436
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2437
            backing)
 
2438
        response = request.execute('')
 
2439
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2440
        repo._pack_collection.reload_pack_names()
 
2441
        self.assertEqual(9, len(repo._pack_collection.names()))
 
2442
 
 
2443
    def test_autopack_on_nonpack_format(self):
 
2444
        """A request to autopack a non-pack repo is a no-op."""
 
2445
        repo = self.make_repository('.', format='knit')
 
2446
        backing = self.get_transport()
 
2447
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2448
            backing)
 
2449
        response = request.execute('')
 
2450
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2451
 
 
2452
 
 
2453
class TestSmartServerVfsGet(tests.TestCaseWithMemoryTransport):
 
2454
 
 
2455
    def test_unicode_path(self):
 
2456
        """VFS requests expect unicode paths to be escaped."""
 
2457
        filename = u'foo\N{INTERROBANG}'
 
2458
        filename_escaped = urlutils.escape(filename)
 
2459
        backing = self.get_transport()
 
2460
        request = vfs.GetRequest(backing)
 
2461
        backing.put_bytes_non_atomic(filename_escaped, 'contents')
 
2462
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'contents'),
 
2463
            request.execute(filename_escaped))
784
2464
 
785
2465
 
786
2466
class TestHandlers(tests.TestCase):
787
2467
    """Tests for the request.request_handlers object."""
788
2468
 
 
2469
    def test_all_registrations_exist(self):
 
2470
        """All registered request_handlers can be found."""
 
2471
        # If there's a typo in a register_lazy call, this loop will fail with
 
2472
        # an AttributeError.
 
2473
        for key in smart_req.request_handlers.keys():
 
2474
            try:
 
2475
                item = smart_req.request_handlers.get(key)
 
2476
            except AttributeError, e:
 
2477
                raise AttributeError('failed to get %s: %s' % (key, e))
 
2478
 
 
2479
    def assertHandlerEqual(self, verb, handler):
 
2480
        self.assertEqual(smart_req.request_handlers.get(verb), handler)
 
2481
 
789
2482
    def test_registered_methods(self):
790
2483
        """Test that known methods are registered to the correct object."""
791
 
        self.assertEqual(
792
 
            smart.request.request_handlers.get('Branch.get_config_file'),
793
 
            smart.branch.SmartServerBranchGetConfigFile)
794
 
        self.assertEqual(
795
 
            smart.request.request_handlers.get('Branch.lock_write'),
796
 
            smart.branch.SmartServerBranchRequestLockWrite)
797
 
        self.assertEqual(
798
 
            smart.request.request_handlers.get('Branch.last_revision_info'),
799
 
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
800
 
        self.assertEqual(
801
 
            smart.request.request_handlers.get('Branch.revision_history'),
802
 
            smart.branch.SmartServerRequestRevisionHistory)
803
 
        self.assertEqual(
804
 
            smart.request.request_handlers.get('Branch.set_last_revision'),
805
 
            smart.branch.SmartServerBranchRequestSetLastRevision)
806
 
        self.assertEqual(
807
 
            smart.request.request_handlers.get('Branch.unlock'),
808
 
            smart.branch.SmartServerBranchRequestUnlock)
809
 
        self.assertEqual(
810
 
            smart.request.request_handlers.get('BzrDir.find_repository'),
811
 
            smart.bzrdir.SmartServerRequestFindRepository)
812
 
        self.assertEqual(
813
 
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
814
 
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
815
 
        self.assertEqual(
816
 
            smart.request.request_handlers.get('BzrDir.open_branch'),
817
 
            smart.bzrdir.SmartServerRequestOpenBranch)
818
 
        self.assertEqual(
819
 
            smart.request.request_handlers.get('Repository.gather_stats'),
820
 
            smart.repository.SmartServerRepositoryGatherStats)
821
 
        self.assertEqual(
822
 
            smart.request.request_handlers.get('Repository.get_revision_graph'),
823
 
            smart.repository.SmartServerRepositoryGetRevisionGraph)
824
 
        self.assertEqual(
825
 
            smart.request.request_handlers.get('Repository.has_revision'),
826
 
            smart.repository.SmartServerRequestHasRevision)
827
 
        self.assertEqual(
828
 
            smart.request.request_handlers.get('Repository.is_shared'),
829
 
            smart.repository.SmartServerRepositoryIsShared)
830
 
        self.assertEqual(
831
 
            smart.request.request_handlers.get('Repository.lock_write'),
832
 
            smart.repository.SmartServerRepositoryLockWrite)
833
 
        self.assertEqual(
834
 
            smart.request.request_handlers.get('Repository.unlock'),
835
 
            smart.repository.SmartServerRepositoryUnlock)
836
 
        self.assertEqual(
837
 
            smart.request.request_handlers.get('Repository.tarball'),
838
 
            smart.repository.SmartServerRepositoryTarball)
839
 
        self.assertEqual(
840
 
            smart.request.request_handlers.get('Transport.is_readonly'),
841
 
            smart.request.SmartServerIsReadonly)
 
2484
        self.assertHandlerEqual('Branch.break_lock',
 
2485
            smart_branch.SmartServerBranchBreakLock)
 
2486
        self.assertHandlerEqual('Branch.get_config_file',
 
2487
            smart_branch.SmartServerBranchGetConfigFile)
 
2488
        self.assertHandlerEqual('Branch.put_config_file',
 
2489
            smart_branch.SmartServerBranchPutConfigFile)
 
2490
        self.assertHandlerEqual('Branch.get_parent',
 
2491
            smart_branch.SmartServerBranchGetParent)
 
2492
        self.assertHandlerEqual('Branch.get_physical_lock_status',
 
2493
            smart_branch.SmartServerBranchRequestGetPhysicalLockStatus)
 
2494
        self.assertHandlerEqual('Branch.get_tags_bytes',
 
2495
            smart_branch.SmartServerBranchGetTagsBytes)
 
2496
        self.assertHandlerEqual('Branch.lock_write',
 
2497
            smart_branch.SmartServerBranchRequestLockWrite)
 
2498
        self.assertHandlerEqual('Branch.last_revision_info',
 
2499
            smart_branch.SmartServerBranchRequestLastRevisionInfo)
 
2500
        self.assertHandlerEqual('Branch.revision_history',
 
2501
            smart_branch.SmartServerRequestRevisionHistory)
 
2502
        self.assertHandlerEqual('Branch.revision_id_to_revno',
 
2503
            smart_branch.SmartServerBranchRequestRevisionIdToRevno)
 
2504
        self.assertHandlerEqual('Branch.set_config_option',
 
2505
            smart_branch.SmartServerBranchRequestSetConfigOption)
 
2506
        self.assertHandlerEqual('Branch.set_last_revision',
 
2507
            smart_branch.SmartServerBranchRequestSetLastRevision)
 
2508
        self.assertHandlerEqual('Branch.set_last_revision_info',
 
2509
            smart_branch.SmartServerBranchRequestSetLastRevisionInfo)
 
2510
        self.assertHandlerEqual('Branch.set_last_revision_ex',
 
2511
            smart_branch.SmartServerBranchRequestSetLastRevisionEx)
 
2512
        self.assertHandlerEqual('Branch.set_parent_location',
 
2513
            smart_branch.SmartServerBranchRequestSetParentLocation)
 
2514
        self.assertHandlerEqual('Branch.unlock',
 
2515
            smart_branch.SmartServerBranchRequestUnlock)
 
2516
        self.assertHandlerEqual('BzrDir.destroy_branch',
 
2517
            smart_dir.SmartServerBzrDirRequestDestroyBranch)
 
2518
        self.assertHandlerEqual('BzrDir.find_repository',
 
2519
            smart_dir.SmartServerRequestFindRepositoryV1)
 
2520
        self.assertHandlerEqual('BzrDir.find_repositoryV2',
 
2521
            smart_dir.SmartServerRequestFindRepositoryV2)
 
2522
        self.assertHandlerEqual('BzrDirFormat.initialize',
 
2523
            smart_dir.SmartServerRequestInitializeBzrDir)
 
2524
        self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
 
2525
            smart_dir.SmartServerRequestBzrDirInitializeEx)
 
2526
        self.assertHandlerEqual('BzrDir.checkout_metadir',
 
2527
            smart_dir.SmartServerBzrDirRequestCheckoutMetaDir)
 
2528
        self.assertHandlerEqual('BzrDir.cloning_metadir',
 
2529
            smart_dir.SmartServerBzrDirRequestCloningMetaDir)
 
2530
        self.assertHandlerEqual('BzrDir.get_branches',
 
2531
            smart_dir.SmartServerBzrDirRequestGetBranches)
 
2532
        self.assertHandlerEqual('BzrDir.get_config_file',
 
2533
            smart_dir.SmartServerBzrDirRequestConfigFile)
 
2534
        self.assertHandlerEqual('BzrDir.open_branch',
 
2535
            smart_dir.SmartServerRequestOpenBranch)
 
2536
        self.assertHandlerEqual('BzrDir.open_branchV2',
 
2537
            smart_dir.SmartServerRequestOpenBranchV2)
 
2538
        self.assertHandlerEqual('BzrDir.open_branchV3',
 
2539
            smart_dir.SmartServerRequestOpenBranchV3)
 
2540
        self.assertHandlerEqual('PackRepository.autopack',
 
2541
            smart_packrepo.SmartServerPackRepositoryAutopack)
 
2542
        self.assertHandlerEqual('Repository.add_signature_text',
 
2543
            smart_repo.SmartServerRepositoryAddSignatureText)
 
2544
        self.assertHandlerEqual('Repository.all_revision_ids',
 
2545
            smart_repo.SmartServerRepositoryAllRevisionIds)
 
2546
        self.assertHandlerEqual('Repository.break_lock',
 
2547
            smart_repo.SmartServerRepositoryBreakLock)
 
2548
        self.assertHandlerEqual('Repository.gather_stats',
 
2549
            smart_repo.SmartServerRepositoryGatherStats)
 
2550
        self.assertHandlerEqual('Repository.get_parent_map',
 
2551
            smart_repo.SmartServerRepositoryGetParentMap)
 
2552
        self.assertHandlerEqual('Repository.get_physical_lock_status',
 
2553
            smart_repo.SmartServerRepositoryGetPhysicalLockStatus)
 
2554
        self.assertHandlerEqual('Repository.get_rev_id_for_revno',
 
2555
            smart_repo.SmartServerRepositoryGetRevIdForRevno)
 
2556
        self.assertHandlerEqual('Repository.get_revision_graph',
 
2557
            smart_repo.SmartServerRepositoryGetRevisionGraph)
 
2558
        self.assertHandlerEqual('Repository.get_revision_signature_text',
 
2559
            smart_repo.SmartServerRepositoryGetRevisionSignatureText)
 
2560
        self.assertHandlerEqual('Repository.get_stream',
 
2561
            smart_repo.SmartServerRepositoryGetStream)
 
2562
        self.assertHandlerEqual('Repository.get_stream_1.19',
 
2563
            smart_repo.SmartServerRepositoryGetStream_1_19)
 
2564
        self.assertHandlerEqual('Repository.iter_revisions',
 
2565
            smart_repo.SmartServerRepositoryIterRevisions)
 
2566
        self.assertHandlerEqual('Repository.has_revision',
 
2567
            smart_repo.SmartServerRequestHasRevision)
 
2568
        self.assertHandlerEqual('Repository.insert_stream',
 
2569
            smart_repo.SmartServerRepositoryInsertStream)
 
2570
        self.assertHandlerEqual('Repository.insert_stream_locked',
 
2571
            smart_repo.SmartServerRepositoryInsertStreamLocked)
 
2572
        self.assertHandlerEqual('Repository.is_shared',
 
2573
            smart_repo.SmartServerRepositoryIsShared)
 
2574
        self.assertHandlerEqual('Repository.iter_files_bytes',
 
2575
            smart_repo.SmartServerRepositoryIterFilesBytes)
 
2576
        self.assertHandlerEqual('Repository.lock_write',
 
2577
            smart_repo.SmartServerRepositoryLockWrite)
 
2578
        self.assertHandlerEqual('Repository.make_working_trees',
 
2579
            smart_repo.SmartServerRepositoryMakeWorkingTrees)
 
2580
        self.assertHandlerEqual('Repository.pack',
 
2581
            smart_repo.SmartServerRepositoryPack)
 
2582
        self.assertHandlerEqual('Repository.reconcile',
 
2583
            smart_repo.SmartServerRepositoryReconcile)
 
2584
        self.assertHandlerEqual('Repository.tarball',
 
2585
            smart_repo.SmartServerRepositoryTarball)
 
2586
        self.assertHandlerEqual('Repository.unlock',
 
2587
            smart_repo.SmartServerRepositoryUnlock)
 
2588
        self.assertHandlerEqual('Repository.start_write_group',
 
2589
            smart_repo.SmartServerRepositoryStartWriteGroup)
 
2590
        self.assertHandlerEqual('Repository.check_write_group',
 
2591
            smart_repo.SmartServerRepositoryCheckWriteGroup)
 
2592
        self.assertHandlerEqual('Repository.commit_write_group',
 
2593
            smart_repo.SmartServerRepositoryCommitWriteGroup)
 
2594
        self.assertHandlerEqual('Repository.abort_write_group',
 
2595
            smart_repo.SmartServerRepositoryAbortWriteGroup)
 
2596
        self.assertHandlerEqual('VersionedFileRepository.get_serializer_format',
 
2597
            smart_repo.SmartServerRepositoryGetSerializerFormat)
 
2598
        self.assertHandlerEqual('VersionedFileRepository.get_inventories',
 
2599
            smart_repo.SmartServerRepositoryGetInventories)
 
2600
        self.assertHandlerEqual('Transport.is_readonly',
 
2601
            smart_req.SmartServerIsReadonly)
 
2602
 
 
2603
 
 
2604
class SmartTCPServerHookTests(tests.TestCaseWithMemoryTransport):
 
2605
    """Tests for SmartTCPServer hooks."""
 
2606
 
 
2607
    def setUp(self):
 
2608
        super(SmartTCPServerHookTests, self).setUp()
 
2609
        self.server = server.SmartTCPServer(self.get_transport())
 
2610
 
 
2611
    def test_run_server_started_hooks(self):
 
2612
        """Test the server started hooks get fired properly."""
 
2613
        started_calls = []
 
2614
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2615
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2616
            None)
 
2617
        started_ex_calls = []
 
2618
        server.SmartTCPServer.hooks.install_named_hook('server_started_ex',
 
2619
            lambda backing_urls, url: started_ex_calls.append((backing_urls, url)),
 
2620
            None)
 
2621
        self.server._sockname = ('example.com', 42)
 
2622
        self.server.run_server_started_hooks()
 
2623
        self.assertEquals(started_calls,
 
2624
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2625
        self.assertEquals(started_ex_calls,
 
2626
            [([self.get_transport().base], self.server)])
 
2627
 
 
2628
    def test_run_server_started_hooks_ipv6(self):
 
2629
        """Test that socknames can contain 4-tuples."""
 
2630
        self.server._sockname = ('::', 42, 0, 0)
 
2631
        started_calls = []
 
2632
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2633
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2634
            None)
 
2635
        self.server.run_server_started_hooks()
 
2636
        self.assertEquals(started_calls,
 
2637
                [([self.get_transport().base], 'bzr://:::42/')])
 
2638
 
 
2639
    def test_run_server_stopped_hooks(self):
 
2640
        """Test the server stopped hooks."""
 
2641
        self.server._sockname = ('example.com', 42)
 
2642
        stopped_calls = []
 
2643
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
 
2644
            lambda backing_urls, url: stopped_calls.append((backing_urls, url)),
 
2645
            None)
 
2646
        self.server.run_server_stopped_hooks()
 
2647
        self.assertEquals(stopped_calls,
 
2648
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2649
 
 
2650
 
 
2651
class TestSmartServerRepositoryPack(tests.TestCaseWithMemoryTransport):
 
2652
 
 
2653
    def test_pack(self):
 
2654
        backing = self.get_transport()
 
2655
        request = smart_repo.SmartServerRepositoryPack(backing)
 
2656
        tree = self.make_branch_and_memory_tree('.')
 
2657
        repo_token = tree.branch.repository.lock_write().repository_token
 
2658
 
 
2659
        self.assertIs(None, request.execute('', repo_token, False))
 
2660
 
 
2661
        self.assertEqual(
 
2662
            smart_req.SuccessfulSmartServerResponse(('ok', ), ),
 
2663
            request.do_body(''))
 
2664
 
 
2665
 
 
2666
class TestSmartServerRepositoryGetInventories(tests.TestCaseWithTransport):
 
2667
 
 
2668
    def _get_serialized_inventory_delta(self, repository, base_revid, revid):
 
2669
        base_inv = repository.revision_tree(base_revid).root_inventory
 
2670
        inv = repository.revision_tree(revid).root_inventory
 
2671
        inv_delta = inv._make_delta(base_inv)
 
2672
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
2673
        return "".join(serializer.delta_to_lines(base_revid, revid, inv_delta))
 
2674
 
 
2675
    def test_single(self):
 
2676
        backing = self.get_transport()
 
2677
        request = smart_repo.SmartServerRepositoryGetInventories(backing)
 
2678
        t = self.make_branch_and_tree('.', format='2a')
 
2679
        self.addCleanup(t.lock_write().unlock)
 
2680
        self.build_tree_contents([("file", "somecontents")])
 
2681
        t.add(["file"], ["thefileid"])
 
2682
        t.commit(rev_id='somerev', message="add file")
 
2683
        self.assertIs(None, request.execute('', 'unordered'))
 
2684
        response = request.do_body("somerev\n")
 
2685
        self.assertTrue(response.is_successful())
 
2686
        self.assertEquals(response.args, ("ok", ))
 
2687
        stream = [('inventory-deltas', [
 
2688
            versionedfile.FulltextContentFactory('somerev', None, None,
 
2689
                self._get_serialized_inventory_delta(
 
2690
                    t.branch.repository, 'null:', 'somerev'))])]
 
2691
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
2692
        self.assertEquals(
 
2693
            "".join(response.body_stream),
 
2694
            "".join(smart_repo._stream_to_byte_stream(stream, fmt)))
 
2695
 
 
2696
    def test_empty(self):
 
2697
        backing = self.get_transport()
 
2698
        request = smart_repo.SmartServerRepositoryGetInventories(backing)
 
2699
        t = self.make_branch_and_tree('.', format='2a')
 
2700
        self.addCleanup(t.lock_write().unlock)
 
2701
        self.build_tree_contents([("file", "somecontents")])
 
2702
        t.add(["file"], ["thefileid"])
 
2703
        t.commit(rev_id='somerev', message="add file")
 
2704
        self.assertIs(None, request.execute('', 'unordered'))
 
2705
        response = request.do_body("")
 
2706
        self.assertTrue(response.is_successful())
 
2707
        self.assertEquals(response.args, ("ok", ))
 
2708
        self.assertEquals("".join(response.body_stream),
 
2709
            "Bazaar pack format 1 (introduced in 0.18)\nB54\n\nBazaar repository format 2a (needs bzr 1.16 or later)\nE")