~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 04:10:52 UTC
  • mfrom: (6616.1.1 fix-en-user-guide)
  • Revision ID: pqm@pqm.ubuntu.com-20160421041052-clcye7ns1qcl2n7w
(richard-wilbur) Ensure build of English use guide always uses English text
 even when user's locale specifies a different language. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2012, 2016 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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests for the smart wire/domain protocol.
18
18
 
24
24
Tests for low-level protocol encoding are found in test_smart_transport.
25
25
"""
26
26
 
27
 
from StringIO import StringIO
28
 
import tempfile
29
 
import tarfile
30
 
 
31
 
from bzrlib import bzrdir, errors, pack, smart, tests
32
 
from bzrlib.smart.request import SmartServerResponse
33
 
import bzrlib.smart.bzrdir
34
 
import bzrlib.smart.branch
35
 
import bzrlib.smart.repository
36
 
from bzrlib.util import bencode
37
 
 
38
 
 
39
 
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
 
27
import bz2
 
28
import zlib
 
29
 
 
30
from bzrlib import (
 
31
    bencode,
 
32
    branch as _mod_branch,
 
33
    controldir,
 
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
        super(TestCaseWithChrootedTransport, self).setUp()
 
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):
40
100
 
41
101
    def setUp(self):
42
102
        super(TestCaseWithSmartMedium, self).setUp()
44
104
        # the default or a parameterized class, but rather use the
45
105
        # TestCaseWithTransport infrastructure to set up a smart server and
46
106
        # transport.
47
 
        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())
48
111
 
49
112
    def get_smart_medium(self):
50
113
        """Get a smart medium to use in tests."""
51
114
        return self.get_transport().get_smart_medium()
52
115
 
53
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 = controldir.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
 
54
136
class TestSmartServerResponse(tests.TestCase):
55
137
 
56
138
    def test__eq__(self):
57
 
        self.assertEqual(SmartServerResponse(('ok', )),
58
 
            SmartServerResponse(('ok', )))
59
 
        self.assertEqual(SmartServerResponse(('ok', ), 'body'),
60
 
            SmartServerResponse(('ok', ), 'body'))
61
 
        self.assertNotEqual(SmartServerResponse(('ok', )),
62
 
            SmartServerResponse(('notok', )))
63
 
        self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
64
 
            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', )))
65
147
        self.assertNotEqual(None,
66
 
            SmartServerResponse(('ok', )))
67
 
 
68
 
 
69
 
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 = controldir.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):
70
345
    """Tests for BzrDir.find_repository."""
71
346
 
72
347
    def test_no_repository(self):
73
348
        """When there is no repository to be found, ('norepository', ) is returned."""
74
349
        backing = self.get_transport()
75
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
350
        request = self._request_class(backing)
76
351
        self.make_bzrdir('.')
77
 
        self.assertEqual(SmartServerResponse(('norepository', )),
78
 
            request.execute(backing.local_abspath('')))
 
352
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
353
            request.execute(''))
79
354
 
80
355
    def test_nonshared_repository(self):
81
 
        # nonshared repositorys only allow 'find' to return a handle when the 
82
 
        # 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
83
358
        # the repository is at.
84
359
        backing = self.get_transport()
85
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
360
        request = self._request_class(backing)
86
361
        result = self._make_repository_and_result()
87
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
362
        self.assertEqual(result, request.execute(''))
88
363
        self.make_bzrdir('subdir')
89
 
        self.assertEqual(SmartServerResponse(('norepository', )),
90
 
            request.execute(backing.local_abspath('subdir')))
 
364
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
365
            request.execute('subdir'))
91
366
 
92
367
    def _make_repository_and_result(self, shared=False, format=None):
93
368
        """Convenience function to setup a repository.
103
378
            subtrees = 'yes'
104
379
        else:
105
380
            subtrees = 'no'
106
 
        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))
107
399
 
108
400
    def test_shared_repository(self):
109
401
        """When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
110
402
        backing = self.get_transport()
111
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
403
        request = self._request_class(backing)
112
404
        result = self._make_repository_and_result(shared=True)
113
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
405
        self.assertEqual(result, request.execute(''))
114
406
        self.make_bzrdir('subdir')
115
 
        result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
 
407
        result2 = smart_req.SmartServerResponse(
 
408
            result.args[0:1] + ('..', ) + result.args[2:])
116
409
        self.assertEqual(result2,
117
 
            request.execute(backing.local_abspath('subdir')))
 
410
            request.execute('subdir'))
118
411
        self.make_bzrdir('subdir/deeper')
119
 
        result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
 
412
        result3 = smart_req.SmartServerResponse(
 
413
            result.args[0:1] + ('../..', ) + result.args[2:])
120
414
        self.assertEqual(result3,
121
 
            request.execute(backing.local_abspath('subdir/deeper')))
 
415
            request.execute('subdir/deeper'))
122
416
 
123
417
    def test_rich_root_and_subtree_encoding(self):
124
418
        """Test for the format attributes for rich root and subtree support."""
125
419
        backing = self.get_transport()
126
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
127
 
        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='development-subtree')
128
423
        # check the test will be valid
129
424
        self.assertEqual('yes', result.args[2])
130
425
        self.assertEqual('yes', result.args[3])
131
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
132
 
 
133
 
 
134
 
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='development-subtree')
 
434
        # check the test will be valid
 
435
        self.assertEqual('yes', 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):
135
489
 
136
490
    def test_empty_dir(self):
137
491
        """Initializing an empty dir should succeed and do it."""
138
492
        backing = self.get_transport()
139
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
140
 
        self.assertEqual(SmartServerResponse(('ok', )),
141
 
            request.execute(backing.local_abspath('.')))
142
 
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
143
 
        # no branch, tree or repository is expected with the current 
 
493
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
 
494
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
495
            request.execute(''))
 
496
        made_dir = controldir.ControlDir.open_from_transport(backing)
 
497
        # no branch, tree or repository is expected with the current
144
498
        # default formart.
145
499
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
146
500
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
149
503
    def test_missing_dir(self):
150
504
        """Initializing a missing directory should fail like the bzrdir api."""
151
505
        backing = self.get_transport()
152
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
 
506
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
153
507
        self.assertRaises(errors.NoSuchFile,
154
 
            request.execute, backing.local_abspath('subdir'))
 
508
            request.execute, 'subdir')
155
509
 
156
510
    def test_initialized_dir(self):
157
511
        """Initializing an extant bzrdir should fail like the bzrdir api."""
158
512
        backing = self.get_transport()
159
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
160
 
        self.make_bzrdir('subdir')
161
 
        self.assertRaises(errors.FileExists,
162
 
            request.execute, backing.local_abspath('subdir'))
163
 
 
164
 
 
165
 
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 = controldir.ControlDir.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):
166
629
 
167
630
    def test_no_branch(self):
168
631
        """When there is no branch, ('nobranch', ) is returned."""
169
632
        backing = self.get_transport()
170
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
633
        request = smart_dir.SmartServerRequestOpenBranch(backing)
171
634
        self.make_bzrdir('.')
172
 
        self.assertEqual(SmartServerResponse(('nobranch', )),
173
 
            request.execute(backing.local_abspath('')))
 
635
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
636
            request.execute(''))
174
637
 
175
638
    def test_branch(self):
176
639
        """When there is a branch, 'ok' is returned."""
177
640
        backing = self.get_transport()
178
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
641
        request = smart_dir.SmartServerRequestOpenBranch(backing)
179
642
        self.make_branch('.')
180
 
        self.assertEqual(SmartServerResponse(('ok', '')),
181
 
            request.execute(backing.local_abspath('')))
182
 
 
183
 
    def test_branch_reference(self):
184
 
        """When there is a branch reference, the reference URL is returned."""
185
 
        backing = self.get_transport()
186
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
187
 
        branch = self.make_branch('branch')
188
 
        checkout = branch.create_checkout('reference',lightweight=True)
189
 
        # TODO: once we have an API to probe for references of any sort, we
190
 
        # can use it here.
191
 
        reference_url = backing.abspath('branch') + '/'
192
 
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
193
 
        self.assertEqual(SmartServerResponse(('ok', reference_url)),
194
 
            request.execute(backing.local_abspath('reference')))
195
 
 
196
 
 
197
 
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):
198
796
 
199
797
    def test_empty(self):
200
798
        """For an empty branch, the body is empty."""
201
799
        backing = self.get_transport()
202
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
800
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
203
801
        self.make_branch('.')
204
 
        self.assertEqual(SmartServerResponse(('ok', ), ''),
205
 
            request.execute(backing.local_abspath('')))
 
802
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), ''),
 
803
            request.execute(''))
206
804
 
207
805
    def test_not_empty(self):
208
806
        """For a non-empty branch, the body is empty."""
209
807
        backing = self.get_transport()
210
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
808
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
211
809
        tree = self.make_branch_and_memory_tree('.')
212
810
        tree.lock_write()
213
811
        tree.add('')
215
813
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
216
814
        tree.unlock()
217
815
        self.assertEqual(
218
 
            SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
219
 
            request.execute(backing.local_abspath('')))
220
 
 
221
 
 
222
 
class TestSmartServerBranchRequest(tests.TestCaseWithTransport):
 
816
            smart_req.SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
 
817
            request.execute(''))
 
818
 
 
819
 
 
820
class TestSmartServerBranchRequest(tests.TestCaseWithMemoryTransport):
223
821
 
224
822
    def test_no_branch(self):
225
823
        """When there is a bzrdir and no branch, NotBranchError is raised."""
226
824
        backing = self.get_transport()
227
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
825
        request = smart_branch.SmartServerBranchRequest(backing)
228
826
        self.make_bzrdir('.')
229
827
        self.assertRaises(errors.NotBranchError,
230
 
            request.execute, backing.local_abspath(''))
 
828
            request.execute, '')
231
829
 
232
830
    def test_branch_reference(self):
233
831
        """When there is a branch reference, NotBranchError is raised."""
234
832
        backing = self.get_transport()
235
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
833
        request = smart_branch.SmartServerBranchRequest(backing)
236
834
        branch = self.make_branch('branch')
237
835
        checkout = branch.create_checkout('reference',lightweight=True)
238
836
        self.assertRaises(errors.NotBranchError,
239
 
            request.execute, backing.local_abspath('checkout'))
240
 
 
241
 
 
242
 
class TestSmartServerBranchRequestLastRevisionInfo(tests.TestCaseWithTransport):
 
837
            request.execute, 'checkout')
 
838
 
 
839
 
 
840
class TestSmartServerBranchRequestLastRevisionInfo(
 
841
    tests.TestCaseWithMemoryTransport):
243
842
 
244
843
    def test_empty(self):
245
844
        """For an empty branch, the result is ('ok', '0', 'null:')."""
246
845
        backing = self.get_transport()
247
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
846
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
248
847
        self.make_branch('.')
249
 
        self.assertEqual(SmartServerResponse(('ok', '0', 'null:')),
250
 
            request.execute(backing.local_abspath('')))
 
848
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0', 'null:')),
 
849
            request.execute(''))
251
850
 
252
851
    def test_not_empty(self):
253
852
        """For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
