1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests for the smart wire/domain protocol.
19
This module contains tests for the domain-level smart requests and responses,
20
such as the 'Branch.lock_write' request. Many of these use specific disk
21
formats to exercise calls that only make sense for formats with specific
24
Tests for low-level protocol encoding are found in test_smart_transport.
32
branch as _mod_branch,
33
bzrbranch as _mod_bzrbranch,
43
from breezy.smart import (
44
branch as smart_branch,
46
repository as smart_repo,
47
packrepository as smart_packrepo,
52
from breezy.testament import Testament
53
from breezy.tests import test_server
54
from breezy.transport import (
60
def load_tests(loader, standard_tests, pattern):
61
"""Multiply tests version and protocol consistency."""
62
# FindRepository tests.
65
"_request_class": smart_dir.SmartServerRequestFindRepositoryV1}),
66
("find_repositoryV2", {
67
"_request_class": smart_dir.SmartServerRequestFindRepositoryV2}),
68
("find_repositoryV3", {
69
"_request_class": smart_dir.SmartServerRequestFindRepositoryV3}),
71
to_adapt, result = tests.split_suite_by_re(standard_tests,
72
"TestSmartServerRequestFindRepository")
73
v2_only, v1_and_2 = tests.split_suite_by_re(to_adapt,
75
tests.multiply_tests(v1_and_2, scenarios, result)
76
# The first scenario is only applicable to v1 protocols, it is deleted
78
tests.multiply_tests(v2_only, scenarios[1:], result)
82
class TestCaseWithChrootedTransport(tests.TestCaseWithTransport):
85
self.vfs_transport_factory = memory.MemoryServer
86
super(TestCaseWithChrootedTransport, self).setUp()
87
self._chroot_server = None
89
def get_transport(self, relpath=None):
90
if self._chroot_server is None:
91
backing_transport = tests.TestCaseWithTransport.get_transport(self)
92
self._chroot_server = chroot.ChrootServer(backing_transport)
93
self.start_server(self._chroot_server)
94
t = transport.get_transport_from_url(self._chroot_server.get_url())
95
if relpath is not None:
100
class TestCaseWithSmartMedium(tests.TestCaseWithMemoryTransport):
103
super(TestCaseWithSmartMedium, self).setUp()
104
# We're allowed to set the transport class here, so that we don't use
105
# the default or a parameterized class, but rather use the
106
# TestCaseWithTransport infrastructure to set up a smart server and
108
self.overrideAttr(self, "transport_server", self.make_transport_server)
110
def make_transport_server(self):
111
return test_server.SmartTCPServer_for_testing('-' + self.id())
113
def get_smart_medium(self):
114
"""Get a smart medium to use in tests."""
115
return self.get_transport().get_smart_medium()
118
class TestByteStreamToStream(tests.TestCase):
120
def test_repeated_substreams_same_kind_are_one_stream(self):
121
# Make a stream - an iterable of bytestrings.
122
stream = [('text', [versionedfile.FulltextContentFactory(('k1',), None,
123
None, 'foo')]),('text', [
124
versionedfile.FulltextContentFactory(('k2',), None, None, 'bar')])]
125
fmt = controldir.format_registry.get('pack-0.92')().repository_format
126
bytes = smart_repo._stream_to_byte_stream(stream, fmt)
128
# Iterate the resulting iterable; checking that we get only one stream
130
fmt, stream = smart_repo._byte_stream_to_stream(bytes)
131
for kind, substream in stream:
132
streams.append((kind, list(substream)))
133
self.assertLength(1, streams)
134
self.assertLength(2, streams[0][1])
137
class TestSmartServerResponse(tests.TestCase):
139
def test__eq__(self):
140
self.assertEqual(smart_req.SmartServerResponse(('ok', )),
141
smart_req.SmartServerResponse(('ok', )))
142
self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
143
smart_req.SmartServerResponse(('ok', ), 'body'))
144
self.assertNotEqual(smart_req.SmartServerResponse(('ok', )),
145
smart_req.SmartServerResponse(('notok', )))
146
self.assertNotEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
147
smart_req.SmartServerResponse(('ok', )))
148
self.assertNotEqual(None,
149
smart_req.SmartServerResponse(('ok', )))
151
def test__str__(self):
152
"""SmartServerResponses can be stringified."""
154
"<SuccessfulSmartServerResponse args=('args',) body='body'>",
155
str(smart_req.SuccessfulSmartServerResponse(('args',), 'body')))
157
"<FailedSmartServerResponse args=('args',) body='body'>",
158
str(smart_req.FailedSmartServerResponse(('args',), 'body')))
161
class TestSmartServerRequest(tests.TestCaseWithMemoryTransport):
163
def test_translate_client_path(self):
164
transport = self.get_transport()
165
request = smart_req.SmartServerRequest(transport, 'foo/')
166
self.assertEqual('./', request.translate_client_path('foo/'))
168
errors.InvalidURLJoin, request.translate_client_path, 'foo/..')
170
errors.PathNotChild, request.translate_client_path, '/')
172
errors.PathNotChild, request.translate_client_path, 'bar/')
173
self.assertEqual('./baz', request.translate_client_path('foo/baz'))
174
e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
175
self.assertEqual('./' + urlutils.escape(e_acute),
176
request.translate_client_path('foo/' + e_acute))
178
def test_translate_client_path_vfs(self):
179
"""VfsRequests receive escaped paths rather than raw UTF-8."""
180
transport = self.get_transport()
181
request = vfs.VfsRequest(transport, 'foo/')
182
e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
183
escaped = urlutils.escape('foo/' + e_acute)
184
self.assertEqual('./' + urlutils.escape(e_acute),
185
request.translate_client_path(escaped))
187
def test_transport_from_client_path(self):
188
transport = self.get_transport()
189
request = smart_req.SmartServerRequest(transport, 'foo/')
192
request.transport_from_client_path('foo/').base)
195
class TestSmartServerBzrDirRequestCloningMetaDir(
196
tests.TestCaseWithMemoryTransport):
197
"""Tests for BzrDir.cloning_metadir."""
199
def test_cloning_metadir(self):
200
"""When there is a bzrdir present, the call succeeds."""
201
backing = self.get_transport()
202
dir = self.make_bzrdir('.')
203
local_result = dir.cloning_metadir()
204
request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
205
request = request_class(backing)
206
expected = smart_req.SuccessfulSmartServerResponse(
207
(local_result.network_name(),
208
local_result.repository_format.network_name(),
209
('branch', local_result.get_branch_format().network_name())))
210
self.assertEqual(expected, request.execute('', 'False'))
212
def test_cloning_metadir_reference(self):
213
"""The request fails when bzrdir contains a branch reference."""
214
backing = self.get_transport()
215
referenced_branch = self.make_branch('referenced')
216
dir = self.make_bzrdir('.')
217
local_result = dir.cloning_metadir()
218
reference = _mod_bzrbranch.BranchReferenceFormat().initialize(
219
dir, target_branch=referenced_branch)
220
reference_url = _mod_bzrbranch.BranchReferenceFormat().get_reference(dir)
221
# The server shouldn't try to follow the branch reference, so it's fine
222
# if the referenced branch isn't reachable.
223
backing.rename('referenced', 'moved')
224
request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
225
request = request_class(backing)
226
expected = smart_req.FailedSmartServerResponse(('BranchReference',))
227
self.assertEqual(expected, request.execute('', 'False'))
230
class TestSmartServerBzrDirRequestCloningMetaDir(
231
tests.TestCaseWithMemoryTransport):
232
"""Tests for BzrDir.checkout_metadir."""
234
def test_checkout_metadir(self):
235
backing = self.get_transport()
236
request = smart_dir.SmartServerBzrDirRequestCheckoutMetaDir(
238
branch = self.make_branch('.', format='2a')
239
response = request.execute('')
241
smart_req.SmartServerResponse(
242
('Bazaar-NG meta directory, format 1\n',
243
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
244
'Bazaar Branch Format 7 (needs bzr 1.6)\n')),
248
class TestSmartServerBzrDirRequestDestroyBranch(
249
tests.TestCaseWithMemoryTransport):
250
"""Tests for BzrDir.destroy_branch."""
252
def test_destroy_branch_default(self):
253
"""The default branch can be removed."""
254
backing = self.get_transport()
255
dir = self.make_branch('.').bzrdir
256
request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
257
request = request_class(backing)
258
expected = smart_req.SuccessfulSmartServerResponse(('ok',))
259
self.assertEqual(expected, request.execute('', None))
261
def test_destroy_branch_named(self):
262
"""A named branch can be removed."""
263
backing = self.get_transport()
264
dir = self.make_repository('.', format="development-colo").bzrdir
265
dir.create_branch(name="branchname")
266
request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
267
request = request_class(backing)
268
expected = smart_req.SuccessfulSmartServerResponse(('ok',))
269
self.assertEqual(expected, request.execute('', "branchname"))
271
def test_destroy_branch_missing(self):
272
"""An error is raised if the branch didn't exist."""
273
backing = self.get_transport()
274
dir = self.make_bzrdir('.', format="development-colo")
275
request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
276
request = request_class(backing)
277
expected = smart_req.FailedSmartServerResponse(('nobranch',), None)
278
self.assertEqual(expected, request.execute('', "branchname"))
281
class TestSmartServerBzrDirRequestHasWorkingTree(
282
tests.TestCaseWithTransport):
283
"""Tests for BzrDir.has_workingtree."""
285
def test_has_workingtree_yes(self):
286
"""A working tree is present."""
287
backing = self.get_transport()
288
dir = self.make_branch_and_tree('.').bzrdir
289
request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
290
request = request_class(backing)
291
expected = smart_req.SuccessfulSmartServerResponse(('yes',))
292
self.assertEqual(expected, request.execute(''))
294
def test_has_workingtree_no(self):
295
"""A working tree is missing."""
296
backing = self.get_transport()
297
dir = self.make_bzrdir('.')
298
request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
299
request = request_class(backing)
300
expected = smart_req.SuccessfulSmartServerResponse(('no',))
301
self.assertEqual(expected, request.execute(''))
304
class TestSmartServerBzrDirRequestDestroyRepository(
305
tests.TestCaseWithMemoryTransport):
306
"""Tests for BzrDir.destroy_repository."""
308
def test_destroy_repository_default(self):
309
"""The repository can be removed."""
310
backing = self.get_transport()
311
dir = self.make_repository('.').bzrdir
312
request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
313
request = request_class(backing)
314
expected = smart_req.SuccessfulSmartServerResponse(('ok',))
315
self.assertEqual(expected, request.execute(''))
317
def test_destroy_repository_missing(self):
318
"""An error is raised if the repository didn't exist."""
319
backing = self.get_transport()
320
dir = self.make_bzrdir('.')
321
request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
322
request = request_class(backing)
323
expected = smart_req.FailedSmartServerResponse(
324
('norepository',), None)
325
self.assertEqual(expected, request.execute(''))
328
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
329
"""Tests for BzrDir.create_repository."""
331
def test_makes_repository(self):
332
"""When there is a bzrdir present, the call succeeds."""
333
backing = self.get_transport()
334
self.make_bzrdir('.')
335
request_class = smart_dir.SmartServerRequestCreateRepository
336
request = request_class(backing)
337
reference_bzrdir_format = controldir.format_registry.get('pack-0.92')()
338
reference_format = reference_bzrdir_format.repository_format
339
network_name = reference_format.network_name()
340
expected = smart_req.SuccessfulSmartServerResponse(
341
('ok', 'no', 'no', 'no', network_name))
342
self.assertEqual(expected, request.execute('', network_name, 'True'))
345
class TestSmartServerRequestFindRepository(tests.TestCaseWithMemoryTransport):
346
"""Tests for BzrDir.find_repository."""
348
def test_no_repository(self):
349
"""When there is no repository to be found, ('norepository', ) is returned."""
350
backing = self.get_transport()
351
request = self._request_class(backing)
352
self.make_bzrdir('.')
353
self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
356
def test_nonshared_repository(self):
357
# nonshared repositorys only allow 'find' to return a handle when the
358
# path the repository is being searched on is the same as that that
359
# the repository is at.
360
backing = self.get_transport()
361
request = self._request_class(backing)
362
result = self._make_repository_and_result()
363
self.assertEqual(result, request.execute(''))
364
self.make_bzrdir('subdir')
365
self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
366
request.execute('subdir'))
368
def _make_repository_and_result(self, shared=False, format=None):
369
"""Convenience function to setup a repository.
371
:result: The SmartServerResponse to expect when opening it.
373
repo = self.make_repository('.', shared=shared, format=format)
374
if repo.supports_rich_root():
378
if repo._format.supports_tree_reference:
382
if repo._format.supports_external_lookups:
386
if (smart_dir.SmartServerRequestFindRepositoryV3 ==
387
self._request_class):
388
return smart_req.SuccessfulSmartServerResponse(
389
('ok', '', rich_root, subtrees, external,
390
repo._format.network_name()))
391
elif (smart_dir.SmartServerRequestFindRepositoryV2 ==
392
self._request_class):
393
# All tests so far are on formats, and for non-external
395
return smart_req.SuccessfulSmartServerResponse(
396
('ok', '', rich_root, subtrees, external))
398
return smart_req.SuccessfulSmartServerResponse(
399
('ok', '', rich_root, subtrees))
401
def test_shared_repository(self):
402
"""When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
403
backing = self.get_transport()
404
request = self._request_class(backing)
405
result = self._make_repository_and_result(shared=True)
406
self.assertEqual(result, request.execute(''))
407
self.make_bzrdir('subdir')
408
result2 = smart_req.SmartServerResponse(
409
result.args[0:1] + ('..', ) + result.args[2:])
410
self.assertEqual(result2,
411
request.execute('subdir'))
412
self.make_bzrdir('subdir/deeper')
413
result3 = smart_req.SmartServerResponse(
414
result.args[0:1] + ('../..', ) + result.args[2:])
415
self.assertEqual(result3,
416
request.execute('subdir/deeper'))
418
def test_rich_root_and_subtree_encoding(self):
419
"""Test for the format attributes for rich root and subtree support."""
420
backing = self.get_transport()
421
request = self._request_class(backing)
422
result = self._make_repository_and_result(
423
format='development-subtree')
424
# check the test will be valid
425
self.assertEqual('yes', result.args[2])
426
self.assertEqual('yes', result.args[3])
427
self.assertEqual(result, request.execute(''))
429
def test_supports_external_lookups_no_v2(self):
430
"""Test for the supports_external_lookups attribute."""
431
backing = self.get_transport()
432
request = self._request_class(backing)
433
result = self._make_repository_and_result(
434
format='development-subtree')
435
# check the test will be valid
436
self.assertEqual('yes', result.args[4])
437
self.assertEqual(result, request.execute(''))
440
class TestSmartServerBzrDirRequestGetConfigFile(
441
tests.TestCaseWithMemoryTransport):
442
"""Tests for BzrDir.get_config_file."""
444
def test_present(self):
445
backing = self.get_transport()
446
dir = self.make_bzrdir('.')
447
dir.get_config().set_default_stack_on("/")
448
local_result = dir._get_config()._get_config_file().read()
449
request_class = smart_dir.SmartServerBzrDirRequestConfigFile
450
request = request_class(backing)
451
expected = smart_req.SuccessfulSmartServerResponse((), local_result)
452
self.assertEqual(expected, request.execute(''))
454
def test_missing(self):
455
backing = self.get_transport()
456
dir = self.make_bzrdir('.')
457
request_class = smart_dir.SmartServerBzrDirRequestConfigFile
458
request = request_class(backing)
459
expected = smart_req.SuccessfulSmartServerResponse((), '')
460
self.assertEqual(expected, request.execute(''))
463
class TestSmartServerBzrDirRequestGetBranches(
464
tests.TestCaseWithMemoryTransport):
465
"""Tests for BzrDir.get_branches."""
467
def test_simple(self):
468
backing = self.get_transport()
469
branch = self.make_branch('.')
470
request_class = smart_dir.SmartServerBzrDirRequestGetBranches
471
request = request_class(backing)
472
local_result = bencode.bencode(
473
{"": ("branch", branch._format.network_name())})
474
expected = smart_req.SuccessfulSmartServerResponse(
475
("success", ), local_result)
476
self.assertEqual(expected, request.execute(''))
478
def test_empty(self):
479
backing = self.get_transport()
480
dir = self.make_bzrdir('.')
481
request_class = smart_dir.SmartServerBzrDirRequestGetBranches
482
request = request_class(backing)
483
local_result = bencode.bencode({})
484
expected = smart_req.SuccessfulSmartServerResponse(
485
('success',), local_result)
486
self.assertEqual(expected, request.execute(''))
489
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithMemoryTransport):
491
def test_empty_dir(self):
492
"""Initializing an empty dir should succeed and do it."""
493
backing = self.get_transport()
494
request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
495
self.assertEqual(smart_req.SmartServerResponse(('ok', )),
497
made_dir = controldir.ControlDir.open_from_transport(backing)
498
# no branch, tree or repository is expected with the current
500
self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
501
self.assertRaises(errors.NotBranchError, made_dir.open_branch)
502
self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
504
def test_missing_dir(self):
505
"""Initializing a missing directory should fail like the bzrdir api."""
506
backing = self.get_transport()
507
request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
508
self.assertRaises(errors.NoSuchFile,
509
request.execute, 'subdir')
511
def test_initialized_dir(self):
512
"""Initializing an extant bzrdir should fail like the bzrdir api."""
513
backing = self.get_transport()
514
request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
515
self.make_bzrdir('subdir')
516
self.assertRaises(errors.AlreadyControlDirError,
517
request.execute, 'subdir')
520
class TestSmartServerRequestBzrDirInitializeEx(
521
tests.TestCaseWithMemoryTransport):
522
"""Basic tests for BzrDir.initialize_ex_1.16 in the smart server.
524
The main unit tests in test_bzrdir exercise the API comprehensively.
527
def test_empty_dir(self):
528
"""Initializing an empty dir should succeed and do it."""
529
backing = self.get_transport()
530
name = self.make_bzrdir('reference')._format.network_name()
531
request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
533
smart_req.SmartServerResponse(('', '', '', '', '', '', name,
534
'False', '', '', '')),
535
request.execute(name, '', 'True', 'False', 'False', '', '', '', '',
537
made_dir = controldir.ControlDir.open_from_transport(backing)
538
# no branch, tree or repository is expected with the current
540
self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
541
self.assertRaises(errors.NotBranchError, made_dir.open_branch)
542
self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
544
def test_missing_dir(self):
545
"""Initializing a missing directory should fail like the bzrdir api."""
546
backing = self.get_transport()
547
name = self.make_bzrdir('reference')._format.network_name()
548
request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
549
self.assertRaises(errors.NoSuchFile, request.execute, name,
550
'subdir/dir', 'False', 'False', 'False', '', '', '', '', 'False')
552
def test_initialized_dir(self):
553
"""Initializing an extant directory should fail like the bzrdir api."""
554
backing = self.get_transport()
555
name = self.make_bzrdir('reference')._format.network_name()
556
request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
557
self.make_bzrdir('subdir')
558
self.assertRaises(errors.FileExists, request.execute, name, 'subdir',
559
'False', 'False', 'False', '', '', '', '', 'False')
562
class TestSmartServerRequestOpenBzrDir(tests.TestCaseWithMemoryTransport):
564
def test_no_directory(self):
565
backing = self.get_transport()
566
request = smart_dir.SmartServerRequestOpenBzrDir(backing)
567
self.assertEqual(smart_req.SmartServerResponse(('no', )),
568
request.execute('does-not-exist'))
570
def test_empty_directory(self):
571
backing = self.get_transport()
572
backing.mkdir('empty')
573
request = smart_dir.SmartServerRequestOpenBzrDir(backing)
574
self.assertEqual(smart_req.SmartServerResponse(('no', )),
575
request.execute('empty'))
577
def test_outside_root_client_path(self):
578
backing = self.get_transport()
579
request = smart_dir.SmartServerRequestOpenBzrDir(backing,
580
root_client_path='root')
581
self.assertEqual(smart_req.SmartServerResponse(('no', )),
582
request.execute('not-root'))
585
class TestSmartServerRequestOpenBzrDir_2_1(tests.TestCaseWithMemoryTransport):
587
def test_no_directory(self):
588
backing = self.get_transport()
589
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
590
self.assertEqual(smart_req.SmartServerResponse(('no', )),
591
request.execute('does-not-exist'))
593
def test_empty_directory(self):
594
backing = self.get_transport()
595
backing.mkdir('empty')
596
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
597
self.assertEqual(smart_req.SmartServerResponse(('no', )),
598
request.execute('empty'))
600
def test_present_without_workingtree(self):
601
backing = self.get_transport()
602
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
603
self.make_bzrdir('.')
604
self.assertEqual(smart_req.SmartServerResponse(('yes', 'no')),
607
def test_outside_root_client_path(self):
608
backing = self.get_transport()
609
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing,
610
root_client_path='root')
611
self.assertEqual(smart_req.SmartServerResponse(('no',)),
612
request.execute('not-root'))
615
class TestSmartServerRequestOpenBzrDir_2_1_disk(TestCaseWithChrootedTransport):
617
def test_present_with_workingtree(self):
618
self.vfs_transport_factory = test_server.LocalURLServer
619
backing = self.get_transport()
620
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
621
bd = self.make_bzrdir('.')
622
bd.create_repository()
624
bd.create_workingtree()
625
self.assertEqual(smart_req.SmartServerResponse(('yes', 'yes')),
629
class TestSmartServerRequestOpenBranch(TestCaseWithChrootedTransport):
631
def test_no_branch(self):
632
"""When there is no branch, ('nobranch', ) is returned."""
633
backing = self.get_transport()
634
request = smart_dir.SmartServerRequestOpenBranch(backing)
635
self.make_bzrdir('.')
636
self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
639
def test_branch(self):
640
"""When there is a branch, 'ok' is returned."""
641
backing = self.get_transport()
642
request = smart_dir.SmartServerRequestOpenBranch(backing)
643
self.make_branch('.')
644
self.assertEqual(smart_req.SmartServerResponse(('ok', '')),
647
def test_branch_reference(self):
648
"""When there is a branch reference, the reference URL is returned."""
649
self.vfs_transport_factory = test_server.LocalURLServer
650
backing = self.get_transport()
651
request = smart_dir.SmartServerRequestOpenBranch(backing)
652
branch = self.make_branch('branch')
653
checkout = branch.create_checkout('reference',lightweight=True)
654
reference_url = _mod_bzrbranch.BranchReferenceFormat().get_reference(
656
self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
657
self.assertEqual(smart_req.SmartServerResponse(('ok', reference_url)),
658
request.execute('reference'))
660
def test_notification_on_branch_from_repository(self):
661
"""When there is a repository, the error should return details."""
662
backing = self.get_transport()
663
request = smart_dir.SmartServerRequestOpenBranch(backing)
664
repo = self.make_repository('.')
665
self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
669
class TestSmartServerRequestOpenBranchV2(TestCaseWithChrootedTransport):
671
def test_no_branch(self):
672
"""When there is no branch, ('nobranch', ) is returned."""
673
backing = self.get_transport()
674
self.make_bzrdir('.')
675
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
676
self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
679
def test_branch(self):
680
"""When there is a branch, 'ok' is returned."""
681
backing = self.get_transport()
682
expected = self.make_branch('.')._format.network_name()
683
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
684
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
685
('branch', expected)),
688
def test_branch_reference(self):
689
"""When there is a branch reference, the reference URL is returned."""
690
self.vfs_transport_factory = test_server.LocalURLServer
691
backing = self.get_transport()
692
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
693
branch = self.make_branch('branch')
694
checkout = branch.create_checkout('reference',lightweight=True)
695
reference_url = _mod_bzrbranch.BranchReferenceFormat().get_reference(
697
self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
698
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
699
('ref', reference_url)),
700
request.execute('reference'))
702
def test_stacked_branch(self):
703
"""Opening a stacked branch does not open the stacked-on branch."""
704
trunk = self.make_branch('trunk')
705
feature = self.make_branch('feature')
706
feature.set_stacked_on_url(trunk.base)
708
_mod_branch.Branch.hooks.install_named_hook(
709
'open', opened_branches.append, None)
710
backing = self.get_transport()
711
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
714
response = request.execute('feature')
716
request.teardown_jail()
717
expected_format = feature._format.network_name()
718
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
719
('branch', expected_format)),
721
self.assertLength(1, opened_branches)
723
def test_notification_on_branch_from_repository(self):
724
"""When there is a repository, the error should return details."""
725
backing = self.get_transport()
726
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
727
repo = self.make_repository('.')
728
self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
732
class TestSmartServerRequestOpenBranchV3(TestCaseWithChrootedTransport):
734
def test_no_branch(self):
735
"""When there is no branch, ('nobranch', ) is returned."""
736
backing = self.get_transport()
737
self.make_bzrdir('.')
738
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
739
self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
742
def test_branch(self):
743
"""When there is a branch, 'ok' is returned."""
744
backing = self.get_transport()
745
expected = self.make_branch('.')._format.network_name()
746
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
747
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
748
('branch', expected)),
751
def test_branch_reference(self):
752
"""When there is a branch reference, the reference URL is returned."""
753
self.vfs_transport_factory = test_server.LocalURLServer
754
backing = self.get_transport()
755
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
756
branch = self.make_branch('branch')
757
checkout = branch.create_checkout('reference',lightweight=True)
758
reference_url = _mod_bzrbranch.BranchReferenceFormat().get_reference(
760
self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
761
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
762
('ref', reference_url)),
763
request.execute('reference'))
765
def test_stacked_branch(self):
766
"""Opening a stacked branch does not open the stacked-on branch."""
767
trunk = self.make_branch('trunk')
768
feature = self.make_branch('feature')
769
feature.set_stacked_on_url(trunk.base)
771
_mod_branch.Branch.hooks.install_named_hook(
772
'open', opened_branches.append, None)
773
backing = self.get_transport()
774
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
777
response = request.execute('feature')
779
request.teardown_jail()
780
expected_format = feature._format.network_name()
781
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
782
('branch', expected_format)),
784
self.assertLength(1, opened_branches)
786
def test_notification_on_branch_from_repository(self):
787
"""When there is a repository, the error should return details."""
788
backing = self.get_transport()
789
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
790
repo = self.make_repository('.')
791
self.assertEqual(smart_req.SmartServerResponse(
792
('nobranch', 'location is a repository')),
796
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
798
def test_empty(self):
799
"""For an empty branch, the body is empty."""
800
backing = self.get_transport()
801
request = smart_branch.SmartServerRequestRevisionHistory(backing)
802
self.make_branch('.')
803
self.assertEqual(smart_req.SmartServerResponse(('ok', ), ''),
806
def test_not_empty(self):
807
"""For a non-empty branch, the body is empty."""
808
backing = self.get_transport()
809
request = smart_branch.SmartServerRequestRevisionHistory(backing)
810
tree = self.make_branch_and_memory_tree('.')
813
r1 = tree.commit('1st commit')
814
r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
817
smart_req.SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
821
class TestSmartServerBranchRequest(tests.TestCaseWithMemoryTransport):
823
def test_no_branch(self):
824
"""When there is a bzrdir and no branch, NotBranchError is raised."""
825
backing = self.get_transport()
826
request = smart_branch.SmartServerBranchRequest(backing)
827
self.make_bzrdir('.')
828
self.assertRaises(errors.NotBranchError,
831
def test_branch_reference(self):
832
"""When there is a branch reference, NotBranchError is raised."""
833
backing = self.get_transport()
834
request = smart_branch.SmartServerBranchRequest(backing)
835
branch = self.make_branch('branch')
836
checkout = branch.create_checkout('reference',lightweight=True)
837
self.assertRaises(errors.NotBranchError,
838
request.execute, 'checkout')
841
class TestSmartServerBranchRequestLastRevisionInfo(
842
tests.TestCaseWithMemoryTransport):
844
def test_empty(self):
845
"""For an empty branch, the result is ('ok', '0', 'null:')."""
846
backing = self.get_transport()
847
request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
848
self.make_branch('.')
849
self.assertEqual(smart_req.SmartServerResponse(('ok', '0', 'null:')),
852
def test_not_empty(self):
853
"""For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
854
backing = self.get_transport()
855
request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
856
tree = self.make_branch_and_memory_tree('.')
859
rev_id_utf8 = u'\xc8'.encode('utf-8')
860
r1 = tree.commit('1st commit')
861
r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
864
smart_req.SmartServerResponse(('ok', '2', rev_id_utf8)),
868
class TestSmartServerBranchRequestRevisionIdToRevno(
869
tests.TestCaseWithMemoryTransport):
872
backing = self.get_transport()
873
request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
875
self.make_branch('.')
876
self.assertEqual(smart_req.SmartServerResponse(('ok', '0')),
877
request.execute('', 'null:'))
879
def test_simple(self):
880
backing = self.get_transport()
881
request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
883
tree = self.make_branch_and_memory_tree('.')
886
r1 = tree.commit('1st commit')
889
smart_req.SmartServerResponse(('ok', '1')),
890
request.execute('', r1))
892
def test_not_found(self):
893
backing = self.get_transport()
894
request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
896
branch = self.make_branch('.')
898
smart_req.FailedSmartServerResponse(
899
('NoSuchRevision', 'idontexist')),
900
request.execute('', 'idontexist'))
903
class TestSmartServerBranchRequestGetConfigFile(
904
tests.TestCaseWithMemoryTransport):
906
def test_default(self):
907
"""With no file, we get empty content."""
908
backing = self.get_transport()
909
request = smart_branch.SmartServerBranchGetConfigFile(backing)
910
branch = self.make_branch('.')
911
# there should be no file by default
913
self.assertEqual(smart_req.SmartServerResponse(('ok', ), content),
916
def test_with_content(self):
917
# SmartServerBranchGetConfigFile should return the content from
918
# branch.control_files.get('branch.conf') for now - in the future it may
919
# perform more complex processing.
920
backing = self.get_transport()
921
request = smart_branch.SmartServerBranchGetConfigFile(backing)
922
branch = self.make_branch('.')
923
branch._transport.put_bytes('branch.conf', 'foo bar baz')
924
self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'foo bar baz'),
928
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
930
def get_lock_tokens(self, branch):
931
branch_token = branch.lock_write().branch_token
932
repo_token = branch.repository.lock_write().repository_token
933
branch.repository.unlock()
934
return branch_token, repo_token
937
class TestSmartServerBranchRequestPutConfigFile(TestLockedBranch):
939
def test_with_content(self):
940
backing = self.get_transport()
941
request = smart_branch.SmartServerBranchPutConfigFile(backing)
942
branch = self.make_branch('.')
943
branch_token, repo_token = self.get_lock_tokens(branch)
944
self.assertIs(None, request.execute('', branch_token, repo_token))
946
smart_req.SmartServerResponse(('ok', )),
947
request.do_body('foo bar baz'))
949
branch.control_transport.get_bytes('branch.conf'),
954
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
956
def test_value_name(self):
957
branch = self.make_branch('.')
958
request = smart_branch.SmartServerBranchRequestSetConfigOption(
959
branch.bzrdir.root_transport)
960
branch_token, repo_token = self.get_lock_tokens(branch)
961
config = branch._get_config()
962
result = request.execute('', branch_token, repo_token, 'bar', 'foo',
964
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
965
self.assertEqual('bar', config.get_option('foo'))
969
def test_value_name_section(self):
970
branch = self.make_branch('.')
971
request = smart_branch.SmartServerBranchRequestSetConfigOption(
972
branch.bzrdir.root_transport)
973
branch_token, repo_token = self.get_lock_tokens(branch)
974
config = branch._get_config()
975
result = request.execute('', branch_token, repo_token, 'bar', 'foo',
977
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
978
self.assertEqual('bar', config.get_option('foo', 'gam'))
983
class TestSmartServerBranchRequestSetConfigOptionDict(TestLockedBranch):
986
TestLockedBranch.setUp(self)
987
# A dict with non-ascii keys and values to exercise unicode
989
self.encoded_value_dict = (
990
'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde')
992
'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
994
def test_value_name(self):
995
branch = self.make_branch('.')
996
request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
997
branch.bzrdir.root_transport)
998
branch_token, repo_token = self.get_lock_tokens(branch)
999
config = branch._get_config()
1000
result = request.execute('', branch_token, repo_token,
1001
self.encoded_value_dict, 'foo', '')
1002
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
1003
self.assertEqual(self.value_dict, config.get_option('foo'))
1007
def test_value_name_section(self):
1008
branch = self.make_branch('.')
1009
request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
1010
branch.bzrdir.root_transport)
1011
branch_token, repo_token = self.get_lock_tokens(branch)
1012
config = branch._get_config()
1013
result = request.execute('', branch_token, repo_token,
1014
self.encoded_value_dict, 'foo', 'gam')
1015
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
1016
self.assertEqual(self.value_dict, config.get_option('foo', 'gam'))
1021
class TestSmartServerBranchRequestSetTagsBytes(TestLockedBranch):
1022
# Only called when the branch format and tags match [yay factory
1023
# methods] so only need to test straight forward cases.
1025
def test_set_bytes(self):
1026
base_branch = self.make_branch('base')
1027
tag_bytes = base_branch._get_tags_bytes()
1028
# get_lock_tokens takes out a lock.
1029
branch_token, repo_token = self.get_lock_tokens(base_branch)
1030
request = smart_branch.SmartServerBranchSetTagsBytes(
1031
self.get_transport())
1032
response = request.execute('base', branch_token, repo_token)
1033
self.assertEqual(None, response)
1034
response = request.do_chunk(tag_bytes)
1035
self.assertEqual(None, response)
1036
response = request.do_end()
1038
smart_req.SuccessfulSmartServerResponse(()), response)
1039
base_branch.unlock()
1041
def test_lock_failed(self):
1042
base_branch = self.make_branch('base')
1043
base_branch.lock_write()
1044
tag_bytes = base_branch._get_tags_bytes()
1045
request = smart_branch.SmartServerBranchSetTagsBytes(
1046
self.get_transport())
1047
self.assertRaises(errors.TokenMismatch, request.execute,
1048
'base', 'wrong token', 'wrong token')
1049
# The request handler will keep processing the message parts, so even
1050
# if the request fails immediately do_chunk and do_end are still
1052
request.do_chunk(tag_bytes)
1054
base_branch.unlock()
1058
class SetLastRevisionTestBase(TestLockedBranch):
1059
"""Base test case for verbs that implement set_last_revision."""
1062
super(SetLastRevisionTestBase, self).setUp()
1063
backing_transport = self.get_transport()
1064
self.request = self.request_class(backing_transport)
1065
self.tree = self.make_branch_and_memory_tree('.')
1067
def lock_branch(self):
1068
return self.get_lock_tokens(self.tree.branch)
1070
def unlock_branch(self):
1071
self.tree.branch.unlock()
1073
def set_last_revision(self, revision_id, revno):
1074
branch_token, repo_token = self.lock_branch()
1075
response = self._set_last_revision(
1076
revision_id, revno, branch_token, repo_token)
1077
self.unlock_branch()
1080
def assertRequestSucceeds(self, revision_id, revno):
1081
response = self.set_last_revision(revision_id, revno)
1082
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
1086
class TestSetLastRevisionVerbMixin(object):
1087
"""Mixin test case for verbs that implement set_last_revision."""
1089
def test_set_null_to_null(self):
1090
"""An empty branch can have its last revision set to 'null:'."""
1091
self.assertRequestSucceeds('null:', 0)
1093
def test_NoSuchRevision(self):
1094
"""If the revision_id is not present, the verb returns NoSuchRevision.
1096
revision_id = 'non-existent revision'
1097
self.assertEqual(smart_req.FailedSmartServerResponse(('NoSuchRevision',
1099
self.set_last_revision(revision_id, 1))
1101
def make_tree_with_two_commits(self):
1102
self.tree.lock_write()
1104
rev_id_utf8 = u'\xc8'.encode('utf-8')
1105
r1 = self.tree.commit('1st commit', rev_id=rev_id_utf8)
1106
r2 = self.tree.commit('2nd commit', rev_id='rev-2')
1109
def test_branch_last_revision_info_is_updated(self):
1110
"""A branch's tip can be set to a revision that is present in its
1113
# Make a branch with an empty revision history, but two revisions in
1115
self.make_tree_with_two_commits()
1116
rev_id_utf8 = u'\xc8'.encode('utf-8')
1117
self.tree.branch.set_last_revision_info(0, 'null:')
1119
(0, 'null:'), self.tree.branch.last_revision_info())
1120
# We can update the branch to a revision that is present in the
1122
self.assertRequestSucceeds(rev_id_utf8, 1)
1124
(1, rev_id_utf8), self.tree.branch.last_revision_info())
1126
def test_branch_last_revision_info_rewind(self):
1127
"""A branch's tip can be set to a revision that is an ancestor of the
1130
self.make_tree_with_two_commits()
1131
rev_id_utf8 = u'\xc8'.encode('utf-8')
1133
(2, 'rev-2'), self.tree.branch.last_revision_info())
1134
self.assertRequestSucceeds(rev_id_utf8, 1)
1136
(1, rev_id_utf8), self.tree.branch.last_revision_info())
1138
def test_TipChangeRejected(self):
1139
"""If a pre_change_branch_tip hook raises TipChangeRejected, the verb
1140
returns TipChangeRejected.
1142
rejection_message = u'rejection message\N{INTERROBANG}'
1143
def hook_that_rejects(params):
1144
raise errors.TipChangeRejected(rejection_message)
1145
_mod_branch.Branch.hooks.install_named_hook(
1146
'pre_change_branch_tip', hook_that_rejects, None)
1148
smart_req.FailedSmartServerResponse(
1149
('TipChangeRejected', rejection_message.encode('utf-8'))),
1150
self.set_last_revision('null:', 0))
1153
class TestSmartServerBranchRequestSetLastRevision(
1154
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
1155
"""Tests for Branch.set_last_revision verb."""
1157
request_class = smart_branch.SmartServerBranchRequestSetLastRevision
1159
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
1160
return self.request.execute(
1161
'', branch_token, repo_token, revision_id)
1164
class TestSmartServerBranchRequestSetLastRevisionInfo(
1165
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
1166
"""Tests for Branch.set_last_revision_info verb."""
1168
request_class = smart_branch.SmartServerBranchRequestSetLastRevisionInfo
1170
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
1171
return self.request.execute(
1172
'', branch_token, repo_token, revno, revision_id)
1174
def test_NoSuchRevision(self):
1175
"""Branch.set_last_revision_info does not have to return
1176
NoSuchRevision if the revision_id is absent.
1178
raise tests.TestNotApplicable()
1181
class TestSmartServerBranchRequestSetLastRevisionEx(
1182
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
1183
"""Tests for Branch.set_last_revision_ex verb."""
1185
request_class = smart_branch.SmartServerBranchRequestSetLastRevisionEx
1187
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
1188
return self.request.execute(
1189
'', branch_token, repo_token, revision_id, 0, 0)
1191
def assertRequestSucceeds(self, revision_id, revno):
1192
response = self.set_last_revision(revision_id, revno)
1194
smart_req.SuccessfulSmartServerResponse(('ok', revno, revision_id)),
1197
def test_branch_last_revision_info_rewind(self):
1198
"""A branch's tip can be set to a revision that is an ancestor of the
1199
current tip, but only if allow_overwrite_descendant is passed.
1201
self.make_tree_with_two_commits()
1202
rev_id_utf8 = u'\xc8'.encode('utf-8')
1204
(2, 'rev-2'), self.tree.branch.last_revision_info())
1205
# If allow_overwrite_descendant flag is 0, then trying to set the tip
1206
# to an older revision ID has no effect.
1207
branch_token, repo_token = self.lock_branch()
1208
response = self.request.execute(
1209
'', branch_token, repo_token, rev_id_utf8, 0, 0)
1211
smart_req.SuccessfulSmartServerResponse(('ok', 2, 'rev-2')),
1214
(2, 'rev-2'), self.tree.branch.last_revision_info())
1216
# If allow_overwrite_descendant flag is 1, then setting the tip to an
1218
response = self.request.execute(
1219
'', branch_token, repo_token, rev_id_utf8, 0, 1)
1221
smart_req.SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)),
1223
self.unlock_branch()
1225
(1, rev_id_utf8), self.tree.branch.last_revision_info())
1227
def make_branch_with_divergent_history(self):
1228
"""Make a branch with divergent history in its repo.
1230
The branch's tip will be 'child-2', and the repo will also contain
1231
'child-1', which diverges from a common base revision.
1233
self.tree.lock_write()
1235
r1 = self.tree.commit('1st commit')
1236
revno_1, revid_1 = self.tree.branch.last_revision_info()
1237
r2 = self.tree.commit('2nd commit', rev_id='child-1')
1238
# Undo the second commit
1239
self.tree.branch.set_last_revision_info(revno_1, revid_1)
1240
self.tree.set_parent_ids([revid_1])
1241
# Make a new second commit, child-2. child-2 has diverged from
1243
new_r2 = self.tree.commit('2nd commit', rev_id='child-2')
1246
def test_not_allow_diverged(self):
1247
"""If allow_diverged is not passed, then setting a divergent history
1248
returns a Diverged error.
1250
self.make_branch_with_divergent_history()
1252
smart_req.FailedSmartServerResponse(('Diverged',)),
1253
self.set_last_revision('child-1', 2))
1254
# The branch tip was not changed.
1255
self.assertEqual('child-2', self.tree.branch.last_revision())
1257
def test_allow_diverged(self):
1258
"""If allow_diverged is passed, then setting a divergent history
1261
self.make_branch_with_divergent_history()
1262
branch_token, repo_token = self.lock_branch()
1263
response = self.request.execute(
1264
'', branch_token, repo_token, 'child-1', 1, 0)
1266
smart_req.SuccessfulSmartServerResponse(('ok', 2, 'child-1')),
1268
self.unlock_branch()
1269
# The branch tip was changed.
1270
self.assertEqual('child-1', self.tree.branch.last_revision())
1273
class TestSmartServerBranchBreakLock(tests.TestCaseWithMemoryTransport):
1275
def test_lock_to_break(self):
1276
base_branch = self.make_branch('base')
1277
request = smart_branch.SmartServerBranchBreakLock(
1278
self.get_transport())
1279
base_branch.lock_write()
1281
smart_req.SuccessfulSmartServerResponse(('ok', ), None),
1282
request.execute('base'))
1284
def test_nothing_to_break(self):
1285
base_branch = self.make_branch('base')
1286
request = smart_branch.SmartServerBranchBreakLock(
1287
self.get_transport())
1289
smart_req.SuccessfulSmartServerResponse(('ok', ), None),
1290
request.execute('base'))
1293
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
1295
def test_get_parent_none(self):
1296
base_branch = self.make_branch('base')
1297
request = smart_branch.SmartServerBranchGetParent(self.get_transport())
1298
response = request.execute('base')
1300
smart_req.SuccessfulSmartServerResponse(('',)), response)
1302
def test_get_parent_something(self):
1303
base_branch = self.make_branch('base')
1304
base_branch.set_parent(self.get_url('foo'))
1305
request = smart_branch.SmartServerBranchGetParent(self.get_transport())
1306
response = request.execute('base')
1308
smart_req.SuccessfulSmartServerResponse(("../foo",)),
1312
class TestSmartServerBranchRequestSetParent(TestLockedBranch):
1314
def test_set_parent_none(self):
1315
branch = self.make_branch('base', format="1.9")
1317
branch._set_parent_location('foo')
1319
request = smart_branch.SmartServerBranchRequestSetParentLocation(
1320
self.get_transport())
1321
branch_token, repo_token = self.get_lock_tokens(branch)
1323
response = request.execute('base', branch_token, repo_token, '')
1326
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
1327
# Refresh branch as SetParentLocation modified it
1328
branch = branch.bzrdir.open_branch()
1329
self.assertEqual(None, branch.get_parent())
1331
def test_set_parent_something(self):
1332
branch = self.make_branch('base', format="1.9")
1333
request = smart_branch.SmartServerBranchRequestSetParentLocation(
1334
self.get_transport())
1335
branch_token, repo_token = self.get_lock_tokens(branch)
1337
response = request.execute('base', branch_token, repo_token,
1341
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
1342
refreshed = _mod_branch.Branch.open(branch.base)
1343
self.assertEqual('http://bar/', refreshed.get_parent())
1346
class TestSmartServerBranchRequestGetTagsBytes(
1347
tests.TestCaseWithMemoryTransport):
1348
# Only called when the branch format and tags match [yay factory
1349
# methods] so only need to test straight forward cases.
1351
def test_get_bytes(self):
1352
base_branch = self.make_branch('base')
1353
request = smart_branch.SmartServerBranchGetTagsBytes(
1354
self.get_transport())
1355
response = request.execute('base')
1357
smart_req.SuccessfulSmartServerResponse(('',)), response)
1360
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
1362
def test_get_stacked_on_url(self):
1363
base_branch = self.make_branch('base', format='1.6')
1364
stacked_branch = self.make_branch('stacked', format='1.6')
1365
# typically should be relative
1366
stacked_branch.set_stacked_on_url('../base')
1367
request = smart_branch.SmartServerBranchRequestGetStackedOnURL(
1368
self.get_transport())
1369
response = request.execute('stacked')
1371
smart_req.SmartServerResponse(('ok', '../base')),
1375
class TestSmartServerBranchRequestLockWrite(TestLockedBranch):
1377
def test_lock_write_on_unlocked_branch(self):
1378
backing = self.get_transport()
1379
request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1380
branch = self.make_branch('.', format='knit')
1381
repository = branch.repository
1382
response = request.execute('')
1383
branch_nonce = branch.control_files._lock.peek().get('nonce')
1384
repository_nonce = repository.control_files._lock.peek().get('nonce')
1385
self.assertEqual(smart_req.SmartServerResponse(
1386
('ok', branch_nonce, repository_nonce)),
1388
# The branch (and associated repository) is now locked. Verify that
1389
# with a new branch object.
1390
new_branch = repository.bzrdir.open_branch()
1391
self.assertRaises(errors.LockContention, new_branch.lock_write)
1393
request = smart_branch.SmartServerBranchRequestUnlock(backing)
1394
response = request.execute('', branch_nonce, repository_nonce)
1396
def test_lock_write_on_locked_branch(self):
1397
backing = self.get_transport()
1398
request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1399
branch = self.make_branch('.')
1400
branch_token = branch.lock_write().branch_token
1401
branch.leave_lock_in_place()
1403
response = request.execute('')
1405
smart_req.SmartServerResponse(('LockContention',)), response)
1407
branch.lock_write(branch_token)
1408
branch.dont_leave_lock_in_place()
1411
def test_lock_write_with_tokens_on_locked_branch(self):
1412
backing = self.get_transport()
1413
request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1414
branch = self.make_branch('.', format='knit')
1415
branch_token, repo_token = self.get_lock_tokens(branch)
1416
branch.leave_lock_in_place()
1417
branch.repository.leave_lock_in_place()
1419
response = request.execute('',
1420
branch_token, repo_token)
1422
smart_req.SmartServerResponse(('ok', branch_token, repo_token)),
1425
branch.repository.lock_write(repo_token)
1426
branch.repository.dont_leave_lock_in_place()
1427
branch.repository.unlock()
1428
branch.lock_write(branch_token)
1429
branch.dont_leave_lock_in_place()
1432
def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
1433
backing = self.get_transport()
1434
request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1435
branch = self.make_branch('.', format='knit')
1436
branch_token, repo_token = self.get_lock_tokens(branch)
1437
branch.leave_lock_in_place()
1438
branch.repository.leave_lock_in_place()
1440
response = request.execute('',
1441
branch_token+'xxx', repo_token)
1443
smart_req.SmartServerResponse(('TokenMismatch',)), response)
1445
branch.repository.lock_write(repo_token)
1446
branch.repository.dont_leave_lock_in_place()
1447
branch.repository.unlock()
1448
branch.lock_write(branch_token)
1449
branch.dont_leave_lock_in_place()
1452
def test_lock_write_on_locked_repo(self):
1453
backing = self.get_transport()
1454
request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1455
branch = self.make_branch('.', format='knit')
1456
repo = branch.repository
1457
repo_token = repo.lock_write().repository_token
1458
repo.leave_lock_in_place()
1460
response = request.execute('')
1462
smart_req.SmartServerResponse(('LockContention',)), response)
1464
repo.lock_write(repo_token)
1465
repo.dont_leave_lock_in_place()
1468
def test_lock_write_on_readonly_transport(self):
1469
backing = self.get_readonly_transport()
1470
request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1471
branch = self.make_branch('.')
1472
root = self.get_transport().clone('/')
1473
path = urlutils.relative_url(root.base, self.get_transport().base)
1474
response = request.execute(path)
1475
error_name, lock_str, why_str = response.args
1476
self.assertFalse(response.is_successful())
1477
self.assertEqual('LockFailed', error_name)
1480
class TestSmartServerBranchRequestGetPhysicalLockStatus(TestLockedBranch):
1482
def test_true(self):
1483
backing = self.get_transport()
1484
request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
1486
branch = self.make_branch('.')
1487
branch_token, repo_token = self.get_lock_tokens(branch)
1488
self.assertEqual(True, branch.get_physical_lock_status())
1489
response = request.execute('')
1491
smart_req.SmartServerResponse(('yes',)), response)
1494
def test_false(self):
1495
backing = self.get_transport()
1496
request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
1498
branch = self.make_branch('.')
1499
self.assertEqual(False, branch.get_physical_lock_status())
1500
response = request.execute('')
1502
smart_req.SmartServerResponse(('no',)), response)
1505
class TestSmartServerBranchRequestUnlock(TestLockedBranch):
1507
def test_unlock_on_locked_branch_and_repo(self):
1508
backing = self.get_transport()
1509
request = smart_branch.SmartServerBranchRequestUnlock(backing)
1510
branch = self.make_branch('.', format='knit')
1512
branch_token, repo_token = self.get_lock_tokens(branch)
1513
# Unlock the branch (and repo) object, leaving the physical locks
1515
branch.leave_lock_in_place()
1516
branch.repository.leave_lock_in_place()
1518
response = request.execute('',
1519
branch_token, repo_token)
1521
smart_req.SmartServerResponse(('ok',)), response)
1522
# The branch is now unlocked. Verify that with a new branch
1524
new_branch = branch.bzrdir.open_branch()
1525
new_branch.lock_write()
1528
def test_unlock_on_unlocked_branch_unlocked_repo(self):
1529
backing = self.get_transport()
1530
request = smart_branch.SmartServerBranchRequestUnlock(backing)
1531
branch = self.make_branch('.', format='knit')
1532
response = request.execute(
1533
'', 'branch token', 'repo token')
1535
smart_req.SmartServerResponse(('TokenMismatch',)), response)
1537
def test_unlock_on_unlocked_branch_locked_repo(self):
1538
backing = self.get_transport()
1539
request = smart_branch.SmartServerBranchRequestUnlock(backing)
1540
branch = self.make_branch('.', format='knit')
1541
# Lock the repository.
1542
repo_token = branch.repository.lock_write().repository_token
1543
branch.repository.leave_lock_in_place()
1544
branch.repository.unlock()
1545
# Issue branch lock_write request on the unlocked branch (with locked
1547
response = request.execute('', 'branch token', repo_token)
1549
smart_req.SmartServerResponse(('TokenMismatch',)), response)
1551
branch.repository.lock_write(repo_token)
1552
branch.repository.dont_leave_lock_in_place()
1553
branch.repository.unlock()
1556
class TestSmartServerRepositoryRequest(tests.TestCaseWithMemoryTransport):
1558
def test_no_repository(self):
1559
"""Raise NoRepositoryPresent when there is a bzrdir and no repo."""
1560
# we test this using a shared repository above the named path,
1561
# thus checking the right search logic is used - that is, that
1562
# its the exact path being looked at and the server is not
1564
backing = self.get_transport()
1565
request = smart_repo.SmartServerRepositoryRequest(backing)
1566
self.make_repository('.', shared=True)
1567
self.make_bzrdir('subdir')
1568
self.assertRaises(errors.NoRepositoryPresent,
1569
request.execute, 'subdir')
1572
class TestSmartServerRepositoryAddSignatureText(tests.TestCaseWithMemoryTransport):
1574
def test_add_text(self):
1575
backing = self.get_transport()
1576
request = smart_repo.SmartServerRepositoryAddSignatureText(backing)
1577
tree = self.make_branch_and_memory_tree('.')
1578
write_token = tree.lock_write()
1579
self.addCleanup(tree.unlock)
1581
tree.commit("Message", rev_id='rev1')
1582
tree.branch.repository.start_write_group()
1583
write_group_tokens = tree.branch.repository.suspend_write_group()
1584
self.assertEqual(None, request.execute('', write_token,
1585
'rev1', *write_group_tokens))
1586
response = request.do_body('somesignature')
1587
self.assertTrue(response.is_successful())
1588
self.assertEqual(response.args[0], 'ok')
1589
write_group_tokens = response.args[1:]
1590
tree.branch.repository.resume_write_group(write_group_tokens)
1591
tree.branch.repository.commit_write_group()
1593
self.assertEqual("somesignature",
1594
tree.branch.repository.get_signature_text("rev1"))
1597
class TestSmartServerRepositoryAllRevisionIds(
1598
tests.TestCaseWithMemoryTransport):
1600
def test_empty(self):
1601
"""An empty body should be returned for an empty repository."""
1602
backing = self.get_transport()
1603
request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
1604
self.make_repository('.')
1606
smart_req.SuccessfulSmartServerResponse(("ok", ), ""),
1607
request.execute(''))
1609
def test_some_revisions(self):
1610
"""An empty body should be returned for an empty repository."""
1611
backing = self.get_transport()
1612
request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
1613
tree = self.make_branch_and_memory_tree('.')
1616
tree.commit(rev_id='origineel', message="message")
1617
tree.commit(rev_id='nog-een-revisie', message="message")
1620
smart_req.SuccessfulSmartServerResponse(("ok", ),
1621
"origineel\nnog-een-revisie"),
1622
request.execute(''))
1625
class TestSmartServerRepositoryBreakLock(tests.TestCaseWithMemoryTransport):
1627
def test_lock_to_break(self):
1628
backing = self.get_transport()
1629
request = smart_repo.SmartServerRepositoryBreakLock(backing)
1630
tree = self.make_branch_and_memory_tree('.')
1631
tree.branch.repository.lock_write()
1633
smart_req.SuccessfulSmartServerResponse(('ok', ), None),
1634
request.execute(''))
1636
def test_nothing_to_break(self):
1637
backing = self.get_transport()
1638
request = smart_repo.SmartServerRepositoryBreakLock(backing)
1639
tree = self.make_branch_and_memory_tree('.')
1641
smart_req.SuccessfulSmartServerResponse(('ok', ), None),
1642
request.execute(''))
1645
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithMemoryTransport):
1647
def test_trivial_bzipped(self):
1648
# This tests that the wire encoding is actually bzipped
1649
backing = self.get_transport()
1650
request = smart_repo.SmartServerRepositoryGetParentMap(backing)
1651
tree = self.make_branch_and_memory_tree('.')
1653
self.assertEqual(None,
1654
request.execute('', 'missing-id'))
1655
# Note that it returns a body that is bzipped.
1657
smart_req.SuccessfulSmartServerResponse(('ok', ), bz2.compress('')),
1658
request.do_body('\n\n0\n'))
1660
def test_trivial_include_missing(self):
1661
backing = self.get_transport()
1662
request = smart_repo.SmartServerRepositoryGetParentMap(backing)
1663
tree = self.make_branch_and_memory_tree('.')
1665
self.assertEqual(None,
1666
request.execute('', 'missing-id', 'include-missing:'))
1668
smart_req.SuccessfulSmartServerResponse(('ok', ),
1669
bz2.compress('missing:missing-id')),
1670
request.do_body('\n\n0\n'))
1673
class TestSmartServerRepositoryGetRevisionGraph(
1674
tests.TestCaseWithMemoryTransport):
1676
def test_none_argument(self):
1677
backing = self.get_transport()
1678
request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
1679
tree = self.make_branch_and_memory_tree('.')
1682
r1 = tree.commit('1st commit')
1683
r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
1686
# the lines of revision_id->revision_parent_list has no guaranteed
1687
# order coming out of a dict, so sort both our test and response
1688
lines = sorted([' '.join([r2, r1]), r1])
1689
response = request.execute('', '')
1690
response.body = '\n'.join(sorted(response.body.split('\n')))
1693
smart_req.SmartServerResponse(('ok', ), '\n'.join(lines)), response)
1695
def test_specific_revision_argument(self):
1696
backing = self.get_transport()
1697
request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
1698
tree = self.make_branch_and_memory_tree('.')
1701
rev_id_utf8 = u'\xc9'.encode('utf-8')
1702
r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
1703
r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
1706
self.assertEqual(smart_req.SmartServerResponse(('ok', ), rev_id_utf8),
1707
request.execute('', rev_id_utf8))
1709
def test_no_such_revision(self):
1710
backing = self.get_transport()
1711
request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
1712
tree = self.make_branch_and_memory_tree('.')
1715
r1 = tree.commit('1st commit')
1718
# Note that it still returns body (of zero bytes).
1719
self.assertEqual(smart_req.SmartServerResponse(
1720
('nosuchrevision', 'missingrevision', ), ''),
1721
request.execute('', 'missingrevision'))
1724
class TestSmartServerRepositoryGetRevIdForRevno(
1725
tests.TestCaseWithMemoryTransport):
1727
def test_revno_found(self):
1728
backing = self.get_transport()
1729
request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
1730
tree = self.make_branch_and_memory_tree('.')
1733
rev1_id_utf8 = u'\xc8'.encode('utf-8')
1734
rev2_id_utf8 = u'\xc9'.encode('utf-8')
1735
tree.commit('1st commit', rev_id=rev1_id_utf8)
1736
tree.commit('2nd commit', rev_id=rev2_id_utf8)
1739
self.assertEqual(smart_req.SmartServerResponse(('ok', rev1_id_utf8)),
1740
request.execute('', 1, (2, rev2_id_utf8)))
1742
def test_known_revid_missing(self):
1743
backing = self.get_transport()
1744
request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
1745
repo = self.make_repository('.')
1747
smart_req.FailedSmartServerResponse(('nosuchrevision', 'ghost')),
1748
request.execute('', 1, (2, 'ghost')))
1750
def test_history_incomplete(self):
1751
backing = self.get_transport()
1752
request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
1753
parent = self.make_branch_and_memory_tree('parent', format='1.9')
1755
parent.add([''], ['TREE_ROOT'])
1756
r1 = parent.commit(message='first commit')
1757
r2 = parent.commit(message='second commit')
1759
local = self.make_branch_and_memory_tree('local', format='1.9')
1760
local.branch.pull(parent.branch)
1761
local.set_parent_ids([r2])
1762
r3 = local.commit(message='local commit')
1763
local.branch.create_clone_on_transport(
1764
self.get_transport('stacked'), stacked_on=self.get_url('parent'))
1766
smart_req.SmartServerResponse(('history-incomplete', 2, r2)),
1767
request.execute('stacked', 1, (3, r3)))
1770
class TestSmartServerRepositoryIterRevisions(
1771
tests.TestCaseWithMemoryTransport):
1773
def test_basic(self):
1774
backing = self.get_transport()
1775
request = smart_repo.SmartServerRepositoryIterRevisions(backing)
1776
tree = self.make_branch_and_memory_tree('.', format='2a')
1779
tree.commit('1st commit', rev_id="rev1")
1780
tree.commit('2nd commit', rev_id="rev2")
1783
self.assertIs(None, request.execute(''))
1784
response = request.do_body("rev1\nrev2")
1785
self.assertTrue(response.is_successful())
1786
# Format 2a uses serializer format 10
1787
self.assertEqual(response.args, ("ok", "10"))
1789
self.addCleanup(tree.branch.lock_read().unlock)
1790
entries = [zlib.compress(record.get_bytes_as("fulltext")) for record in
1791
tree.branch.repository.revisions.get_record_stream(
1792
[("rev1", ), ("rev2", )], "unordered", True)]
1794
contents = "".join(response.body_stream)
1795
self.assertTrue(contents in (
1796
"".join([entries[0], entries[1]]),
1797
"".join([entries[1], entries[0]])))
1799
def test_missing(self):
1800
backing = self.get_transport()
1801
request = smart_repo.SmartServerRepositoryIterRevisions(backing)
1802
tree = self.make_branch_and_memory_tree('.', format='2a')
1804
self.assertIs(None, request.execute(''))
1805
response = request.do_body("rev1\nrev2")
1806
self.assertTrue(response.is_successful())
1807
# Format 2a uses serializer format 10
1808
self.assertEqual(response.args, ("ok", "10"))
1810
contents = "".join(response.body_stream)
1811
self.assertEqual(contents, "")
1814
class GetStreamTestBase(tests.TestCaseWithMemoryTransport):
1816
def make_two_commit_repo(self):
1817
tree = self.make_branch_and_memory_tree('.')
1820
r1 = tree.commit('1st commit')
1821
r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
1823
repo = tree.branch.repository
1827
class TestSmartServerRepositoryGetStream(GetStreamTestBase):
1829
def test_ancestry_of(self):
1830
"""The search argument may be a 'ancestry-of' some heads'."""
1831
backing = self.get_transport()
1832
request = smart_repo.SmartServerRepositoryGetStream(backing)
1833
repo, r1, r2 = self.make_two_commit_repo()
1834
fetch_spec = ['ancestry-of', r2]
1835
lines = '\n'.join(fetch_spec)
1836
request.execute('', repo._format.network_name())
1837
response = request.do_body(lines)
1838
self.assertEqual(('ok',), response.args)
1839
stream_bytes = ''.join(response.body_stream)
1840
self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
1842
def test_search(self):
1843
"""The search argument may be a 'search' of some explicit keys."""
1844
backing = self.get_transport()
1845
request = smart_repo.SmartServerRepositoryGetStream(backing)
1846
repo, r1, r2 = self.make_two_commit_repo()
1847
fetch_spec = ['search', '%s %s' % (r1, r2), 'null:', '2']
1848
lines = '\n'.join(fetch_spec)
1849
request.execute('', repo._format.network_name())
1850
response = request.do_body(lines)
1851
self.assertEqual(('ok',), response.args)
1852
stream_bytes = ''.join(response.body_stream)
1853
self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
1855
def test_search_everything(self):
1856
"""A search of 'everything' returns a stream."""
1857
backing = self.get_transport()
1858
request = smart_repo.SmartServerRepositoryGetStream_1_19(backing)
1859
repo, r1, r2 = self.make_two_commit_repo()
1860
serialised_fetch_spec = 'everything'
1861
request.execute('', repo._format.network_name())
1862
response = request.do_body(serialised_fetch_spec)
1863
self.assertEqual(('ok',), response.args)
1864
stream_bytes = ''.join(response.body_stream)
1865
self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
1868
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
1870
def test_missing_revision(self):
1871
"""For a missing revision, ('no', ) is returned."""
1872
backing = self.get_transport()
1873
request = smart_repo.SmartServerRequestHasRevision(backing)
1874
self.make_repository('.')
1875
self.assertEqual(smart_req.SmartServerResponse(('no', )),
1876
request.execute('', 'revid'))
1878
def test_present_revision(self):
1879
"""For a present revision, ('yes', ) is returned."""
1880
backing = self.get_transport()
1881
request = smart_repo.SmartServerRequestHasRevision(backing)
1882
tree = self.make_branch_and_memory_tree('.')
1885
rev_id_utf8 = u'\xc8abc'.encode('utf-8')
1886
r1 = tree.commit('a commit', rev_id=rev_id_utf8)
1888
self.assertTrue(tree.branch.repository.has_revision(rev_id_utf8))
1889
self.assertEqual(smart_req.SmartServerResponse(('yes', )),
1890
request.execute('', rev_id_utf8))
1893
class TestSmartServerRepositoryIterFilesBytes(tests.TestCaseWithTransport):
1895
def test_single(self):
1896
backing = self.get_transport()
1897
request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
1898
t = self.make_branch_and_tree('.')
1899
self.addCleanup(t.lock_write().unlock)
1900
self.build_tree_contents([("file", "somecontents")])
1901
t.add(["file"], ["thefileid"])
1902
t.commit(rev_id='somerev', message="add file")
1903
self.assertIs(None, request.execute(''))
1904
response = request.do_body("thefileid\0somerev\n")
1905
self.assertTrue(response.is_successful())
1906
self.assertEqual(response.args, ("ok", ))
1907
self.assertEqual("".join(response.body_stream),
1908
"ok\x000\n" + zlib.compress("somecontents"))
1910
def test_missing(self):
1911
backing = self.get_transport()
1912
request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
1913
t = self.make_branch_and_tree('.')
1914
self.addCleanup(t.lock_write().unlock)
1915
self.assertIs(None, request.execute(''))
1916
response = request.do_body("thefileid\0revision\n")
1917
self.assertTrue(response.is_successful())
1918
self.assertEqual(response.args, ("ok", ))
1919
self.assertEqual("".join(response.body_stream),
1920
"absent\x00thefileid\x00revision\x000\n")
1923
class TestSmartServerRequestHasSignatureForRevisionId(
1924
tests.TestCaseWithMemoryTransport):
1926
def test_missing_revision(self):
1927
"""For a missing revision, NoSuchRevision is returned."""
1928
backing = self.get_transport()
1929
request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
1931
self.make_repository('.')
1933
smart_req.FailedSmartServerResponse(
1934
('nosuchrevision', 'revid'), None),
1935
request.execute('', 'revid'))
1937
def test_missing_signature(self):
1938
"""For a missing signature, ('no', ) is returned."""
1939
backing = self.get_transport()
1940
request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
1942
tree = self.make_branch_and_memory_tree('.')
1945
r1 = tree.commit('a commit', rev_id='A')
1947
self.assertTrue(tree.branch.repository.has_revision('A'))
1948
self.assertEqual(smart_req.SmartServerResponse(('no', )),
1949
request.execute('', 'A'))
1951
def test_present_signature(self):
1952
"""For a present signature, ('yes', ) is returned."""
1953
backing = self.get_transport()
1954
request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
1956
strategy = gpg.LoopbackGPGStrategy(None)
1957
tree = self.make_branch_and_memory_tree('.')
1960
r1 = tree.commit('a commit', rev_id='A')
1961
tree.branch.repository.start_write_group()
1962
tree.branch.repository.sign_revision('A', strategy)
1963
tree.branch.repository.commit_write_group()
1965
self.assertTrue(tree.branch.repository.has_revision('A'))
1966
self.assertEqual(smart_req.SmartServerResponse(('yes', )),
1967
request.execute('', 'A'))
1970
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithMemoryTransport):
1972
def test_empty_revid(self):
1973
"""With an empty revid, we get only size an number and revisions"""
1974
backing = self.get_transport()
1975
request = smart_repo.SmartServerRepositoryGatherStats(backing)
1976
repository = self.make_repository('.')
1977
stats = repository.gather_stats()
1978
expected_body = 'revisions: 0\n'
1979
self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
1980
request.execute('', '', 'no'))
1982
def test_revid_with_committers(self):
1983
"""For a revid we get more infos."""
1984
backing = self.get_transport()
1985
rev_id_utf8 = u'\xc8abc'.encode('utf-8')
1986
request = smart_repo.SmartServerRepositoryGatherStats(backing)
1987
tree = self.make_branch_and_memory_tree('.')
1990
# Let's build a predictable result
1991
tree.commit('a commit', timestamp=123456.2, timezone=3600)
1992
tree.commit('a commit', timestamp=654321.4, timezone=0,
1996
stats = tree.branch.repository.gather_stats()
1997
expected_body = ('firstrev: 123456.200 3600\n'
1998
'latestrev: 654321.400 0\n'
2000
self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
2004
def test_not_empty_repository_with_committers(self):
2005
"""For a revid and requesting committers we get the whole thing."""
2006
backing = self.get_transport()
2007
rev_id_utf8 = u'\xc8abc'.encode('utf-8')
2008
request = smart_repo.SmartServerRepositoryGatherStats(backing)
2009
tree = self.make_branch_and_memory_tree('.')
2012
# Let's build a predictable result
2013
tree.commit('a commit', timestamp=123456.2, timezone=3600,
2015
tree.commit('a commit', timestamp=654321.4, timezone=0,
2016
committer='bar', rev_id=rev_id_utf8)
2018
stats = tree.branch.repository.gather_stats()
2020
expected_body = ('committers: 2\n'
2021
'firstrev: 123456.200 3600\n'
2022
'latestrev: 654321.400 0\n'
2024
self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
2026
rev_id_utf8, 'yes'))
2028
def test_unknown_revid(self):
2029
"""An unknown revision id causes a 'nosuchrevision' error."""
2030
backing = self.get_transport()
2031
request = smart_repo.SmartServerRepositoryGatherStats(backing)
2032
repository = self.make_repository('.')
2033
expected_body = 'revisions: 0\n'
2035
smart_req.FailedSmartServerResponse(
2036
('nosuchrevision', 'mia'), None),
2037
request.execute('', 'mia', 'yes'))
2040
class TestSmartServerRepositoryIsShared(tests.TestCaseWithMemoryTransport):
2042
def test_is_shared(self):
2043
"""For a shared repository, ('yes', ) is returned."""
2044
backing = self.get_transport()
2045
request = smart_repo.SmartServerRepositoryIsShared(backing)
2046
self.make_repository('.', shared=True)
2047
self.assertEqual(smart_req.SmartServerResponse(('yes', )),
2048
request.execute('', ))
2050
def test_is_not_shared(self):
2051
"""For a shared repository, ('no', ) is returned."""
2052
backing = self.get_transport()
2053
request = smart_repo.SmartServerRepositoryIsShared(backing)
2054
self.make_repository('.', shared=False)
2055
self.assertEqual(smart_req.SmartServerResponse(('no', )),
2056
request.execute('', ))
2059
class TestSmartServerRepositoryGetRevisionSignatureText(
2060
tests.TestCaseWithMemoryTransport):
2062
def test_get_signature(self):
2063
backing = self.get_transport()
2064
request = smart_repo.SmartServerRepositoryGetRevisionSignatureText(
2066
bb = self.make_branch_builder('.')
2067
bb.build_commit(rev_id='A')
2068
repo = bb.get_branch().repository
2069
strategy = gpg.LoopbackGPGStrategy(None)
2070
self.addCleanup(repo.lock_write().unlock)
2071
repo.start_write_group()
2072
repo.sign_revision('A', strategy)
2073
repo.commit_write_group()
2075
'-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
2076
Testament.from_revision(repo, 'A').as_short_text() +
2077
'-----END PSEUDO-SIGNED CONTENT-----\n')
2079
smart_req.SmartServerResponse(('ok', ), expected_body),
2080
request.execute('', 'A'))
2083
class TestSmartServerRepositoryMakeWorkingTrees(
2084
tests.TestCaseWithMemoryTransport):
2086
def test_make_working_trees(self):
2087
"""For a repository with working trees, ('yes', ) is returned."""
2088
backing = self.get_transport()
2089
request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
2090
r = self.make_repository('.')
2091
r.set_make_working_trees(True)
2092
self.assertEqual(smart_req.SmartServerResponse(('yes', )),
2093
request.execute('', ))
2095
def test_is_not_shared(self):
2096
"""For a repository with working trees, ('no', ) is returned."""
2097
backing = self.get_transport()
2098
request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
2099
r = self.make_repository('.')
2100
r.set_make_working_trees(False)
2101
self.assertEqual(smart_req.SmartServerResponse(('no', )),
2102
request.execute('', ))
2105
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
2107
def test_lock_write_on_unlocked_repo(self):
2108
backing = self.get_transport()
2109
request = smart_repo.SmartServerRepositoryLockWrite(backing)
2110
repository = self.make_repository('.', format='knit')
2111
response = request.execute('')
2112
nonce = repository.control_files._lock.peek().get('nonce')
2113
self.assertEqual(smart_req.SmartServerResponse(('ok', nonce)), response)
2114
# The repository is now locked. Verify that with a new repository
2116
new_repo = repository.bzrdir.open_repository()
2117
self.assertRaises(errors.LockContention, new_repo.lock_write)
2119
request = smart_repo.SmartServerRepositoryUnlock(backing)
2120
response = request.execute('', nonce)
2122
def test_lock_write_on_locked_repo(self):
2123
backing = self.get_transport()
2124
request = smart_repo.SmartServerRepositoryLockWrite(backing)
2125
repository = self.make_repository('.', format='knit')
2126
repo_token = repository.lock_write().repository_token
2127
repository.leave_lock_in_place()
2129
response = request.execute('')
2131
smart_req.SmartServerResponse(('LockContention',)), response)
2133
repository.lock_write(repo_token)
2134
repository.dont_leave_lock_in_place()
2137
def test_lock_write_on_readonly_transport(self):
2138
backing = self.get_readonly_transport()
2139
request = smart_repo.SmartServerRepositoryLockWrite(backing)
2140
repository = self.make_repository('.', format='knit')
2141
response = request.execute('')
2142
self.assertFalse(response.is_successful())
2143
self.assertEqual('LockFailed', response.args[0])
2146
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
2148
def make_empty_byte_stream(self, repo):
2149
byte_stream = smart_repo._stream_to_byte_stream([], repo._format)
2150
return ''.join(byte_stream)
2153
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
2155
def test_insert_stream_empty(self):
2156
backing = self.get_transport()
2157
request = smart_repo.SmartServerRepositoryInsertStream(backing)
2158
repository = self.make_repository('.')
2159
response = request.execute('', '')
2160
self.assertEqual(None, response)
2161
response = request.do_chunk(self.make_empty_byte_stream(repository))
2162
self.assertEqual(None, response)
2163
response = request.do_end()
2164
self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
2167
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
2169
def test_insert_stream_empty(self):
2170
backing = self.get_transport()
2171
request = smart_repo.SmartServerRepositoryInsertStreamLocked(
2173
repository = self.make_repository('.', format='knit')
2174
lock_token = repository.lock_write().repository_token
2175
response = request.execute('', '', lock_token)
2176
self.assertEqual(None, response)
2177
response = request.do_chunk(self.make_empty_byte_stream(repository))
2178
self.assertEqual(None, response)
2179
response = request.do_end()
2180
self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
2183
def test_insert_stream_with_wrong_lock_token(self):
2184
backing = self.get_transport()
2185
request = smart_repo.SmartServerRepositoryInsertStreamLocked(
2187
repository = self.make_repository('.', format='knit')
2188
lock_token = repository.lock_write().repository_token
2190
errors.TokenMismatch, request.execute, '', '', 'wrong-token')
2194
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
2196
def test_unlock_on_locked_repo(self):
2197
backing = self.get_transport()
2198
request = smart_repo.SmartServerRepositoryUnlock(backing)
2199
repository = self.make_repository('.', format='knit')
2200
token = repository.lock_write().repository_token
2201
repository.leave_lock_in_place()
2203
response = request.execute('', token)
2205
smart_req.SmartServerResponse(('ok',)), response)
2206
# The repository is now unlocked. Verify that with a new repository
2208
new_repo = repository.bzrdir.open_repository()
2209
new_repo.lock_write()
2212
def test_unlock_on_unlocked_repo(self):
2213
backing = self.get_transport()
2214
request = smart_repo.SmartServerRepositoryUnlock(backing)
2215
repository = self.make_repository('.', format='knit')
2216
response = request.execute('', 'some token')
2218
smart_req.SmartServerResponse(('TokenMismatch',)), response)
2221
class TestSmartServerRepositoryGetPhysicalLockStatus(
2222
tests.TestCaseWithTransport):
2224
def test_with_write_lock(self):
2225
backing = self.get_transport()
2226
repo = self.make_repository('.')
2227
self.addCleanup(repo.lock_write().unlock)
2228
# lock_write() doesn't necessarily actually take a physical
2230
if repo.get_physical_lock_status():
2234
request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
2235
request = request_class(backing)
2236
self.assertEqual(smart_req.SuccessfulSmartServerResponse((expected,)),
2237
request.execute('', ))
2239
def test_without_write_lock(self):
2240
backing = self.get_transport()
2241
repo = self.make_repository('.')
2242
self.assertEqual(False, repo.get_physical_lock_status())
2243
request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
2244
request = request_class(backing)
2245
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('no',)),
2246
request.execute('', ))
2249
class TestSmartServerRepositoryReconcile(tests.TestCaseWithTransport):
2251
def test_reconcile(self):
2252
backing = self.get_transport()
2253
repo = self.make_repository('.')
2254
token = repo.lock_write().repository_token
2255
self.addCleanup(repo.unlock)
2256
request_class = smart_repo.SmartServerRepositoryReconcile
2257
request = request_class(backing)
2258
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
2260
'garbage_inventories: 0\n'
2261
'inconsistent_parents: 0\n'),
2262
request.execute('', token))
2265
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
2267
def test_is_readonly_no(self):
2268
backing = self.get_transport()
2269
request = smart_req.SmartServerIsReadonly(backing)
2270
response = request.execute()
2272
smart_req.SmartServerResponse(('no',)), response)
2274
def test_is_readonly_yes(self):
2275
backing = self.get_readonly_transport()
2276
request = smart_req.SmartServerIsReadonly(backing)
2277
response = request.execute()
2279
smart_req.SmartServerResponse(('yes',)), response)
2282
class TestSmartServerRepositorySetMakeWorkingTrees(
2283
tests.TestCaseWithMemoryTransport):
2285
def test_set_false(self):
2286
backing = self.get_transport()
2287
repo = self.make_repository('.', shared=True)
2288
repo.set_make_working_trees(True)
2289
request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
2290
request = request_class(backing)
2291
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
2292
request.execute('', 'False'))
2293
repo = repo.bzrdir.open_repository()
2294
self.assertFalse(repo.make_working_trees())
2296
def test_set_true(self):
2297
backing = self.get_transport()
2298
repo = self.make_repository('.', shared=True)
2299
repo.set_make_working_trees(False)
2300
request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
2301
request = request_class(backing)
2302
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
2303
request.execute('', 'True'))
2304
repo = repo.bzrdir.open_repository()
2305
self.assertTrue(repo.make_working_trees())
2308
class TestSmartServerRepositoryGetSerializerFormat(
2309
tests.TestCaseWithMemoryTransport):
2311
def test_get_serializer_format(self):
2312
backing = self.get_transport()
2313
repo = self.make_repository('.', format='2a')
2314
request_class = smart_repo.SmartServerRepositoryGetSerializerFormat
2315
request = request_class(backing)
2317
smart_req.SuccessfulSmartServerResponse(('ok', '10')),
2318
request.execute(''))
2321
class TestSmartServerRepositoryWriteGroup(
2322
tests.TestCaseWithMemoryTransport):
2324
def test_start_write_group(self):
2325
backing = self.get_transport()
2326
repo = self.make_repository('.')
2327
lock_token = repo.lock_write().repository_token
2328
self.addCleanup(repo.unlock)
2329
request_class = smart_repo.SmartServerRepositoryStartWriteGroup
2330
request = request_class(backing)
2331
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok', [])),
2332
request.execute('', lock_token))
2334
def test_start_write_group_unsuspendable(self):
2335
backing = self.get_transport()
2336
repo = self.make_repository('.', format='knit')
2337
lock_token = repo.lock_write().repository_token
2338
self.addCleanup(repo.unlock)
2339
request_class = smart_repo.SmartServerRepositoryStartWriteGroup
2340
request = request_class(backing)
2342
smart_req.FailedSmartServerResponse(('UnsuspendableWriteGroup',)),
2343
request.execute('', lock_token))
2345
def test_commit_write_group(self):
2346
backing = self.get_transport()
2347
repo = self.make_repository('.')
2348
lock_token = repo.lock_write().repository_token
2349
self.addCleanup(repo.unlock)
2350
repo.start_write_group()
2351
tokens = repo.suspend_write_group()
2352
request_class = smart_repo.SmartServerRepositoryCommitWriteGroup
2353
request = request_class(backing)
2354
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
2355
request.execute('', lock_token, tokens))
2357
def test_abort_write_group(self):
2358
backing = self.get_transport()
2359
repo = self.make_repository('.')
2360
lock_token = repo.lock_write().repository_token
2361
repo.start_write_group()
2362
tokens = repo.suspend_write_group()
2363
self.addCleanup(repo.unlock)
2364
request_class = smart_repo.SmartServerRepositoryAbortWriteGroup
2365
request = request_class(backing)
2366
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
2367
request.execute('', lock_token, tokens))
2369
def test_check_write_group(self):
2370
backing = self.get_transport()
2371
repo = self.make_repository('.')
2372
lock_token = repo.lock_write().repository_token
2373
repo.start_write_group()
2374
tokens = repo.suspend_write_group()
2375
self.addCleanup(repo.unlock)
2376
request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
2377
request = request_class(backing)
2378
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
2379
request.execute('', lock_token, tokens))
2381
def test_check_write_group_invalid(self):
2382
backing = self.get_transport()
2383
repo = self.make_repository('.')
2384
lock_token = repo.lock_write().repository_token
2385
self.addCleanup(repo.unlock)
2386
request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
2387
request = request_class(backing)
2388
self.assertEqual(smart_req.FailedSmartServerResponse(
2389
('UnresumableWriteGroup', ['random'],
2390
'Malformed write group token')),
2391
request.execute('', lock_token, ["random"]))
2394
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
2396
def make_repo_needing_autopacking(self, path='.'):
2397
# Make a repo in need of autopacking.
2398
tree = self.make_branch_and_tree('.', format='pack-0.92')
2399
repo = tree.branch.repository
2400
# monkey-patch the pack collection to disable autopacking
2401
repo._pack_collection._max_pack_count = lambda count: count
2403
tree.commit('commit %s' % x)
2404
self.assertEqual(10, len(repo._pack_collection.names()))
2405
del repo._pack_collection._max_pack_count
2408
def test_autopack_needed(self):
2409
repo = self.make_repo_needing_autopacking()
2411
self.addCleanup(repo.unlock)
2412
backing = self.get_transport()
2413
request = smart_packrepo.SmartServerPackRepositoryAutopack(
2415
response = request.execute('')
2416
self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
2417
repo._pack_collection.reload_pack_names()
2418
self.assertEqual(1, len(repo._pack_collection.names()))
2420
def test_autopack_not_needed(self):
2421
tree = self.make_branch_and_tree('.', format='pack-0.92')
2422
repo = tree.branch.repository
2424
self.addCleanup(repo.unlock)
2426
tree.commit('commit %s' % x)
2427
backing = self.get_transport()
2428
request = smart_packrepo.SmartServerPackRepositoryAutopack(
2430
response = request.execute('')
2431
self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
2432
repo._pack_collection.reload_pack_names()
2433
self.assertEqual(9, len(repo._pack_collection.names()))
2435
def test_autopack_on_nonpack_format(self):
2436
"""A request to autopack a non-pack repo is a no-op."""
2437
repo = self.make_repository('.', format='knit')
2438
backing = self.get_transport()
2439
request = smart_packrepo.SmartServerPackRepositoryAutopack(
2441
response = request.execute('')
2442
self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
2445
class TestSmartServerVfsGet(tests.TestCaseWithMemoryTransport):
2447
def test_unicode_path(self):
2448
"""VFS requests expect unicode paths to be escaped."""
2449
filename = u'foo\N{INTERROBANG}'
2450
filename_escaped = urlutils.escape(filename)
2451
backing = self.get_transport()
2452
request = vfs.GetRequest(backing)
2453
backing.put_bytes_non_atomic(filename_escaped, 'contents')
2454
self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'contents'),
2455
request.execute(filename_escaped))
2458
class TestHandlers(tests.TestCase):
2459
"""Tests for the request.request_handlers object."""
2461
def test_all_registrations_exist(self):
2462
"""All registered request_handlers can be found."""
2463
# If there's a typo in a register_lazy call, this loop will fail with
2464
# an AttributeError.
2465
for key in smart_req.request_handlers.keys():
2467
item = smart_req.request_handlers.get(key)
2468
except AttributeError as e:
2469
raise AttributeError('failed to get %s: %s' % (key, e))
2471
def assertHandlerEqual(self, verb, handler):
2472
self.assertEqual(smart_req.request_handlers.get(verb), handler)
2474
def test_registered_methods(self):
2475
"""Test that known methods are registered to the correct object."""
2476
self.assertHandlerEqual('Branch.break_lock',
2477
smart_branch.SmartServerBranchBreakLock)
2478
self.assertHandlerEqual('Branch.get_config_file',
2479
smart_branch.SmartServerBranchGetConfigFile)
2480
self.assertHandlerEqual('Branch.put_config_file',
2481
smart_branch.SmartServerBranchPutConfigFile)
2482
self.assertHandlerEqual('Branch.get_parent',
2483
smart_branch.SmartServerBranchGetParent)
2484
self.assertHandlerEqual('Branch.get_physical_lock_status',
2485
smart_branch.SmartServerBranchRequestGetPhysicalLockStatus)
2486
self.assertHandlerEqual('Branch.get_tags_bytes',
2487
smart_branch.SmartServerBranchGetTagsBytes)
2488
self.assertHandlerEqual('Branch.lock_write',
2489
smart_branch.SmartServerBranchRequestLockWrite)
2490
self.assertHandlerEqual('Branch.last_revision_info',
2491
smart_branch.SmartServerBranchRequestLastRevisionInfo)
2492
self.assertHandlerEqual('Branch.revision_history',
2493
smart_branch.SmartServerRequestRevisionHistory)
2494
self.assertHandlerEqual('Branch.revision_id_to_revno',
2495
smart_branch.SmartServerBranchRequestRevisionIdToRevno)
2496
self.assertHandlerEqual('Branch.set_config_option',
2497
smart_branch.SmartServerBranchRequestSetConfigOption)
2498
self.assertHandlerEqual('Branch.set_last_revision',
2499
smart_branch.SmartServerBranchRequestSetLastRevision)
2500
self.assertHandlerEqual('Branch.set_last_revision_info',
2501
smart_branch.SmartServerBranchRequestSetLastRevisionInfo)
2502
self.assertHandlerEqual('Branch.set_last_revision_ex',
2503
smart_branch.SmartServerBranchRequestSetLastRevisionEx)
2504
self.assertHandlerEqual('Branch.set_parent_location',
2505
smart_branch.SmartServerBranchRequestSetParentLocation)
2506
self.assertHandlerEqual('Branch.unlock',
2507
smart_branch.SmartServerBranchRequestUnlock)
2508
self.assertHandlerEqual('BzrDir.destroy_branch',
2509
smart_dir.SmartServerBzrDirRequestDestroyBranch)
2510
self.assertHandlerEqual('BzrDir.find_repository',
2511
smart_dir.SmartServerRequestFindRepositoryV1)
2512
self.assertHandlerEqual('BzrDir.find_repositoryV2',
2513
smart_dir.SmartServerRequestFindRepositoryV2)
2514
self.assertHandlerEqual('BzrDirFormat.initialize',
2515
smart_dir.SmartServerRequestInitializeBzrDir)
2516
self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
2517
smart_dir.SmartServerRequestBzrDirInitializeEx)
2518
self.assertHandlerEqual('BzrDir.checkout_metadir',
2519
smart_dir.SmartServerBzrDirRequestCheckoutMetaDir)
2520
self.assertHandlerEqual('BzrDir.cloning_metadir',
2521
smart_dir.SmartServerBzrDirRequestCloningMetaDir)
2522
self.assertHandlerEqual('BzrDir.get_branches',
2523
smart_dir.SmartServerBzrDirRequestGetBranches)
2524
self.assertHandlerEqual('BzrDir.get_config_file',
2525
smart_dir.SmartServerBzrDirRequestConfigFile)
2526
self.assertHandlerEqual('BzrDir.open_branch',
2527
smart_dir.SmartServerRequestOpenBranch)
2528
self.assertHandlerEqual('BzrDir.open_branchV2',
2529
smart_dir.SmartServerRequestOpenBranchV2)
2530
self.assertHandlerEqual('BzrDir.open_branchV3',
2531
smart_dir.SmartServerRequestOpenBranchV3)
2532
self.assertHandlerEqual('PackRepository.autopack',
2533
smart_packrepo.SmartServerPackRepositoryAutopack)
2534
self.assertHandlerEqual('Repository.add_signature_text',
2535
smart_repo.SmartServerRepositoryAddSignatureText)
2536
self.assertHandlerEqual('Repository.all_revision_ids',
2537
smart_repo.SmartServerRepositoryAllRevisionIds)
2538
self.assertHandlerEqual('Repository.break_lock',
2539
smart_repo.SmartServerRepositoryBreakLock)
2540
self.assertHandlerEqual('Repository.gather_stats',
2541
smart_repo.SmartServerRepositoryGatherStats)
2542
self.assertHandlerEqual('Repository.get_parent_map',
2543
smart_repo.SmartServerRepositoryGetParentMap)
2544
self.assertHandlerEqual('Repository.get_physical_lock_status',
2545
smart_repo.SmartServerRepositoryGetPhysicalLockStatus)
2546
self.assertHandlerEqual('Repository.get_rev_id_for_revno',
2547
smart_repo.SmartServerRepositoryGetRevIdForRevno)
2548
self.assertHandlerEqual('Repository.get_revision_graph',
2549
smart_repo.SmartServerRepositoryGetRevisionGraph)
2550
self.assertHandlerEqual('Repository.get_revision_signature_text',
2551
smart_repo.SmartServerRepositoryGetRevisionSignatureText)
2552
self.assertHandlerEqual('Repository.get_stream',
2553
smart_repo.SmartServerRepositoryGetStream)
2554
self.assertHandlerEqual('Repository.get_stream_1.19',
2555
smart_repo.SmartServerRepositoryGetStream_1_19)
2556
self.assertHandlerEqual('Repository.iter_revisions',
2557
smart_repo.SmartServerRepositoryIterRevisions)
2558
self.assertHandlerEqual('Repository.has_revision',
2559
smart_repo.SmartServerRequestHasRevision)
2560
self.assertHandlerEqual('Repository.insert_stream',
2561
smart_repo.SmartServerRepositoryInsertStream)
2562
self.assertHandlerEqual('Repository.insert_stream_locked',
2563
smart_repo.SmartServerRepositoryInsertStreamLocked)
2564
self.assertHandlerEqual('Repository.is_shared',
2565
smart_repo.SmartServerRepositoryIsShared)
2566
self.assertHandlerEqual('Repository.iter_files_bytes',
2567
smart_repo.SmartServerRepositoryIterFilesBytes)
2568
self.assertHandlerEqual('Repository.lock_write',
2569
smart_repo.SmartServerRepositoryLockWrite)
2570
self.assertHandlerEqual('Repository.make_working_trees',
2571
smart_repo.SmartServerRepositoryMakeWorkingTrees)
2572
self.assertHandlerEqual('Repository.pack',
2573
smart_repo.SmartServerRepositoryPack)
2574
self.assertHandlerEqual('Repository.reconcile',
2575
smart_repo.SmartServerRepositoryReconcile)
2576
self.assertHandlerEqual('Repository.tarball',
2577
smart_repo.SmartServerRepositoryTarball)
2578
self.assertHandlerEqual('Repository.unlock',
2579
smart_repo.SmartServerRepositoryUnlock)
2580
self.assertHandlerEqual('Repository.start_write_group',
2581
smart_repo.SmartServerRepositoryStartWriteGroup)
2582
self.assertHandlerEqual('Repository.check_write_group',
2583
smart_repo.SmartServerRepositoryCheckWriteGroup)
2584
self.assertHandlerEqual('Repository.commit_write_group',
2585
smart_repo.SmartServerRepositoryCommitWriteGroup)
2586
self.assertHandlerEqual('Repository.abort_write_group',
2587
smart_repo.SmartServerRepositoryAbortWriteGroup)
2588
self.assertHandlerEqual('VersionedFileRepository.get_serializer_format',
2589
smart_repo.SmartServerRepositoryGetSerializerFormat)
2590
self.assertHandlerEqual('VersionedFileRepository.get_inventories',
2591
smart_repo.SmartServerRepositoryGetInventories)
2592
self.assertHandlerEqual('Transport.is_readonly',
2593
smart_req.SmartServerIsReadonly)
2596
class SmartTCPServerHookTests(tests.TestCaseWithMemoryTransport):
2597
"""Tests for SmartTCPServer hooks."""
2600
super(SmartTCPServerHookTests, self).setUp()
2601
self.server = server.SmartTCPServer(self.get_transport())
2603
def test_run_server_started_hooks(self):
2604
"""Test the server started hooks get fired properly."""
2606
server.SmartTCPServer.hooks.install_named_hook('server_started',
2607
lambda backing_urls, url: started_calls.append((backing_urls, url)),
2609
started_ex_calls = []
2610
server.SmartTCPServer.hooks.install_named_hook('server_started_ex',
2611
lambda backing_urls, url: started_ex_calls.append((backing_urls, url)),
2613
self.server._sockname = ('example.com', 42)
2614
self.server.run_server_started_hooks()
2615
self.assertEqual(started_calls,
2616
[([self.get_transport().base], 'bzr://example.com:42/')])
2617
self.assertEqual(started_ex_calls,
2618
[([self.get_transport().base], self.server)])
2620
def test_run_server_started_hooks_ipv6(self):
2621
"""Test that socknames can contain 4-tuples."""
2622
self.server._sockname = ('::', 42, 0, 0)
2624
server.SmartTCPServer.hooks.install_named_hook('server_started',
2625
lambda backing_urls, url: started_calls.append((backing_urls, url)),
2627
self.server.run_server_started_hooks()
2628
self.assertEqual(started_calls,
2629
[([self.get_transport().base], 'bzr://:::42/')])
2631
def test_run_server_stopped_hooks(self):
2632
"""Test the server stopped hooks."""
2633
self.server._sockname = ('example.com', 42)
2635
server.SmartTCPServer.hooks.install_named_hook('server_stopped',
2636
lambda backing_urls, url: stopped_calls.append((backing_urls, url)),
2638
self.server.run_server_stopped_hooks()
2639
self.assertEqual(stopped_calls,
2640
[([self.get_transport().base], 'bzr://example.com:42/')])
2643
class TestSmartServerRepositoryPack(tests.TestCaseWithMemoryTransport):
2645
def test_pack(self):
2646
backing = self.get_transport()
2647
request = smart_repo.SmartServerRepositoryPack(backing)
2648
tree = self.make_branch_and_memory_tree('.')
2649
repo_token = tree.branch.repository.lock_write().repository_token
2651
self.assertIs(None, request.execute('', repo_token, False))
2654
smart_req.SuccessfulSmartServerResponse(('ok', ), ),
2655
request.do_body(''))
2658
class TestSmartServerRepositoryGetInventories(tests.TestCaseWithTransport):
2660
def _get_serialized_inventory_delta(self, repository, base_revid, revid):
2661
base_inv = repository.revision_tree(base_revid).root_inventory
2662
inv = repository.revision_tree(revid).root_inventory
2663
inv_delta = inv._make_delta(base_inv)
2664
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
2665
return "".join(serializer.delta_to_lines(base_revid, revid, inv_delta))
2667
def test_single(self):
2668
backing = self.get_transport()
2669
request = smart_repo.SmartServerRepositoryGetInventories(backing)
2670
t = self.make_branch_and_tree('.', format='2a')
2671
self.addCleanup(t.lock_write().unlock)
2672
self.build_tree_contents([("file", "somecontents")])
2673
t.add(["file"], ["thefileid"])
2674
t.commit(rev_id='somerev', message="add file")
2675
self.assertIs(None, request.execute('', 'unordered'))
2676
response = request.do_body("somerev\n")
2677
self.assertTrue(response.is_successful())
2678
self.assertEqual(response.args, ("ok", ))
2679
stream = [('inventory-deltas', [
2680
versionedfile.FulltextContentFactory('somerev', None, None,
2681
self._get_serialized_inventory_delta(
2682
t.branch.repository, 'null:', 'somerev'))])]
2683
fmt = controldir.format_registry.get('2a')().repository_format
2685
"".join(response.body_stream),
2686
"".join(smart_repo._stream_to_byte_stream(stream, fmt)))
2688
def test_empty(self):
2689
backing = self.get_transport()
2690
request = smart_repo.SmartServerRepositoryGetInventories(backing)
2691
t = self.make_branch_and_tree('.', format='2a')
2692
self.addCleanup(t.lock_write().unlock)
2693
self.build_tree_contents([("file", "somecontents")])
2694
t.add(["file"], ["thefileid"])
2695
t.commit(rev_id='somerev', message="add file")
2696
self.assertIs(None, request.execute('', 'unordered'))
2697
response = request.do_body("")
2698
self.assertTrue(response.is_successful())
2699
self.assertEqual(response.args, ("ok", ))
2700
self.assertEqual("".join(response.body_stream),
2701
"Bazaar pack format 1 (introduced in 0.18)\nB54\n\nBazaar repository format 2a (needs bzr 1.16 or later)\nE")