254
853
        backing = self.get_transport()
255
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
854
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
256
855
        tree = self.make_branch_and_memory_tree('.')
257
856
        tree.lock_write()
258
857
        tree.add('')
261
860
        r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
262
861
        tree.unlock()
263
862
        self.assertEqual(
264
 
            SmartServerResponse(('ok', '2', rev_id_utf8)),
265
 
            request.execute(backing.local_abspath('')))
266
 
 
267
 
 
268
 
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):
269
904
 
270
905
    def test_default(self):
271
906
        """With no file, we get empty content."""
272
907
        backing = self.get_transport()
273
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
 
908
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
274
909
        branch = self.make_branch('.')
275
910
        # there should be no file by default
276
911
        content = ''
277
 
        self.assertEqual(SmartServerResponse(('ok', ), content),
278
 
            request.execute(backing.local_abspath('')))
 
912
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), content),
 
913
            request.execute(''))
279
914
 
280
915
    def test_with_content(self):
281
916
        # SmartServerBranchGetConfigFile should return the content from
282
917
        # branch.control_files.get('branch.conf') for now - in the future it may
283
 
        # perform more complex processing. 
284
 
        backing = self.get_transport()
285
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
286
 
        branch = self.make_branch('.')
287
 
        branch.control_files.put_utf8('branch.conf', 'foo bar baz')
288
 
        self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
289
 
            request.execute(backing.local_abspath('')))
290
 
 
291
 
 
292
 
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
293
 
 
294
 
    def test_empty(self):
295
 
        backing = self.get_transport()
296
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
297
 
        b = self.make_branch('.')
298
 
        branch_token = b.lock_write()
299
 
        repo_token = b.repository.lock_write()
300
 
        b.repository.unlock()
301
 
        try:
302
 
            self.assertEqual(SmartServerResponse(('ok',)),
303
 
                request.execute(
304
 
                    backing.local_abspath(''), branch_token, repo_token,
305
 
                    'null:'))
306
 
        finally:
307
 
            b.unlock()
308
 
 
309
 
    def test_not_present_revision_id(self):
310
 
        backing = self.get_transport()
311
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
312
 
        b = self.make_branch('.')
313
 
        branch_token = b.lock_write()
314
 
        repo_token = b.repository.lock_write()
315
 
        b.repository.unlock()
316
 
        try:
317
 
            revision_id = 'non-existent revision'
318
 
            self.assertEqual(
319
 
                SmartServerResponse(('NoSuchRevision', revision_id)),
320
 
                request.execute(
321
 
                    backing.local_abspath(''), branch_token, repo_token,
322
 
                    revision_id))
323
 
        finally:
324
 
            b.unlock()
325
 
 
326
 
    def test_revision_id_present(self):
327
 
        backing = self.get_transport()
328
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
329
 
        tree = self.make_branch_and_memory_tree('.')
330
 
        tree.lock_write()
331
 
        tree.add('')
332
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
333
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
334
 
        r2 = tree.commit('2nd commit')
335
 
        tree.unlock()
336
 
        branch_token = tree.branch.lock_write()
337
 
        repo_token = tree.branch.repository.lock_write()
338
 
        tree.branch.repository.unlock()
339
 
        try:
340
 
            self.assertEqual(
341
 
                SmartServerResponse(('ok',)),
342
 
                request.execute(
343
 
                    backing.local_abspath(''), branch_token, repo_token,
344
 
                    rev_id_utf8))
345
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
346
 
        finally:
347
 
            tree.branch.unlock()
348
 
 
349
 
    def test_revision_id_present2(self):
350
 
        backing = self.get_transport()
351
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
352
 
        tree = self.make_branch_and_memory_tree('.')
353
 
        tree.lock_write()
354
 
        tree.add('')
355
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
356
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
357
 
        r2 = tree.commit('2nd commit')
358
 
        tree.unlock()
359
 
        tree.branch.set_revision_history([])
360
 
        branch_token = tree.branch.lock_write()
361
 
        repo_token = tree.branch.repository.lock_write()
362
 
        tree.branch.repository.unlock()
363
 
        try:
364
 
            self.assertEqual(
365
 
                SmartServerResponse(('ok',)),
366
 
                request.execute(
367
 
                    backing.local_abspath(''), branch_token, repo_token,
368
 
                    rev_id_utf8))
369
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
370
 
        finally:
371
 
            tree.branch.unlock()
372
 
 
373
 
 
374
 
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
375
 
 
376
 
    def setUp(self):
377
 
        tests.TestCaseWithTransport.setUp(self)
378
 
        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.assertEqual(
 
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.assertEqual(
 
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
        super(SetLastRevisionTestBase, self).setUp()
 
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.assertEqual(
 
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.assertEqual(
 
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
        # Refresh branch as SetParentLocation modified it
 
1327
        branch = branch.bzrdir.open_branch()
 
1328
        self.assertEqual(None, branch.get_parent())
 
1329
 
 
1330
    def test_set_parent_something(self):
 
1331
        branch = self.make_branch('base', format="1.9")
 
1332
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1333
            self.get_transport())
 
1334
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1335
        try:
 
1336
            response = request.execute('base', branch_token, repo_token,
 
1337
                                       'http://bar/')
 
1338
        finally:
 
1339
            branch.unlock()
 
1340
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1341
        refreshed = _mod_branch.Branch.open(branch.base)
 
1342
        self.assertEqual('http://bar/', refreshed.get_parent())
 
1343
 
 
1344
 
 
1345
class TestSmartServerBranchRequestGetTagsBytes(
 
1346
    tests.TestCaseWithMemoryTransport):
 
1347
    # Only called when the branch format and tags match [yay factory
 
1348
    # methods] so only need to test straight forward cases.
 
1349
 
 
1350
    def test_get_bytes(self):
 
1351
        base_branch = self.make_branch('base')
 
1352
        request = smart_branch.SmartServerBranchGetTagsBytes(
 
1353
            self.get_transport())
 
1354
        response = request.execute('base')
 
1355
        self.assertEqual(
 
1356
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1357
 
 
1358
 
 
1359
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
 
1360
 
 
1361
    def test_get_stacked_on_url(self):
 
1362
        base_branch = self.make_branch('base', format='1.6')
 
1363
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1364
        # typically should be relative
 
1365
        stacked_branch.set_stacked_on_url('../base')
 
1366
        request = smart_branch.SmartServerBranchRequestGetStackedOnURL(
 
1367
            self.get_transport())
 
1368
        response = request.execute('stacked')
 
1369
        self.assertEqual(
 
1370
            smart_req.SmartServerResponse(('ok', '../base')),
 
1371
            response)
 
1372
 
 
1373
 
 
1374
class TestSmartServerBranchRequestLockWrite(TestLockedBranch):
379
1375
 
380
1376
    def test_lock_write_on_unlocked_branch(self):
381
1377
        backing = self.get_transport()
382
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1378
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
383
1379
        branch = self.make_branch('.', format='knit')
384
1380
        repository = branch.repository
385
 
        response = request.execute(backing.local_abspath(''))
 
1381
        response = request.execute('')
386
1382
        branch_nonce = branch.control_files._lock.peek().get('nonce')
387
1383
        repository_nonce = repository.control_files._lock.peek().get('nonce')
388
 
        self.assertEqual(
389
 
            SmartServerResponse(('ok', branch_nonce, repository_nonce)),
390
 
            response)
 
1384
        self.assertEqual(smart_req.SmartServerResponse(
 
1385
                ('ok', branch_nonce, repository_nonce)),
 
1386
                         response)
391
1387
        # The branch (and associated repository) is now locked.  Verify that
392
1388
        # with a new branch object.
393
1389
        new_branch = repository.bzrdir.open_branch()
394
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)
395
1394
 
396
1395
    def test_lock_write_on_locked_branch(self):
397
1396
        backing = self.get_transport()
398
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1397
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
399
1398
        branch = self.make_branch('.')
400
 
        branch.lock_write()
 
1399
        branch_token = branch.lock_write().branch_token
401
1400
        branch.leave_lock_in_place()
402
1401
        branch.unlock()
403
 
        response = request.execute(backing.local_abspath(''))
 
1402
        response = request.execute('')
404
1403
        self.assertEqual(
405
 
            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()
406
1409
 
407
1410
    def test_lock_write_with_tokens_on_locked_branch(self):
408
1411
        backing = self.get_transport()
409
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1412
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
410
1413
        branch = self.make_branch('.', format='knit')
411
 
        branch_token = branch.lock_write()
412
 
        repo_token = branch.repository.lock_write()
413
 
        branch.repository.unlock()
 
1414
        branch_token, repo_token = self.get_lock_tokens(branch)
414
1415
        branch.leave_lock_in_place()
415
1416
        branch.repository.leave_lock_in_place()
416
1417
        branch.unlock()
417
 
        response = request.execute(backing.local_abspath(''),
 
1418
        response = request.execute('',
418
1419
                                   branch_token, repo_token)
419
1420
        self.assertEqual(
420
 
            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()
421
1430
 
422
1431
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
423
1432
        backing = self.get_transport()
424
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1433
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
425
1434
        branch = self.make_branch('.', format='knit')
426
 
        branch_token = branch.lock_write()
427
 
        repo_token = branch.repository.lock_write()
428
 
        branch.repository.unlock()
 
1435
        branch_token, repo_token = self.get_lock_tokens(branch)
429
1436
        branch.leave_lock_in_place()
430
1437
        branch.repository.leave_lock_in_place()
431
1438
        branch.unlock()
432
 
        response = request.execute(backing.local_abspath(''),
 
1439
        response = request.execute('',
433
1440
                                   branch_token+'xxx', repo_token)
434
1441
        self.assertEqual(
435
 
            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()
436
1450
 
437
1451
    def test_lock_write_on_locked_repo(self):
438
1452
        backing = self.get_transport()
439
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1453
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
440
1454
        branch = self.make_branch('.', format='knit')
441
 
        branch.repository.lock_write()
442
 
        branch.repository.leave_lock_in_place()
443
 
        branch.repository.unlock()
444
 
        response = request.execute(backing.local_abspath(''))
 
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('')
445
1460
        self.assertEqual(
446
 
            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()
447
1466
 
448
1467
    def test_lock_write_on_readonly_transport(self):
449
1468
        backing = self.get_readonly_transport()
450
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1469
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
451
1470
        branch = self.make_branch('.')
452
 
        response = request.execute('')
 
1471
        root = self.get_transport().clone('/')
 
1472
        path = urlutils.relative_url(root.base, self.get_transport().base)
 
1473
        response = request.execute(path)
453
1474
        error_name, lock_str, why_str = response.args
454
1475
        self.assertFalse(response.is_successful())
455
1476
        self.assertEqual('LockFailed', error_name)
456
1477
 
457
1478
 
458
 
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
459
 
 
460
 
    def setUp(self):
461
 
        tests.TestCaseWithTransport.setUp(self)
462
 
        self.reduceLockdirTimeout()
 
1479
class TestSmartServerBranchRequestGetPhysicalLockStatus(TestLockedBranch):
 
1480
 
 
1481
    def test_true(self):
 
1482
        backing = self.get_transport()
 
1483
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1484
            backing)
 
1485
        branch = self.make_branch('.')
 
1486
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1487
        self.assertEqual(True, branch.get_physical_lock_status())
 
1488
        response = request.execute('')
 
1489
        self.assertEqual(
 
1490
            smart_req.SmartServerResponse(('yes',)), response)
 
1491
        branch.unlock()
 
1492
 
 
1493
    def test_false(self):
 
1494
        backing = self.get_transport()
 
1495
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1496
            backing)
 
1497
        branch = self.make_branch('.')
 
1498
        self.assertEqual(False, branch.get_physical_lock_status())
 
1499
        response = request.execute('')
 
1500
        self.assertEqual(
 
1501
            smart_req.SmartServerResponse(('no',)), response)
 
1502
 
 
1503
 
 
1504
class TestSmartServerBranchRequestUnlock(TestLockedBranch):
463
1505
 
464
1506
    def test_unlock_on_locked_branch_and_repo(self):
465
1507
        backing = self.get_transport()
466
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
 
1508
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
467
1509
        branch = self.make_branch('.', format='knit')
468
1510
        # Lock the branch
469
 
        branch_token = branch.lock_write()
470
 
        repo_token = branch.repository.lock_write()
471
 
        branch.repository.unlock()
 
1511
        branch_token, repo_token = self.get_lock_tokens(branch)
472
1512
        # Unlock the branch (and repo) object, leaving the physical locks
473
1513
        # in place.
474
1514
        branch.leave_lock_in_place()
475
1515
        branch.repository.leave_lock_in_place()
476
1516
        branch.unlock()
477
 
        response = request.execute(backing.local_abspath(''),
 
1517
        response = request.execute('',
478
1518
                                   branch_token, repo_token)
479
1519
        self.assertEqual(
480
 
            SmartServerResponse(('ok',)), response)
 
1520
            smart_req.SmartServerResponse(('ok',)), response)
481
1521
        # The branch is now unlocked.  Verify that with a new branch
482
1522
        # object.
483
1523
        new_branch = branch.bzrdir.open_branch()
486
1526
 
487
1527
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
488
1528
        backing = self.get_transport()
489
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
 
1529
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
490
1530
        branch = self.make_branch('.', format='knit')
491
1531
        response = request.execute(
492
 
            backing.local_abspath(''), 'branch token', 'repo token')
 
1532
            '', 'branch token', 'repo token')
493
1533
        self.assertEqual(
494
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1534
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
495
1535
 
496
1536
    def test_unlock_on_unlocked_branch_locked_repo(self):
497
1537
        backing = self.get_transport()
498
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
 
1538
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
499
1539
        branch = self.make_branch('.', format='knit')
500
1540
        # Lock the repository.
501
 
        repo_token = branch.repository.lock_write()
 
1541
        repo_token = branch.repository.lock_write().repository_token
502
1542
        branch.repository.leave_lock_in_place()
503
1543
        branch.repository.unlock()
504
1544
        # Issue branch lock_write request on the unlocked branch (with locked
505
1545
        # repo).
506
 
        response = request.execute(
507
 
            backing.local_abspath(''), 'branch token', repo_token)
 
1546
        response = request.execute('', 'branch token', repo_token)
508
1547
        self.assertEqual(
509
 
            SmartServerResponse(('TokenMismatch',)), response)
510
 
 
511
 
 
512
 
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
 
1548
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1549
        # Cleanup
 
1550
        branch.repository.lock_write(repo_token)
 
1551
        branch.repository.dont_leave_lock_in_place()
 
1552
        branch.repository.unlock()
 
1553
 
 
1554
 
 
1555
class TestSmartServerRepositoryRequest(tests.TestCaseWithMemoryTransport):
513
1556
 
514
1557
    def test_no_repository(self):
515
1558
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
518
1561
        # its the exact path being looked at and the server is not
519
1562
        # searching.
520
1563
        backing = self.get_transport()
521
 
        request = smart.repository.SmartServerRepositoryRequest(backing)
 
1564
        request = smart_repo.SmartServerRepositoryRequest(backing)
522
1565
        self.make_repository('.', shared=True)
523
1566
        self.make_bzrdir('subdir')
524
1567
        self.assertRaises(errors.NoRepositoryPresent,
525
 
            request.execute, backing.local_abspath('subdir'))
526
 
 
527
 
 
528
 
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
 
1568
            request.execute, 'subdir')
 
1569
 
 
1570
 
 
1571
class TestSmartServerRepositoryAddSignatureText(tests.TestCaseWithMemoryTransport):
 
1572
 
 
1573
    def test_add_text(self):
 
1574
        backing = self.get_transport()
 
1575
        request = smart_repo.SmartServerRepositoryAddSignatureText(backing)
 
1576
        tree = self.make_branch_and_memory_tree('.')
 
1577
        write_token = tree.lock_write()
 
1578
        self.addCleanup(tree.unlock)
 
1579
        tree.add('')
 
1580
        tree.commit("Message", rev_id='rev1')
 
1581
        tree.branch.repository.start_write_group()
 
1582
        write_group_tokens = tree.branch.repository.suspend_write_group()
 
1583
        self.assertEqual(None, request.execute('', write_token,
 
1584
            'rev1', *write_group_tokens))
 
1585
        response = request.do_body('somesignature')
 
1586
        self.assertTrue(response.is_successful())
 
1587
        self.assertEqual(response.args[0], 'ok')
 
1588
        write_group_tokens = response.args[1:]
 
1589
        tree.branch.repository.resume_write_group(write_group_tokens)
 
1590
        tree.branch.repository.commit_write_group()
 
1591
        tree.unlock()
 
1592
        self.assertEqual("somesignature",
 
1593
            tree.branch.repository.get_signature_text("rev1"))
 
1594
 
 
1595
 
 
1596
class TestSmartServerRepositoryAllRevisionIds(
 
1597
    tests.TestCaseWithMemoryTransport):
 
1598
 
 
1599
    def test_empty(self):
 
1600
        """An empty body should be returned for an empty repository."""
 
1601
        backing = self.get_transport()
 
1602
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1603
        self.make_repository('.')
 
1604
        self.assertEqual(
 
1605
            smart_req.SuccessfulSmartServerResponse(("ok", ), ""),
 
1606
            request.execute(''))
 
1607
 
 
1608
    def test_some_revisions(self):
 
1609
        """An empty body should be returned for an empty repository."""
 
1610
        backing = self.get_transport()
 
1611
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1612
        tree = self.make_branch_and_memory_tree('.')
 
1613
        tree.lock_write()
 
1614
        tree.add('')
 
1615
        tree.commit(rev_id='origineel', message="message")
 
1616
        tree.commit(rev_id='nog-een-revisie', message="message")
 
1617
        tree.unlock()
 
1618
        self.assertEqual(
 
1619
            smart_req.SuccessfulSmartServerResponse(("ok", ),
 
1620
                "origineel\nnog-een-revisie"),
 
1621
            request.execute(''))
 
1622
 
 
1623
 
 
1624
class TestSmartServerRepositoryBreakLock(tests.TestCaseWithMemoryTransport):
 
1625
 
 
1626
    def test_lock_to_break(self):
 
1627
        backing = self.get_transport()
 
1628
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1629
        tree = self.make_branch_and_memory_tree('.')
 
1630
        tree.branch.repository.lock_write()
 
1631
        self.assertEqual(
 
1632
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1633
            request.execute(''))
 
1634
 
 
1635
    def test_nothing_to_break(self):
 
1636
        backing = self.get_transport()
 
1637
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1638
        tree = self.make_branch_and_memory_tree('.')
 
1639
        self.assertEqual(
 
1640
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1641
            request.execute(''))
 
1642
 
 
1643
 
 
1644
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithMemoryTransport):
 
1645
 
 
1646
    def test_trivial_bzipped(self):
 
1647
        # This tests that the wire encoding is actually bzipped
 
1648
        backing = self.get_transport()
 
1649
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1650
        tree = self.make_branch_and_memory_tree('.')
 
1651
 
 
1652
        self.assertEqual(None,
 
1653
            request.execute('', 'missing-id'))
 
1654
        # Note that it returns a body that is bzipped.
 
1655
        self.assertEqual(
 
1656
            smart_req.SuccessfulSmartServerResponse(('ok', ), bz2.compress('')),
 
1657
            request.do_body('\n\n0\n'))
 
1658
 
 
1659
    def test_trivial_include_missing(self):
 
1660
        backing = self.get_transport()
 
1661
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1662
        tree = self.make_branch_and_memory_tree('.')
 
1663
 
 
1664
        self.assertEqual(None,
 
1665
            request.execute('', 'missing-id', 'include-missing:'))
 
1666
        self.assertEqual(
 
1667
            smart_req.SuccessfulSmartServerResponse(('ok', ),
 
1668
                bz2.compress('missing:missing-id')),
 
1669
            request.do_body('\n\n0\n'))
 
1670
 
 
1671
 
 
1672
class TestSmartServerRepositoryGetRevisionGraph(
 
1673
    tests.TestCaseWithMemoryTransport):
529
1674
 
530
1675
    def test_none_argument(self):
531
1676
        backing = self.get_transport()
532
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1677
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
533
1678
        tree = self.make_branch_and_memory_tree('.')
534
1679
        tree.lock_write()
535
1680
        tree.add('')
540
1685
        # the lines of revision_id->revision_parent_list has no guaranteed
541
1686
        # order coming out of a dict, so sort both our test and response
542
1687
        lines = sorted([' '.join([r2, r1]), r1])
543
 
        response = request.execute(backing.local_abspath(''), '')
 
1688
        response = request.execute('', '')
544
1689
        response.body = '\n'.join(sorted(response.body.split('\n')))
545
1690
 
546
1691
        self.assertEqual(
547
 
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
 
1692
            smart_req.SmartServerResponse(('ok', ), '\n'.join(lines)), response)
548
1693
 
549
1694
    def test_specific_revision_argument(self):
550
1695
        backing = self.get_transport()
551
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1696
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
552
1697
        tree = self.make_branch_and_memory_tree('.')
553
1698
        tree.lock_write()
554
1699
        tree.add('')
557
1702
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
558
1703
        tree.unlock()
559
1704
 
560
 
        self.assertEqual(SmartServerResponse(('ok', ), rev_id_utf8),
561
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
562
 
    
 
1705
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), rev_id_utf8),
 
1706
            request.execute('', rev_id_utf8))
 
1707
 
563
1708
    def test_no_such_revision(self):
564
1709
        backing = self.get_transport()
565
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1710
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
566
1711
        tree = self.make_branch_and_memory_tree('.')
567
1712
        tree.lock_write()
568
1713
        tree.add('')
570
1715
        tree.unlock()
571
1716
 
572
1717
        # Note that it still returns body (of zero bytes).
573
 
        self.assertEqual(
574
 
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
575
 
            request.execute(backing.local_abspath(''), 'missingrevision'))
576
 
 
577
 
 
578
 
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
 
1718
        self.assertEqual(smart_req.SmartServerResponse(
 
1719
                ('nosuchrevision', 'missingrevision', ), ''),
 
1720
                         request.execute('', 'missingrevision'))
 
1721
 
 
1722
 
 
1723
class TestSmartServerRepositoryGetRevIdForRevno(
 
1724
    tests.TestCaseWithMemoryTransport):
 
1725
 
 
1726
    def test_revno_found(self):
 
1727
        backing = self.get_transport()
 
1728
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1729
        tree = self.make_branch_and_memory_tree('.')
 
1730
        tree.lock_write()
 
1731
        tree.add('')
 
1732
        rev1_id_utf8 = u'\xc8'.encode('utf-8')
 
1733
        rev2_id_utf8 = u'\xc9'.encode('utf-8')
 
1734
        tree.commit('1st commit', rev_id=rev1_id_utf8)
 
1735
        tree.commit('2nd commit', rev_id=rev2_id_utf8)
 
1736
        tree.unlock()
 
1737
 
 
1738
        self.assertEqual(smart_req.SmartServerResponse(('ok', rev1_id_utf8)),
 
1739
            request.execute('', 1, (2, rev2_id_utf8)))
 
1740
 
 
1741
    def test_known_revid_missing(self):
 
1742
        backing = self.get_transport()
 
1743
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1744
        repo = self.make_repository('.')
 
1745
        self.assertEqual(
 
1746
            smart_req.FailedSmartServerResponse(('nosuchrevision', 'ghost')),
 
1747
            request.execute('', 1, (2, 'ghost')))
 
1748
 
 
1749
    def test_history_incomplete(self):
 
1750
        backing = self.get_transport()
 
1751
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1752
        parent = self.make_branch_and_memory_tree('parent', format='1.9')
 
1753
        parent.lock_write()
 
1754
        parent.add([''], ['TREE_ROOT'])
 
1755
        r1 = parent.commit(message='first commit')
 
1756
        r2 = parent.commit(message='second commit')
 
1757
        parent.unlock()
 
1758
        local = self.make_branch_and_memory_tree('local', format='1.9')
 
1759
        local.branch.pull(parent.branch)
 
1760
        local.set_parent_ids([r2])
 
1761
        r3 = local.commit(message='local commit')
 
1762
        local.branch.create_clone_on_transport(
 
1763
            self.get_transport('stacked'), stacked_on=self.get_url('parent'))
 
1764
        self.assertEqual(
 
1765
            smart_req.SmartServerResponse(('history-incomplete', 2, r2)),
 
1766
            request.execute('stacked', 1, (3, r3)))
 
1767
 
 
1768
 
 
1769
class TestSmartServerRepositoryIterRevisions(
 
1770
    tests.TestCaseWithMemoryTransport):
 
1771
 
 
1772
    def test_basic(self):
 
1773
        backing = self.get_transport()
 
1774
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1775
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1776
        tree.lock_write()
 
1777
        tree.add('')
 
1778
        tree.commit('1st commit', rev_id="rev1")
 
1779
        tree.commit('2nd commit', rev_id="rev2")
 
1780
        tree.unlock()
 
1781
 
 
1782
        self.assertIs(None, request.execute(''))
 
1783
        response = request.do_body("rev1\nrev2")
 
1784
        self.assertTrue(response.is_successful())
 
1785
        # Format 2a uses serializer format 10
 
1786
        self.assertEqual(response.args, ("ok", "10"))
 
1787
 
 
1788
        self.addCleanup(tree.branch.lock_read().unlock)
 
1789
        entries = [zlib.compress(record.get_bytes_as("fulltext")) for record in
 
1790
            tree.branch.repository.revisions.get_record_stream(
 
1791
            [("rev1", ), ("rev2", )], "unordered", True)]
 
1792
 
 
1793
        contents = "".join(response.body_stream)
 
1794
        self.assertTrue(contents in (
 
1795
            "".join([entries[0], entries[1]]),
 
1796
            "".join([entries[1], entries[0]])))
 
1797
 
 
1798
    def test_missing(self):
 
1799
        backing = self.get_transport()
 
1800
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1801
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1802
 
 
1803
        self.assertIs(None, request.execute(''))
 
1804
        response = request.do_body("rev1\nrev2")
 
1805
        self.assertTrue(response.is_successful())
 
1806
        # Format 2a uses serializer format 10
 
1807
        self.assertEqual(response.args, ("ok", "10"))
 
1808
 
 
1809
        contents = "".join(response.body_stream)
 
1810
        self.assertEqual(contents, "")
 
1811
 
 
1812
 
 
1813
class GetStreamTestBase(tests.TestCaseWithMemoryTransport):
 
1814
 
 
1815
    def make_two_commit_repo(self):
 
1816
        tree = self.make_branch_and_memory_tree('.')
 
1817
        tree.lock_write()
 
1818
        tree.add('')
 
1819
        r1 = tree.commit('1st commit')
 
1820
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
 
1821
        tree.unlock()
 
1822
        repo = tree.branch.repository
 
1823
        return repo, r1, r2
 
1824
 
 
1825
 
 
1826
class TestSmartServerRepositoryGetStream(GetStreamTestBase):
 
1827
 
 
1828
    def test_ancestry_of(self):
 
1829
        """The search argument may be a 'ancestry-of' some heads'."""
 
1830
        backing = self.get_transport()
 
1831
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1832
        repo, r1, r2 = self.make_two_commit_repo()
 
1833
        fetch_spec = ['ancestry-of', r2]
 
1834
        lines = '\n'.join(fetch_spec)
 
1835
        request.execute('', repo._format.network_name())
 
1836
        response = request.do_body(lines)
 
1837
        self.assertEqual(('ok',), response.args)
 
1838
        stream_bytes = ''.join(response.body_stream)
 
1839
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1840
 
 
1841
    def test_search(self):
 
1842
        """The search argument may be a 'search' of some explicit keys."""
 
1843
        backing = self.get_transport()
 
1844
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1845
        repo, r1, r2 = self.make_two_commit_repo()
 
1846
        fetch_spec = ['search', '%s %s' % (r1, r2), 'null:', '2']
 
1847
        lines = '\n'.join(fetch_spec)
 
1848
        request.execute('', repo._format.network_name())
 
1849
        response = request.do_body(lines)
 
1850
        self.assertEqual(('ok',), response.args)
 
1851
        stream_bytes = ''.join(response.body_stream)
 
1852
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1853
 
 
1854
    def test_search_everything(self):
 
1855
        """A search of 'everything' returns a stream."""
 
1856
        backing = self.get_transport()
 
1857
        request = smart_repo.SmartServerRepositoryGetStream_1_19(backing)
 
1858
        repo, r1, r2 = self.make_two_commit_repo()
 
1859
        serialised_fetch_spec = 'everything'
 
1860
        request.execute('', repo._format.network_name())
 
1861
        response = request.do_body(serialised_fetch_spec)
 
1862
        self.assertEqual(('ok',), response.args)
 
1863
        stream_bytes = ''.join(response.body_stream)
 
1864
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1865
 
 
1866
 
 
1867
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
579
1868
 
580
1869
    def test_missing_revision(self):
581
1870
        """For a missing revision, ('no', ) is returned."""
582
1871
        backing = self.get_transport()
583
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1872
        request = smart_repo.SmartServerRequestHasRevision(backing)
584
1873
        self.make_repository('.')
585
 
        self.assertEqual(SmartServerResponse(('no', )),
586
 
            request.execute(backing.local_abspath(''), 'revid'))
 
1874
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1875
            request.execute('', 'revid'))
587
1876
 
588
1877
    def test_present_revision(self):
589
1878
        """For a present revision, ('yes', ) is returned."""
590
1879
        backing = self.get_transport()
591
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1880
        request = smart_repo.SmartServerRequestHasRevision(backing)
592
1881
        tree = self.make_branch_and_memory_tree('.')
593
1882
        tree.lock_write()
594
1883
        tree.add('')
596
1885
        r1 = tree.commit('a commit', rev_id=rev_id_utf8)
597
1886
        tree.unlock()
598
1887
        self.assertTrue(tree.branch.repository.has_revision(rev_id_utf8))
599
 
        self.assertEqual(SmartServerResponse(('yes', )),
600
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
601
 
 
602
 
 
603
 
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
 
1888
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1889
            request.execute('', rev_id_utf8))
 
1890
 
 
1891
 
 
1892
class TestSmartServerRepositoryIterFilesBytes(tests.TestCaseWithTransport):
 
1893
 
 
1894
    def test_single(self):
 
1895
        backing = self.get_transport()
 
1896
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1897
        t = self.make_branch_and_tree('.')
 
1898
        self.addCleanup(t.lock_write().unlock)
 
1899
        self.build_tree_contents([("file", "somecontents")])
 
1900
        t.add(["file"], ["thefileid"])
 
1901
        t.commit(rev_id='somerev', message="add file")
 
1902
        self.assertIs(None, request.execute(''))
 
1903
        response = request.do_body("thefileid\0somerev\n")
 
1904
        self.assertTrue(response.is_successful())
 
1905
        self.assertEqual(response.args, ("ok", ))
 
1906
        self.assertEqual("".join(response.body_stream),
 
1907
            "ok\x000\n" + zlib.compress("somecontents"))
 
1908
 
 
1909
    def test_missing(self):
 
1910
        backing = self.get_transport()
 
1911
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1912
        t = self.make_branch_and_tree('.')
 
1913
        self.addCleanup(t.lock_write().unlock)
 
1914
        self.assertIs(None, request.execute(''))
 
1915
        response = request.do_body("thefileid\0revision\n")
 
1916
        self.assertTrue(response.is_successful())
 
1917
        self.assertEqual(response.args, ("ok", ))
 
1918
        self.assertEqual("".join(response.body_stream),
 
1919
            "absent\x00thefileid\x00revision\x000\n")
 
1920
 
 
1921
 
 
1922
class TestSmartServerRequestHasSignatureForRevisionId(
 
1923
        tests.TestCaseWithMemoryTransport):
 
1924
 
 
1925
    def test_missing_revision(self):
 
1926
        """For a missing revision, NoSuchRevision is returned."""
 
1927
        backing = self.get_transport()
 
1928
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1929
            backing)
 
1930
        self.make_repository('.')
 
1931
        self.assertEqual(
 
1932
            smart_req.FailedSmartServerResponse(
 
1933
                ('nosuchrevision', 'revid'), None),
 
1934
            request.execute('', 'revid'))
 
1935
 
 
1936
    def test_missing_signature(self):
 
1937
        """For a missing signature, ('no', ) is returned."""
 
1938
        backing = self.get_transport()
 
1939
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1940
            backing)
 
1941
        tree = self.make_branch_and_memory_tree('.')
 
1942
        tree.lock_write()
 
1943
        tree.add('')
 
1944
        r1 = tree.commit('a commit', rev_id='A')
 
1945
        tree.unlock()
 
1946
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1947
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1948
            request.execute('', 'A'))
 
1949
 
 
1950
    def test_present_signature(self):
 
1951
        """For a present signature, ('yes', ) is returned."""
 
1952
        backing = self.get_transport()
 
1953
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1954
            backing)
 
1955
        strategy = gpg.LoopbackGPGStrategy(None)
 
1956
        tree = self.make_branch_and_memory_tree('.')
 
1957
        tree.lock_write()
 
1958
        tree.add('')
 
1959
        r1 = tree.commit('a commit', rev_id='A')
 
1960
        tree.branch.repository.start_write_group()
 
1961
        tree.branch.repository.sign_revision('A', strategy)
 
1962
        tree.branch.repository.commit_write_group()
 
1963
        tree.unlock()
 
1964
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1965
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1966
            request.execute('', 'A'))
 
1967
 
 
1968
 
 
1969
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithMemoryTransport):
604
1970
 
605
1971
    def test_empty_revid(self):
606
1972
        """With an empty revid, we get only size an number and revisions"""
607
1973
        backing = self.get_transport()
608
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1974
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
609
1975
        repository = self.make_repository('.')
610
1976
        stats = repository.gather_stats()
611
 
        size = stats['size']
612
 
        expected_body = 'revisions: 0\nsize: %d\n' % size
613
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
614
 
                         request.execute(backing.local_abspath(''), '', 'no'))
 
1977
        expected_body = 'revisions: 0\n'
 
1978
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1979
                         request.execute('', '', 'no'))
615
1980
 
616
1981
    def test_revid_with_committers(self):
617
1982
        """For a revid we get more infos."""
618
1983
        backing = self.get_transport()
619
1984
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
620
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1985
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
621
1986
        tree = self.make_branch_and_memory_tree('.')
622
1987
        tree.lock_write()
623
1988
        tree.add('')
628
1993
        tree.unlock()
629
1994
 
630
1995
        stats = tree.branch.repository.gather_stats()
631
 
        size = stats['size']
632
1996
        expected_body = ('firstrev: 123456.200 3600\n'
633
1997
                         'latestrev: 654321.400 0\n'
634
 
                         'revisions: 2\n'
635
 
                         'size: %d\n' % size)
636
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
637
 
                         request.execute(backing.local_abspath(''),
 
1998
                         'revisions: 2\n')
 
1999
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
2000
                         request.execute('',
638
2001
                                         rev_id_utf8, 'no'))
639
2002
 
640
2003
    def test_not_empty_repository_with_committers(self):
641
2004
        """For a revid and requesting committers we get the whole thing."""
642
2005
        backing = self.get_transport()
643
2006
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
644
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
2007
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
645
2008
        tree = self.make_branch_and_memory_tree('.')
646
2009
        tree.lock_write()
647
2010
        tree.add('')
653
2016
        tree.unlock()
654
2017
        stats = tree.branch.repository.gather_stats()
655
2018
 
656
 
        size = stats['size']
657
2019
        expected_body = ('committers: 2\n'
658
2020
                         'firstrev: 123456.200 3600\n'
659
2021
                         'latestrev: 654321.400 0\n'
660
 
                         'revisions: 2\n'
661
 
                         'size: %d\n' % size)
662
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
663
 
                         request.execute(backing.local_abspath(''),
 
2022
                         'revisions: 2\n')
 
2023
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
2024
                         request.execute('',
664
2025
                                         rev_id_utf8, 'yes'))
665
2026
 
666
 
 
667
 
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
 
2027
    def test_unknown_revid(self):
 
2028
        """An unknown revision id causes a 'nosuchrevision' error."""
 
2029
        backing = self.get_transport()
 
2030
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
 
2031
        repository = self.make_repository('.')
 
2032
        expected_body = 'revisions: 0\n'
 
2033
        self.assertEqual(
 
2034
            smart_req.FailedSmartServerResponse(
 
2035
                ('nosuchrevision', 'mia'), None),
 
2036
            request.execute('', 'mia', 'yes'))
 
2037
 
 
2038
 
 
2039
class TestSmartServerRepositoryIsShared(tests.TestCaseWithMemoryTransport):
668
2040
 
669
2041
    def test_is_shared(self):
670
2042
        """For a shared repository, ('yes', ) is returned."""
671
2043
        backing = self.get_transport()
672
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
2044
        request = smart_repo.SmartServerRepositoryIsShared(backing)
673
2045
        self.make_repository('.', shared=True)
674
 
        self.assertEqual(SmartServerResponse(('yes', )),
675
 
            request.execute(backing.local_abspath(''), ))
 
2046
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2047
            request.execute('', ))
676
2048
 
677
2049
    def test_is_not_shared(self):
678
2050
        """For a shared repository, ('no', ) is returned."""
679
2051
        backing = self.get_transport()
680
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
2052
        request = smart_repo.SmartServerRepositoryIsShared(backing)
681
2053
        self.make_repository('.', shared=False)
682
 
        self.assertEqual(SmartServerResponse(('no', )),
683
 
            request.execute(backing.local_abspath(''), ))
684
 
 
685
 
 
686
 
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
687
 
 
688
 
    def setUp(self):
689
 
        tests.TestCaseWithTransport.setUp(self)
690
 
        self.reduceLockdirTimeout()
 
2054
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2055
            request.execute('', ))
 
2056
 
 
2057
 
 
2058
class TestSmartServerRepositoryGetRevisionSignatureText(
 
2059
        tests.TestCaseWithMemoryTransport):
 
2060
 
 
2061
    def test_get_signature(self):
 
2062
        backing = self.get_transport()
 
2063
        request = smart_repo.SmartServerRepositoryGetRevisionSignatureText(
 
2064
            backing)
 
2065
        bb = self.make_branch_builder('.')
 
2066
        bb.build_commit(rev_id='A')
 
2067
        repo = bb.get_branch().repository
 
2068
        strategy = gpg.LoopbackGPGStrategy(None)
 
2069
        self.addCleanup(repo.lock_write().unlock)
 
2070
        repo.start_write_group()
 
2071
        repo.sign_revision('A', strategy)
 
2072
        repo.commit_write_group()
 
2073
        expected_body = (
 
2074
            '-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
 
2075
            Testament.from_revision(repo, 'A').as_short_text() +
 
2076
            '-----END PSEUDO-SIGNED CONTENT-----\n')
 
2077
        self.assertEqual(
 
2078
            smart_req.SmartServerResponse(('ok', ), expected_body),
 
2079
            request.execute('', 'A'))
 
2080
 
 
2081
 
 
2082
class TestSmartServerRepositoryMakeWorkingTrees(
 
2083
        tests.TestCaseWithMemoryTransport):
 
2084
 
 
2085
    def test_make_working_trees(self):
 
2086
        """For a repository with working trees, ('yes', ) is returned."""
 
2087
        backing = self.get_transport()
 
2088
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2089
        r = self.make_repository('.')
 
2090
        r.set_make_working_trees(True)
 
2091
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2092
            request.execute('', ))
 
2093
 
 
2094
    def test_is_not_shared(self):
 
2095
        """For a repository with working trees, ('no', ) is returned."""
 
2096
        backing = self.get_transport()
 
2097
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2098
        r = self.make_repository('.')
 
2099
        r.set_make_working_trees(False)
 
2100
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2101
            request.execute('', ))
 
2102
 
 
2103
 
 
2104
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
691
2105
 
692
2106
    def test_lock_write_on_unlocked_repo(self):
693
2107
        backing = self.get_transport()
694
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
 
2108
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
695
2109
        repository = self.make_repository('.', format='knit')
696
 
        response = request.execute(backing.local_abspath(''))
 
2110
        response = request.execute('')
697
2111
        nonce = repository.control_files._lock.peek().get('nonce')
698
 
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
 
2112
        self.assertEqual(smart_req.SmartServerResponse(('ok', nonce)), response)
699
2113
        # The repository is now locked.  Verify that with a new repository
700
2114
        # object.
701
2115
        new_repo = repository.bzrdir.open_repository()
702
2116
        self.assertRaises(errors.LockContention, new_repo.lock_write)
 
2117
        # Cleanup
 
2118
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2119
        response = request.execute('', nonce)
703
2120
 
704
2121
    def test_lock_write_on_locked_repo(self):
705
2122
        backing = self.get_transport()
706
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
 
2123
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
707
2124
        repository = self.make_repository('.', format='knit')
708
 
        repository.lock_write()
 
2125
        repo_token = repository.lock_write().repository_token
709
2126
        repository.leave_lock_in_place()
710
2127
        repository.unlock()
711
 
        response = request.execute(backing.local_abspath(''))
 
2128
        response = request.execute('')
712
2129
        self.assertEqual(
713
 
            SmartServerResponse(('LockContention',)), response)
 
2130
            smart_req.SmartServerResponse(('LockContention',)), response)
 
2131
        # Cleanup
 
2132
        repository.lock_write(repo_token)
 
2133
        repository.dont_leave_lock_in_place()
 
2134
        repository.unlock()
714
2135
 
715
2136
    def test_lock_write_on_readonly_transport(self):
716
2137
        backing = self.get_readonly_transport()
717
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
 
2138
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
718
2139
        repository = self.make_repository('.', format='knit')
719
2140
        response = request.execute('')
720
2141
        self.assertFalse(response.is_successful())
721
2142
        self.assertEqual('LockFailed', response.args[0])
722
2143
 
723
2144
 
724
 
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
725
 
 
726
 
    def setUp(self):
727
 
        tests.TestCaseWithTransport.setUp(self)
728
 
        self.reduceLockdirTimeout()
 
2145
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
 
2146
 
 
2147
    def make_empty_byte_stream(self, repo):
 
2148
        byte_stream = smart_repo._stream_to_byte_stream([], repo._format)
 
2149
        return ''.join(byte_stream)
 
2150
 
 
2151
 
 
2152
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
 
2153
 
 
2154
    def test_insert_stream_empty(self):
 
2155
        backing = self.get_transport()
 
2156
        request = smart_repo.SmartServerRepositoryInsertStream(backing)
 
2157
        repository = self.make_repository('.')
 
2158
        response = request.execute('', '')
 
2159
        self.assertEqual(None, response)
 
2160
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
2161
        self.assertEqual(None, response)
 
2162
        response = request.do_end()
 
2163
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
2164
 
 
2165
 
 
2166
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
 
2167
 
 
2168
    def test_insert_stream_empty(self):
 
2169
        backing = self.get_transport()
 
2170
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
2171
            backing)
 
2172
        repository = self.make_repository('.', format='knit')
 
2173
        lock_token = repository.lock_write().repository_token
 
2174
        response = request.execute('', '', lock_token)
 
2175
        self.assertEqual(None, response)
 
2176
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
2177
        self.assertEqual(None, response)
 
2178
        response = request.do_end()
 
2179
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
2180
        repository.unlock()
 
2181
 
 
2182
    def test_insert_stream_with_wrong_lock_token(self):
 
2183
        backing = self.get_transport()
 
2184
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
2185
            backing)
 
2186
        repository = self.make_repository('.', format='knit')
 
2187
        lock_token = repository.lock_write().repository_token
 
2188
        self.assertRaises(
 
2189
            errors.TokenMismatch, request.execute, '', '', 'wrong-token')
 
2190
        repository.unlock()
 
2191
 
 
2192
 
 
2193
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
729
2194
 
730
2195
    def test_unlock_on_locked_repo(self):
731
2196
        backing = self.get_transport()
732
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
 
2197
        request = smart_repo.SmartServerRepositoryUnlock(backing)
733
2198
        repository = self.make_repository('.', format='knit')
734
 
        token = repository.lock_write()
 
2199
        token = repository.lock_write().repository_token
735
2200
        repository.leave_lock_in_place()
736
2201
        repository.unlock()
737
 
        response = request.execute(backing.local_abspath(''), token)
 
2202
        response = request.execute('', token)
738
2203
        self.assertEqual(
739
 
            SmartServerResponse(('ok',)), response)
 
2204
            smart_req.SmartServerResponse(('ok',)), response)
740
2205
        # The repository is now unlocked.  Verify that with a new repository
741
2206
        # object.
742
2207
        new_repo = repository.bzrdir.open_repository()
745
2210
 
746
2211
    def test_unlock_on_unlocked_repo(self):
747
2212
        backing = self.get_transport()
748
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
 
2213
        request = smart_repo.SmartServerRepositoryUnlock(backing)
749
2214
        repository = self.make_repository('.', format='knit')
750
 
        response = request.execute(backing.local_abspath(''), 'some token')
751
 
        self.assertEqual(
752
 
            SmartServerResponse(('TokenMismatch',)), response)
753
 
 
754
 
 
755
 
class TestSmartServerRepositoryTarball(tests.TestCaseWithTransport):
756
 
 
757
 
    def test_repository_tarball(self):
758
 
        backing = self.get_transport()
759
 
        request = smart.repository.SmartServerRepositoryTarball(backing)
760
 
        repository = self.make_repository('.')
761
 
        # make some extraneous junk in the repository directory which should
762
 
        # not be copied
763
 
        self.build_tree(['.bzr/repository/extra-junk'])
764
 
        response = request.execute(backing.local_abspath(''), 'bz2')
765
 
        self.assertEqual(('ok',), response.args)
766
 
        # body should be a tbz2
767
 
        body_file = StringIO(response.body)
768
 
        body_tar = tarfile.open('body_tar.tbz2', fileobj=body_file,
769
 
            mode='r|bz2')
770
 
        # let's make sure there are some key repository components inside it.
771
 
        # the tarfile returns directories with trailing slashes...
772
 
        names = set([n.rstrip('/') for n in body_tar.getnames()])
773
 
        self.assertTrue('.bzr/repository/lock' in names)
774
 
        self.assertTrue('.bzr/repository/format' in names)
775
 
        self.assertTrue('.bzr/repository/extra-junk' not in names,
776
 
            "extraneous file present in tar file")
777
 
 
778
 
 
779
 
class TestSmartServerRepositoryStreamKnitData(tests.TestCaseWithTransport):
780
 
 
781
 
    def test_fetch_revisions(self):
782
 
        backing = self.get_transport()
783
 
        request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
784
 
        tree = self.make_branch_and_memory_tree('.')
785
 
        tree.lock_write()
786
 
        tree.add('')
787
 
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
788
 
        rev_id2_utf8 = u'\xc9'.encode('utf-8')
789
 
        r1 = tree.commit('1st commit', rev_id=rev_id1_utf8)
790
 
        r1 = tree.commit('2nd commit', rev_id=rev_id2_utf8)
791
 
        tree.unlock()
792
 
 
793
 
        response = request.execute(backing.local_abspath(''), rev_id2_utf8)
794
 
        self.assertEqual(('ok',), response.args)
795
 
        from cStringIO import StringIO
796
 
        unpacker = pack.ContainerReader(StringIO(response.body))
797
 
        names = []
798
 
        for [name], read_bytes in unpacker.iter_records():
799
 
            names.append(name)
800
 
            bytes = read_bytes(None)
801
 
            # The bytes should be a valid bencoded string.
802
 
            bencode.bdecode(bytes)
803
 
            # XXX: assert that the bencoded knit records have the right
804
 
            # contents?
805
 
        
806
 
    def test_no_such_revision_error(self):
807
 
        backing = self.get_transport()
808
 
        request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
809
 
        repo = self.make_repository('.')
810
 
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
811
 
        response = request.execute(backing.local_abspath(''), rev_id1_utf8)
812
 
        self.assertEqual(
813
 
            SmartServerResponse(('NoSuchRevision', rev_id1_utf8)),
814
 
            response)
815
 
 
816
 
 
817
 
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
 
2215
        response = request.execute('', 'some token')
 
2216
        self.assertEqual(
 
2217
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
2218
 
 
2219
 
 
2220
class TestSmartServerRepositoryGetPhysicalLockStatus(
 
2221
    tests.TestCaseWithTransport):
 
2222
 
 
2223
    def test_with_write_lock(self):
 
2224
        backing = self.get_transport()
 
2225
        repo = self.make_repository('.')
 
2226
        self.addCleanup(repo.lock_write().unlock)
 
2227
        # lock_write() doesn't necessarily actually take a physical
 
2228
        # lock out.
 
2229
        if repo.get_physical_lock_status():
 
2230
            expected = 'yes'
 
2231
        else:
 
2232
            expected = 'no'
 
2233
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2234
        request = request_class(backing)
 
2235
        self.assertEqual(smart_req.SuccessfulSmartServerResponse((expected,)),
 
2236
            request.execute('', ))
 
2237
 
 
2238
    def test_without_write_lock(self):
 
2239
        backing = self.get_transport()
 
2240
        repo = self.make_repository('.')
 
2241
        self.assertEqual(False, repo.get_physical_lock_status())
 
2242
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2243
        request = request_class(backing)
 
2244
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('no',)),
 
2245
            request.execute('', ))
 
2246
 
 
2247
 
 
2248
class TestSmartServerRepositoryReconcile(tests.TestCaseWithTransport):
 
2249
 
 
2250
    def test_reconcile(self):
 
2251
        backing = self.get_transport()
 
2252
        repo = self.make_repository('.')
 
2253
        token = repo.lock_write().repository_token
 
2254
        self.addCleanup(repo.unlock)
 
2255
        request_class = smart_repo.SmartServerRepositoryReconcile
 
2256
        request = request_class(backing)
 
2257
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
2258
            ('ok', ),
 
2259
             'garbage_inventories: 0\n'
 
2260
             'inconsistent_parents: 0\n'),
 
2261
            request.execute('', token))
 
2262
 
 
2263
 
 
2264
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
818
2265
 
819
2266
    def test_is_readonly_no(self):
820
2267
        backing = self.get_transport()
821
 
        request = smart.request.SmartServerIsReadonly(backing)
 
2268
        request = smart_req.SmartServerIsReadonly(backing)
822
2269
        response = request.execute()
823
2270
        self.assertEqual(
824
 
            SmartServerResponse(('no',)), response)
 
2271
            smart_req.SmartServerResponse(('no',)), response)
825
2272
 
826
2273
    def test_is_readonly_yes(self):
827
2274
        backing = self.get_readonly_transport()
828
 
        request = smart.request.SmartServerIsReadonly(backing)
 
2275
        request = smart_req.SmartServerIsReadonly(backing)
829
2276
        response = request.execute()
830
2277
        self.assertEqual(
831
 
            SmartServerResponse(('yes',)), response)
 
2278
            smart_req.SmartServerResponse(('yes',)), response)
 
2279
 
 
2280
 
 
2281
class TestSmartServerRepositorySetMakeWorkingTrees(
 
2282
    tests.TestCaseWithMemoryTransport):
 
2283
 
 
2284
    def test_set_false(self):
 
2285
        backing = self.get_transport()
 
2286
        repo = self.make_repository('.', shared=True)
 
2287
        repo.set_make_working_trees(True)
 
2288
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
2289
        request = request_class(backing)
 
2290
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2291
            request.execute('', 'False'))
 
2292
        repo = repo.bzrdir.open_repository()
 
2293
        self.assertFalse(repo.make_working_trees())
 
2294
 
 
2295
    def test_set_true(self):
 
2296
        backing = self.get_transport()
 
2297
        repo = self.make_repository('.', shared=True)
 
2298
        repo.set_make_working_trees(False)
 
2299
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
2300
        request = request_class(backing)
 
2301
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2302
            request.execute('', 'True'))
 
2303
        repo = repo.bzrdir.open_repository()
 
2304
        self.assertTrue(repo.make_working_trees())
 
2305
 
 
2306
 
 
2307
class TestSmartServerRepositoryGetSerializerFormat(
 
2308
    tests.TestCaseWithMemoryTransport):
 
2309
 
 
2310
    def test_get_serializer_format(self):
 
2311
        backing = self.get_transport()
 
2312
        repo = self.make_repository('.', format='2a')
 
2313
        request_class = smart_repo.SmartServerRepositoryGetSerializerFormat
 
2314
        request = request_class(backing)
 
2315
        self.assertEqual(
 
2316
            smart_req.SuccessfulSmartServerResponse(('ok', '10')),
 
2317
            request.execute(''))
 
2318
 
 
2319
 
 
2320
class TestSmartServerRepositoryWriteGroup(
 
2321
    tests.TestCaseWithMemoryTransport):
 
2322
 
 
2323
    def test_start_write_group(self):
 
2324
        backing = self.get_transport()
 
2325
        repo = self.make_repository('.')
 
2326
        lock_token = repo.lock_write().repository_token
 
2327
        self.addCleanup(repo.unlock)
 
2328
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2329
        request = request_class(backing)
 
2330
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok', [])),
 
2331
            request.execute('', lock_token))
 
2332
 
 
2333
    def test_start_write_group_unsuspendable(self):
 
2334
        backing = self.get_transport()
 
2335
        repo = self.make_repository('.', format='knit')
 
2336
        lock_token = repo.lock_write().repository_token
 
2337
        self.addCleanup(repo.unlock)
 
2338
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2339
        request = request_class(backing)
 
2340
        self.assertEqual(
 
2341
            smart_req.FailedSmartServerResponse(('UnsuspendableWriteGroup',)),
 
2342
            request.execute('', lock_token))
 
2343
 
 
2344
    def test_commit_write_group(self):
 
2345
        backing = self.get_transport()
 
2346
        repo = self.make_repository('.')
 
2347
        lock_token = repo.lock_write().repository_token
 
2348
        self.addCleanup(repo.unlock)
 
2349
        repo.start_write_group()
 
2350
        tokens = repo.suspend_write_group()
 
2351
        request_class = smart_repo.SmartServerRepositoryCommitWriteGroup
 
2352
        request = request_class(backing)
 
2353
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2354
            request.execute('', lock_token, tokens))
 
2355
 
 
2356
    def test_abort_write_group(self):
 
2357
        backing = self.get_transport()
 
2358
        repo = self.make_repository('.')
 
2359
        lock_token = repo.lock_write().repository_token
 
2360
        repo.start_write_group()
 
2361
        tokens = repo.suspend_write_group()
 
2362
        self.addCleanup(repo.unlock)
 
2363
        request_class = smart_repo.SmartServerRepositoryAbortWriteGroup
 
2364
        request = request_class(backing)
 
2365
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2366
            request.execute('', lock_token, tokens))
 
2367
 
 
2368
    def test_check_write_group(self):
 
2369
        backing = self.get_transport()
 
2370
        repo = self.make_repository('.')
 
2371
        lock_token = repo.lock_write().repository_token
 
2372
        repo.start_write_group()
 
2373
        tokens = repo.suspend_write_group()
 
2374
        self.addCleanup(repo.unlock)
 
2375
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2376
        request = request_class(backing)
 
2377
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2378
            request.execute('', lock_token, tokens))
 
2379
 
 
2380
    def test_check_write_group_invalid(self):
 
2381
        backing = self.get_transport()
 
2382
        repo = self.make_repository('.')
 
2383
        lock_token = repo.lock_write().repository_token
 
2384
        self.addCleanup(repo.unlock)
 
2385
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2386
        request = request_class(backing)
 
2387
        self.assertEqual(smart_req.FailedSmartServerResponse(
 
2388
            ('UnresumableWriteGroup', ['random'],
 
2389
                'Malformed write group token')),
 
2390
            request.execute('', lock_token, ["random"]))
 
2391
 
 
2392
 
 
2393
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
 
2394
 
 
2395
    def make_repo_needing_autopacking(self, path='.'):
 
2396
        # Make a repo in need of autopacking.
 
2397
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
2398
        repo = tree.branch.repository
 
2399
        # monkey-patch the pack collection to disable autopacking
 
2400
        repo._pack_collection._max_pack_count = lambda count: count
 
2401
        for x in range(10):
 
2402
            tree.commit('commit %s' % x)
 
2403
        self.assertEqual(10, len(repo._pack_collection.names()))
 
2404
        del repo._pack_collection._max_pack_count
 
2405
        return repo
 
2406
 
 
2407
    def test_autopack_needed(self):
 
2408
        repo = self.make_repo_needing_autopacking()
 
2409
        repo.lock_write()
 
2410
        self.addCleanup(repo.unlock)
 
2411
        backing = self.get_transport()
 
2412
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2413
            backing)
 
2414
        response = request.execute('')
 
2415
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2416
        repo._pack_collection.reload_pack_names()
 
2417
        self.assertEqual(1, len(repo._pack_collection.names()))
 
2418
 
 
2419
    def test_autopack_not_needed(self):
 
2420
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
2421
        repo = tree.branch.repository
 
2422
        repo.lock_write()
 
2423
        self.addCleanup(repo.unlock)
 
2424
        for x in range(9):
 
2425
            tree.commit('commit %s' % x)
 
2426
        backing = self.get_transport()
 
2427
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2428
            backing)
 
2429
        response = request.execute('')
 
2430
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2431
        repo._pack_collection.reload_pack_names()
 
2432
        self.assertEqual(9, len(repo._pack_collection.names()))
 
2433
 
 
2434
    def test_autopack_on_nonpack_format(self):
 
2435
        """A request to autopack a non-pack repo is a no-op."""
 
2436
        repo = self.make_repository('.', format='knit')
 
2437
        backing = self.get_transport()
 
2438
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2439
            backing)
 
2440
        response = request.execute('')
 
2441
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2442
 
 
2443
 
 
2444
class TestSmartServerVfsGet(tests.TestCaseWithMemoryTransport):
 
2445
 
 
2446
    def test_unicode_path(self):
 
2447
        """VFS requests expect unicode paths to be escaped."""
 
2448
        filename = u'foo\N{INTERROBANG}'
 
2449
        filename_escaped = urlutils.escape(filename)
 
2450
        backing = self.get_transport()
 
2451
        request = vfs.GetRequest(backing)
 
2452
        backing.put_bytes_non_atomic(filename_escaped, 'contents')
 
2453
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'contents'),
 
2454
            request.execute(filename_escaped))
832
2455
 
833
2456
 
834
2457
class TestHandlers(tests.TestCase):
835
2458
    """Tests for the request.request_handlers object."""
836
2459
 
 
2460
    def test_all_registrations_exist(self):
 
2461
        """All registered request_handlers can be found."""
 
2462
        # If there's a typo in a register_lazy call, this loop will fail with
 
2463
        # an AttributeError.
 
2464
        for key in smart_req.request_handlers.keys():
 
2465
            try:
 
2466
                item = smart_req.request_handlers.get(key)
 
2467
            except AttributeError, e:
 
2468
                raise AttributeError('failed to get %s: %s' % (key, e))
 
2469
 
 
2470
    def assertHandlerEqual(self, verb, handler):
 
2471
        self.assertEqual(smart_req.request_handlers.get(verb), handler)
 
2472
 
837
2473
    def test_registered_methods(self):
838
2474
        """Test that known methods are registered to the correct object."""
839
 
        self.assertEqual(
840
 
            smart.request.request_handlers.get('Branch.get_config_file'),
841
 
            smart.branch.SmartServerBranchGetConfigFile)
842
 
        self.assertEqual(
843
 
            smart.request.request_handlers.get('Branch.lock_write'),
844
 
            smart.branch.SmartServerBranchRequestLockWrite)
845
 
        self.assertEqual(
846
 
            smart.request.request_handlers.get('Branch.last_revision_info'),
847
 
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
848
 
        self.assertEqual(
849
 
            smart.request.request_handlers.get('Branch.revision_history'),
850
 
            smart.branch.SmartServerRequestRevisionHistory)
851
 
        self.assertEqual(
852
 
            smart.request.request_handlers.get('Branch.set_last_revision'),
853
 
            smart.branch.SmartServerBranchRequestSetLastRevision)
854
 
        self.assertEqual(
855
 
            smart.request.request_handlers.get('Branch.unlock'),
856
 
            smart.branch.SmartServerBranchRequestUnlock)
857
 
        self.assertEqual(
858
 
            smart.request.request_handlers.get('BzrDir.find_repository'),
859
 
            smart.bzrdir.SmartServerRequestFindRepository)
860
 
        self.assertEqual(
861
 
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
862
 
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
863
 
        self.assertEqual(
864
 
            smart.request.request_handlers.get('BzrDir.open_branch'),
865
 
            smart.bzrdir.SmartServerRequestOpenBranch)
866
 
        self.assertEqual(
867
 
            smart.request.request_handlers.get('Repository.gather_stats'),
868
 
            smart.repository.SmartServerRepositoryGatherStats)
869
 
        self.assertEqual(
870
 
            smart.request.request_handlers.get(
871
 
                'Repository.get_revision_graph'),
872
 
            smart.repository.SmartServerRepositoryGetRevisionGraph)
873
 
        self.assertEqual(
874
 
            smart.request.request_handlers.get('Repository.has_revision'),
875
 
            smart.repository.SmartServerRequestHasRevision)
876
 
        self.assertEqual(
877
 
            smart.request.request_handlers.get('Repository.is_shared'),
878
 
            smart.repository.SmartServerRepositoryIsShared)
879
 
        self.assertEqual(
880
 
            smart.request.request_handlers.get('Repository.lock_write'),
881
 
            smart.repository.SmartServerRepositoryLockWrite)
882
 
        self.assertEqual(
883
 
            smart.request.request_handlers.get(
884
 
                'Repository.stream_knit_data_for_revisions'),
885
 
            smart.repository.SmartServerRepositoryStreamKnitDataForRevisions)
886
 
        self.assertEqual(
887
 
            smart.request.request_handlers.get('Repository.tarball'),
888
 
            smart.repository.SmartServerRepositoryTarball)
889
 
        self.assertEqual(
890
 
            smart.request.request_handlers.get('Repository.unlock'),
891
 
            smart.repository.SmartServerRepositoryUnlock)
892
 
        self.assertEqual(
893
 
            smart.request.request_handlers.get('Transport.is_readonly'),
894
 
            smart.request.SmartServerIsReadonly)
 
2475
        self.assertHandlerEqual('Branch.break_lock',
 
2476
            smart_branch.SmartServerBranchBreakLock)
 
2477
        self.assertHandlerEqual('Branch.get_config_file',
 
2478
            smart_branch.SmartServerBranchGetConfigFile)
 
2479
        self.assertHandlerEqual('Branch.put_config_file',
 
2480
            smart_branch.SmartServerBranchPutConfigFile)
 
2481
        self.assertHandlerEqual('Branch.get_parent',
 
2482
            smart_branch.SmartServerBranchGetParent)
 
2483
        self.assertHandlerEqual('Branch.get_physical_lock_status',
 
2484
            smart_branch.SmartServerBranchRequestGetPhysicalLockStatus)
 
2485
        self.assertHandlerEqual('Branch.get_tags_bytes',
 
2486
            smart_branch.SmartServerBranchGetTagsBytes)
 
2487
        self.assertHandlerEqual('Branch.lock_write',
 
2488
            smart_branch.SmartServerBranchRequestLockWrite)
 
2489
        self.assertHandlerEqual('Branch.last_revision_info',
 
2490
            smart_branch.SmartServerBranchRequestLastRevisionInfo)
 
2491
        self.assertHandlerEqual('Branch.revision_history',
 
2492
            smart_branch.SmartServerRequestRevisionHistory)
 
2493
        self.assertHandlerEqual('Branch.revision_id_to_revno',
 
2494
            smart_branch.SmartServerBranchRequestRevisionIdToRevno)
 
2495
        self.assertHandlerEqual('Branch.set_config_option',
 
2496
            smart_branch.SmartServerBranchRequestSetConfigOption)
 
2497
        self.assertHandlerEqual('Branch.set_last_revision',
 
2498
            smart_branch.SmartServerBranchRequestSetLastRevision)
 
2499
        self.assertHandlerEqual('Branch.set_last_revision_info',
 
2500
            smart_branch.SmartServerBranchRequestSetLastRevisionInfo)
 
2501
        self.assertHandlerEqual('Branch.set_last_revision_ex',
 
2502
            smart_branch.SmartServerBranchRequestSetLastRevisionEx)
 
2503
        self.assertHandlerEqual('Branch.set_parent_location',
 
2504
            smart_branch.SmartServerBranchRequestSetParentLocation)
 
2505
        self.assertHandlerEqual('Branch.unlock',
 
2506
            smart_branch.SmartServerBranchRequestUnlock)
 
2507
        self.assertHandlerEqual('BzrDir.destroy_branch',
 
2508
            smart_dir.SmartServerBzrDirRequestDestroyBranch)
 
2509
        self.assertHandlerEqual('BzrDir.find_repository',
 
2510
            smart_dir.SmartServerRequestFindRepositoryV1)
 
2511
        self.assertHandlerEqual('BzrDir.find_repositoryV2',
 
2512
            smart_dir.SmartServerRequestFindRepositoryV2)
 
2513
        self.assertHandlerEqual('BzrDirFormat.initialize',
 
2514
            smart_dir.SmartServerRequestInitializeBzrDir)
 
2515
        self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
 
2516
            smart_dir.SmartServerRequestBzrDirInitializeEx)
 
2517
        self.assertHandlerEqual('BzrDir.checkout_metadir',
 
2518
            smart_dir.SmartServerBzrDirRequestCheckoutMetaDir)
 
2519
        self.assertHandlerEqual('BzrDir.cloning_metadir',
 
2520
            smart_dir.SmartServerBzrDirRequestCloningMetaDir)
 
2521
        self.assertHandlerEqual('BzrDir.get_branches',
 
2522
            smart_dir.SmartServerBzrDirRequestGetBranches)
 
2523
        self.assertHandlerEqual('BzrDir.get_config_file',
 
2524
            smart_dir.SmartServerBzrDirRequestConfigFile)
 
2525
        self.assertHandlerEqual('BzrDir.open_branch',
 
2526
            smart_dir.SmartServerRequestOpenBranch)
 
2527
        self.assertHandlerEqual('BzrDir.open_branchV2',
 
2528
            smart_dir.SmartServerRequestOpenBranchV2)
 
2529
        self.assertHandlerEqual('BzrDir.open_branchV3',
 
2530
            smart_dir.SmartServerRequestOpenBranchV3)
 
2531
        self.assertHandlerEqual('PackRepository.autopack',
 
2532
            smart_packrepo.SmartServerPackRepositoryAutopack)
 
2533
        self.assertHandlerEqual('Repository.add_signature_text',
 
2534
            smart_repo.SmartServerRepositoryAddSignatureText)
 
2535
        self.assertHandlerEqual('Repository.all_revision_ids',
 
2536
            smart_repo.SmartServerRepositoryAllRevisionIds)
 
2537
        self.assertHandlerEqual('Repository.break_lock',
 
2538
            smart_repo.SmartServerRepositoryBreakLock)
 
2539
        self.assertHandlerEqual('Repository.gather_stats',
 
2540
            smart_repo.SmartServerRepositoryGatherStats)
 
2541
        self.assertHandlerEqual('Repository.get_parent_map',
 
2542
            smart_repo.SmartServerRepositoryGetParentMap)
 
2543
        self.assertHandlerEqual('Repository.get_physical_lock_status',
 
2544
            smart_repo.SmartServerRepositoryGetPhysicalLockStatus)
 
2545
        self.assertHandlerEqual('Repository.get_rev_id_for_revno',
 
2546
            smart_repo.SmartServerRepositoryGetRevIdForRevno)
 
2547
        self.assertHandlerEqual('Repository.get_revision_graph',
 
2548
            smart_repo.SmartServerRepositoryGetRevisionGraph)
 
2549
        self.assertHandlerEqual('Repository.get_revision_signature_text',
 
2550
            smart_repo.SmartServerRepositoryGetRevisionSignatureText)
 
2551
        self.assertHandlerEqual('Repository.get_stream',
 
2552
            smart_repo.SmartServerRepositoryGetStream)
 
2553
        self.assertHandlerEqual('Repository.get_stream_1.19',
 
2554
            smart_repo.SmartServerRepositoryGetStream_1_19)
 
2555
        self.assertHandlerEqual('Repository.iter_revisions',
 
2556
            smart_repo.SmartServerRepositoryIterRevisions)
 
2557
        self.assertHandlerEqual('Repository.has_revision',
 
2558
            smart_repo.SmartServerRequestHasRevision)
 
2559
        self.assertHandlerEqual('Repository.insert_stream',
 
2560
            smart_repo.SmartServerRepositoryInsertStream)
 
2561
        self.assertHandlerEqual('Repository.insert_stream_locked',
 
2562
            smart_repo.SmartServerRepositoryInsertStreamLocked)
 
2563
        self.assertHandlerEqual('Repository.is_shared',
 
2564
            smart_repo.SmartServerRepositoryIsShared)
 
2565
        self.assertHandlerEqual('Repository.iter_files_bytes',
 
2566
            smart_repo.SmartServerRepositoryIterFilesBytes)
 
2567
        self.assertHandlerEqual('Repository.lock_write',
 
2568
            smart_repo.SmartServerRepositoryLockWrite)
 
2569
        self.assertHandlerEqual('Repository.make_working_trees',
 
2570
            smart_repo.SmartServerRepositoryMakeWorkingTrees)
 
2571
        self.assertHandlerEqual('Repository.pack',
 
2572
            smart_repo.SmartServerRepositoryPack)
 
2573
        self.assertHandlerEqual('Repository.reconcile',
 
2574
            smart_repo.SmartServerRepositoryReconcile)
 
2575
        self.assertHandlerEqual('Repository.tarball',
 
2576
            smart_repo.SmartServerRepositoryTarball)
 
2577
        self.assertHandlerEqual('Repository.unlock',
 
2578
            smart_repo.SmartServerRepositoryUnlock)
 
2579
        self.assertHandlerEqual('Repository.start_write_group',
 
2580
            smart_repo.SmartServerRepositoryStartWriteGroup)
 
2581
        self.assertHandlerEqual('Repository.check_write_group',
 
2582
            smart_repo.SmartServerRepositoryCheckWriteGroup)
 
2583
        self.assertHandlerEqual('Repository.commit_write_group',
 
2584
            smart_repo.SmartServerRepositoryCommitWriteGroup)
 
2585
        self.assertHandlerEqual('Repository.abort_write_group',
 
2586
            smart_repo.SmartServerRepositoryAbortWriteGroup)
 
2587
        self.assertHandlerEqual('VersionedFileRepository.get_serializer_format',
 
2588
            smart_repo.SmartServerRepositoryGetSerializerFormat)
 
2589
        self.assertHandlerEqual('VersionedFileRepository.get_inventories',
 
2590
            smart_repo.SmartServerRepositoryGetInventories)
 
2591
        self.assertHandlerEqual('Transport.is_readonly',
 
2592
            smart_req.SmartServerIsReadonly)
 
2593
 
 
2594
 
 
2595
class SmartTCPServerHookTests(tests.TestCaseWithMemoryTransport):
 
2596
    """Tests for SmartTCPServer hooks."""
 
2597
 
 
2598
    def setUp(self):
 
2599
        super(SmartTCPServerHookTests, self).setUp()
 
2600
        self.server = server.SmartTCPServer(self.get_transport())
 
2601
 
 
2602
    def test_run_server_started_hooks(self):
 
2603
        """Test the server started hooks get fired properly."""
 
2604
        started_calls = []
 
2605
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2606
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2607
            None)
 
2608
        started_ex_calls = []
 
2609
        server.SmartTCPServer.hooks.install_named_hook('server_started_ex',
 
2610
            lambda backing_urls, url: started_ex_calls.append((backing_urls, url)),
 
2611
            None)
 
2612
        self.server._sockname = ('example.com', 42)
 
2613
        self.server.run_server_started_hooks()
 
2614
        self.assertEqual(started_calls,
 
2615
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2616
        self.assertEqual(started_ex_calls,
 
2617
            [([self.get_transport().base], self.server)])
 
2618
 
 
2619
    def test_run_server_started_hooks_ipv6(self):
 
2620
        """Test that socknames can contain 4-tuples."""
 
2621
        self.server._sockname = ('::', 42, 0, 0)
 
2622
        started_calls = []
 
2623
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2624
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2625
            None)
 
2626
        self.server.run_server_started_hooks()
 
2627
        self.assertEqual(started_calls,
 
2628
                [([self.get_transport().base], 'bzr://:::42/')])
 
2629
 
 
2630
    def test_run_server_stopped_hooks(self):
 
2631
        """Test the server stopped hooks."""
 
2632
        self.server._sockname = ('example.com', 42)
 
2633
        stopped_calls = []
 
2634
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
 
2635
            lambda backing_urls, url: stopped_calls.append((backing_urls, url)),
 
2636
            None)
 
2637
        self.server.run_server_stopped_hooks()
 
2638
        self.assertEqual(stopped_calls,
 
2639
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2640
 
 
2641
 
 
2642
class TestSmartServerRepositoryPack(tests.TestCaseWithMemoryTransport):
 
2643
 
 
2644
    def test_pack(self):
 
2645
        backing = self.get_transport()
 
2646
        request = smart_repo.SmartServerRepositoryPack(backing)
 
2647
        tree = self.make_branch_and_memory_tree('.')
 
2648
        repo_token = tree.branch.repository.lock_write().repository_token
 
2649
 
 
2650
        self.assertIs(None, request.execute('', repo_token, False))
 
2651
 
 
2652
        self.assertEqual(
 
2653
            smart_req.SuccessfulSmartServerResponse(('ok', ), ),
 
2654
            request.do_body(''))
 
2655
 
 
2656
 
 
2657
class TestSmartServerRepositoryGetInventories(tests.TestCaseWithTransport):
 
2658
 
 
2659
    def _get_serialized_inventory_delta(self, repository, base_revid, revid):
 
2660
        base_inv = repository.revision_tree(base_revid).root_inventory
 
2661
        inv = repository.revision_tree(revid).root_inventory
 
2662
        inv_delta = inv._make_delta(base_inv)
 
2663
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
2664
        return "".join(serializer.delta_to_lines(base_revid, revid, inv_delta))
 
2665
 
 
2666
    def test_single(self):
 
2667
        backing = self.get_transport()
 
2668
        request = smart_repo.SmartServerRepositoryGetInventories(backing)
 
2669
        t = self.make_branch_and_tree('.', format='2a')
 
2670
        self.addCleanup(t.lock_write().unlock)
 
2671
        self.build_tree_contents([("file", "somecontents")])
 
2672
        t.add(["file"], ["thefileid"])
 
2673
        t.commit(rev_id='somerev', message="add file")
 
2674
        self.assertIs(None, request.execute('', 'unordered'))
 
2675
        response = request.do_body("somerev\n")
 
2676
        self.assertTrue(response.is_successful())
 
2677
        self.assertEqual(response.args, ("ok", ))
 
2678
        stream = [('inventory-deltas', [
 
2679
            versionedfile.FulltextContentFactory('somerev', None, None,
 
2680
                self._get_serialized_inventory_delta(
 
2681
                    t.branch.repository, 'null:', 'somerev'))])]
 
2682
        fmt = controldir.format_registry.get('2a')().repository_format
 
2683
        self.assertEqual(
 
2684
            "".join(response.body_stream),
 
2685
            "".join(smart_repo._stream_to_byte_stream(stream, fmt)))
 
2686
 
 
2687
    def test_empty(self):
 
2688
        backing = self.get_transport()
 
2689
        request = smart_repo.SmartServerRepositoryGetInventories(backing)
 
2690
        t = self.make_branch_and_tree('.', format='2a')
 
2691
        self.addCleanup(t.lock_write().unlock)
 
2692
        self.build_tree_contents([("file", "somecontents")])
 
2693
        t.add(["file"], ["thefileid"])
 
2694
        t.commit(rev_id='somerev', message="add file")
 
2695
        self.assertIs(None, request.execute('', 'unordered'))
 
2696
        response = request.do_body("")
 
2697
        self.assertTrue(response.is_successful())
 
2698
        self.assertEqual(response.args, ("ok", ))
 
2699
        self.assertEqual("".join(response.body_stream),
 
2700
            "Bazaar pack format 1 (introduced in 0.18)\nB54\n\nBazaar repository format 2a (needs bzr 1.16 or later)\nE")