13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 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.
28
from cStringIO import StringIO
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Tests for the smart wire/domain protococl."""
19
from StringIO import StringIO
39
from bzrlib.branch import Branch, BranchReferenceFormat
23
from bzrlib import bzrdir, errors, smart, tests
24
from bzrlib.smart.request import SmartServerResponse
25
import bzrlib.smart.bzrdir
40
26
import bzrlib.smart.branch
41
import bzrlib.smart.bzrdir, bzrlib.smart.bzrdir as smart_dir
42
import bzrlib.smart.packrepository
43
27
import bzrlib.smart.repository
44
from bzrlib.smart.request import (
45
FailedSmartServerResponse,
48
SuccessfulSmartServerResponse,
50
from bzrlib.tests import (
53
from bzrlib.transport import chroot, get_transport
54
from bzrlib.util import bencode
57
def load_tests(standard_tests, module, loader):
58
"""Multiply tests version and protocol consistency."""
59
# FindRepository tests.
60
bzrdir_mod = bzrlib.smart.bzrdir
63
"_request_class":bzrdir_mod.SmartServerRequestFindRepositoryV1}),
64
("find_repositoryV2", {
65
"_request_class":bzrdir_mod.SmartServerRequestFindRepositoryV2}),
66
("find_repositoryV3", {
67
"_request_class":bzrdir_mod.SmartServerRequestFindRepositoryV3}),
69
to_adapt, result = split_suite_by_re(standard_tests,
70
"TestSmartServerRequestFindRepository")
71
v2_only, v1_and_2 = split_suite_by_re(to_adapt,
73
tests.multiply_tests(v1_and_2, scenarios, result)
74
# The first scenario is only applicable to v1 protocols, it is deleted
76
tests.multiply_tests(v2_only, scenarios[1:], result)
80
class TestCaseWithChrootedTransport(tests.TestCaseWithTransport):
83
tests.TestCaseWithTransport.setUp(self)
84
self._chroot_server = None
86
def get_transport(self, relpath=None):
87
if self._chroot_server is None:
88
backing_transport = tests.TestCaseWithTransport.get_transport(self)
89
self._chroot_server = chroot.ChrootServer(backing_transport)
90
self._chroot_server.setUp()
91
self.addCleanup(self._chroot_server.tearDown)
92
t = get_transport(self._chroot_server.get_url())
93
if relpath is not None:
98
30
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
127
56
self.assertNotEqual(None,
128
57
SmartServerResponse(('ok', )))
130
def test__str__(self):
131
"""SmartServerResponses can be stringified."""
133
"<SuccessfulSmartServerResponse args=('args',) body='body'>",
134
str(SuccessfulSmartServerResponse(('args',), 'body')))
136
"<FailedSmartServerResponse args=('args',) body='body'>",
137
str(FailedSmartServerResponse(('args',), 'body')))
140
class TestSmartServerRequest(tests.TestCaseWithMemoryTransport):
142
def test_translate_client_path(self):
143
transport = self.get_transport()
144
request = SmartServerRequest(transport, 'foo/')
145
self.assertEqual('./', request.translate_client_path('foo/'))
147
errors.InvalidURLJoin, request.translate_client_path, 'foo/..')
149
errors.PathNotChild, request.translate_client_path, '/')
151
errors.PathNotChild, request.translate_client_path, 'bar/')
152
self.assertEqual('./baz', request.translate_client_path('foo/baz'))
154
def test_transport_from_client_path(self):
155
transport = self.get_transport()
156
request = SmartServerRequest(transport, 'foo/')
159
request.transport_from_client_path('foo/').base)
162
class TestSmartServerBzrDirRequestCloningMetaDir(
163
tests.TestCaseWithMemoryTransport):
164
"""Tests for BzrDir.cloning_metadir."""
166
def test_cloning_metadir(self):
167
"""When there is a bzrdir present, the call succeeds."""
168
backing = self.get_transport()
169
dir = self.make_bzrdir('.')
170
local_result = dir.cloning_metadir()
171
request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
172
request = request_class(backing)
173
expected = SuccessfulSmartServerResponse(
174
(local_result.network_name(),
175
local_result.repository_format.network_name(),
176
('branch', local_result.get_branch_format().network_name())))
177
self.assertEqual(expected, request.execute('', 'False'))
179
def test_cloning_metadir_reference(self):
180
"""The request fails when bzrdir contains a branch reference."""
181
backing = self.get_transport()
182
referenced_branch = self.make_branch('referenced')
183
dir = self.make_bzrdir('.')
184
local_result = dir.cloning_metadir()
185
reference = BranchReferenceFormat().initialize(dir, referenced_branch)
186
reference_url = BranchReferenceFormat().get_reference(dir)
187
# The server shouldn't try to follow the branch reference, so it's fine
188
# if the referenced branch isn't reachable.
189
backing.rename('referenced', 'moved')
190
request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
191
request = request_class(backing)
192
expected = FailedSmartServerResponse(('BranchReference',))
193
self.assertEqual(expected, request.execute('', 'False'))
196
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
197
"""Tests for BzrDir.create_repository."""
199
def test_makes_repository(self):
200
"""When there is a bzrdir present, the call succeeds."""
201
backing = self.get_transport()
202
self.make_bzrdir('.')
203
request_class = bzrlib.smart.bzrdir.SmartServerRequestCreateRepository
204
request = request_class(backing)
205
reference_bzrdir_format = bzrdir.format_registry.get('default')()
206
reference_format = reference_bzrdir_format.repository_format
207
network_name = reference_format.network_name()
208
expected = SuccessfulSmartServerResponse(
209
('ok', 'no', 'no', 'no', network_name))
210
self.assertEqual(expected, request.execute('', network_name, 'True'))
213
class TestSmartServerRequestFindRepository(tests.TestCaseWithMemoryTransport):
60
class TestSmartServerRequestFindRepository(tests.TestCaseWithTransport):
214
61
"""Tests for BzrDir.find_repository."""
216
63
def test_no_repository(self):
217
64
"""When there is no repository to be found, ('norepository', ) is returned."""
218
65
backing = self.get_transport()
219
request = self._request_class(backing)
66
request = smart.bzrdir.SmartServerRequestFindRepository(backing)
220
67
self.make_bzrdir('.')
221
68
self.assertEqual(SmartServerResponse(('norepository', )),
69
request.execute(backing.local_abspath('')))
224
71
def test_nonshared_repository(self):
225
# nonshared repositorys only allow 'find' to return a handle when the
226
# path the repository is being searched on is the same as that that
72
# nonshared repositorys only allow 'find' to return a handle when the
73
# path the repository is being searched on is the same as that that
227
74
# the repository is at.
228
75
backing = self.get_transport()
229
request = self._request_class(backing)
76
request = smart.bzrdir.SmartServerRequestFindRepository(backing)
230
77
result = self._make_repository_and_result()
231
self.assertEqual(result, request.execute(''))
78
self.assertEqual(result, request.execute(backing.local_abspath('')))
232
79
self.make_bzrdir('subdir')
233
80
self.assertEqual(SmartServerResponse(('norepository', )),
234
request.execute('subdir'))
81
request.execute(backing.local_abspath('subdir')))
236
83
def _make_repository_and_result(self, shared=False, format=None):
237
84
"""Convenience function to setup a repository.
250
if (smart.bzrdir.SmartServerRequestFindRepositoryV3 ==
251
self._request_class):
252
return SuccessfulSmartServerResponse(
253
('ok', '', rich_root, subtrees, 'no',
254
repo._format.network_name()))
255
elif (smart.bzrdir.SmartServerRequestFindRepositoryV2 ==
256
self._request_class):
257
# All tests so far are on formats, and for non-external
259
return SuccessfulSmartServerResponse(
260
('ok', '', rich_root, subtrees, 'no'))
262
return SuccessfulSmartServerResponse(('ok', '', rich_root, subtrees))
97
return SmartServerResponse(('ok', '', rich_root, subtrees))
264
99
def test_shared_repository(self):
265
100
"""When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
266
101
backing = self.get_transport()
267
request = self._request_class(backing)
102
request = smart.bzrdir.SmartServerRequestFindRepository(backing)
268
103
result = self._make_repository_and_result(shared=True)
269
self.assertEqual(result, request.execute(''))
104
self.assertEqual(result, request.execute(backing.local_abspath('')))
270
105
self.make_bzrdir('subdir')
271
106
result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
272
107
self.assertEqual(result2,
273
request.execute('subdir'))
108
request.execute(backing.local_abspath('subdir')))
274
109
self.make_bzrdir('subdir/deeper')
275
110
result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
276
111
self.assertEqual(result3,
277
request.execute('subdir/deeper'))
112
request.execute(backing.local_abspath('subdir/deeper')))
279
114
def test_rich_root_and_subtree_encoding(self):
280
115
"""Test for the format attributes for rich root and subtree support."""
281
116
backing = self.get_transport()
282
request = self._request_class(backing)
117
request = smart.bzrdir.SmartServerRequestFindRepository(backing)
283
118
result = self._make_repository_and_result(format='dirstate-with-subtree')
284
119
# check the test will be valid
285
120
self.assertEqual('yes', result.args[2])
286
121
self.assertEqual('yes', result.args[3])
287
self.assertEqual(result, request.execute(''))
289
def test_supports_external_lookups_no_v2(self):
290
"""Test for the supports_external_lookups attribute."""
291
backing = self.get_transport()
292
request = self._request_class(backing)
293
result = self._make_repository_and_result(format='dirstate-with-subtree')
294
# check the test will be valid
295
self.assertEqual('no', result.args[4])
296
self.assertEqual(result, request.execute(''))
299
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithMemoryTransport):
122
self.assertEqual(result, request.execute(backing.local_abspath('')))
125
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithTransport):
301
127
def test_empty_dir(self):
302
128
"""Initializing an empty dir should succeed and do it."""
303
129
backing = self.get_transport()
304
130
request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
305
131
self.assertEqual(SmartServerResponse(('ok', )),
132
request.execute(backing.local_abspath('.')))
307
133
made_dir = bzrdir.BzrDir.open_from_transport(backing)
308
# no branch, tree or repository is expected with the current
134
# no branch, tree or repository is expected with the current
309
135
# default formart.
310
136
self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
311
137
self.assertRaises(errors.NotBranchError, made_dir.open_branch)
488
266
# there should be no file by default
490
268
self.assertEqual(SmartServerResponse(('ok', ), content),
269
request.execute(backing.local_abspath('')))
493
271
def test_with_content(self):
494
272
# SmartServerBranchGetConfigFile should return the content from
495
273
# branch.control_files.get('branch.conf') for now - in the future it may
496
# perform more complex processing.
274
# perform more complex processing.
497
275
backing = self.get_transport()
498
276
request = smart.branch.SmartServerBranchGetConfigFile(backing)
499
277
branch = self.make_branch('.')
500
branch._transport.put_bytes('branch.conf', 'foo bar baz')
278
branch.control_files.put_utf8('branch.conf', 'foo bar baz')
501
279
self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
505
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
507
def get_lock_tokens(self, branch):
508
branch_token = branch.lock_write()
509
repo_token = branch.repository.lock_write()
510
branch.repository.unlock()
511
return branch_token, repo_token
514
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
516
def test_value_name(self):
517
branch = self.make_branch('.')
518
request = smart.branch.SmartServerBranchRequestSetConfigOption(
519
branch.bzrdir.root_transport)
520
branch_token, repo_token = self.get_lock_tokens(branch)
521
config = branch._get_config()
522
result = request.execute('', branch_token, repo_token, 'bar', 'foo',
524
self.assertEqual(SuccessfulSmartServerResponse(()), result)
525
self.assertEqual('bar', config.get_option('foo'))
527
def test_value_name_section(self):
528
branch = self.make_branch('.')
529
request = smart.branch.SmartServerBranchRequestSetConfigOption(
530
branch.bzrdir.root_transport)
531
branch_token, repo_token = self.get_lock_tokens(branch)
532
config = branch._get_config()
533
result = request.execute('', branch_token, repo_token, 'bar', 'foo',
535
self.assertEqual(SuccessfulSmartServerResponse(()), result)
536
self.assertEqual('bar', config.get_option('foo', 'gam'))
539
class SetLastRevisionTestBase(TestLockedBranch):
540
"""Base test case for verbs that implement set_last_revision."""
543
tests.TestCaseWithMemoryTransport.setUp(self)
544
backing_transport = self.get_transport()
545
self.request = self.request_class(backing_transport)
546
self.tree = self.make_branch_and_memory_tree('.')
548
def lock_branch(self):
549
return self.get_lock_tokens(self.tree.branch)
551
def unlock_branch(self):
552
self.tree.branch.unlock()
554
def set_last_revision(self, revision_id, revno):
555
branch_token, repo_token = self.lock_branch()
556
response = self._set_last_revision(
557
revision_id, revno, branch_token, repo_token)
561
def assertRequestSucceeds(self, revision_id, revno):
562
response = self.set_last_revision(revision_id, revno)
563
self.assertEqual(SuccessfulSmartServerResponse(('ok',)), response)
566
class TestSetLastRevisionVerbMixin(object):
567
"""Mixin test case for verbs that implement set_last_revision."""
569
def test_set_null_to_null(self):
570
"""An empty branch can have its last revision set to 'null:'."""
571
self.assertRequestSucceeds('null:', 0)
573
def test_NoSuchRevision(self):
574
"""If the revision_id is not present, the verb returns NoSuchRevision.
576
revision_id = 'non-existent revision'
578
FailedSmartServerResponse(('NoSuchRevision', revision_id)),
579
self.set_last_revision(revision_id, 1))
581
def make_tree_with_two_commits(self):
582
self.tree.lock_write()
584
rev_id_utf8 = u'\xc8'.encode('utf-8')
585
r1 = self.tree.commit('1st commit', rev_id=rev_id_utf8)
586
r2 = self.tree.commit('2nd commit', rev_id='rev-2')
589
def test_branch_last_revision_info_is_updated(self):
590
"""A branch's tip can be set to a revision that is present in its
593
# Make a branch with an empty revision history, but two revisions in
595
self.make_tree_with_two_commits()
596
rev_id_utf8 = u'\xc8'.encode('utf-8')
597
self.tree.branch.set_revision_history([])
599
(0, 'null:'), self.tree.branch.last_revision_info())
600
# We can update the branch to a revision that is present in the
602
self.assertRequestSucceeds(rev_id_utf8, 1)
604
(1, rev_id_utf8), self.tree.branch.last_revision_info())
606
def test_branch_last_revision_info_rewind(self):
607
"""A branch's tip can be set to a revision that is an ancestor of the
610
self.make_tree_with_two_commits()
611
rev_id_utf8 = u'\xc8'.encode('utf-8')
613
(2, 'rev-2'), self.tree.branch.last_revision_info())
614
self.assertRequestSucceeds(rev_id_utf8, 1)
616
(1, rev_id_utf8), self.tree.branch.last_revision_info())
618
def test_TipChangeRejected(self):
619
"""If a pre_change_branch_tip hook raises TipChangeRejected, the verb
620
returns TipChangeRejected.
622
rejection_message = u'rejection message\N{INTERROBANG}'
623
def hook_that_rejects(params):
624
raise errors.TipChangeRejected(rejection_message)
625
Branch.hooks.install_named_hook(
626
'pre_change_branch_tip', hook_that_rejects, None)
628
FailedSmartServerResponse(
629
('TipChangeRejected', rejection_message.encode('utf-8'))),
630
self.set_last_revision('null:', 0))
633
class TestSmartServerBranchRequestSetLastRevision(
634
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
635
"""Tests for Branch.set_last_revision verb."""
637
request_class = smart.branch.SmartServerBranchRequestSetLastRevision
639
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
640
return self.request.execute(
641
'', branch_token, repo_token, revision_id)
644
class TestSmartServerBranchRequestSetLastRevisionInfo(
645
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
646
"""Tests for Branch.set_last_revision_info verb."""
648
request_class = smart.branch.SmartServerBranchRequestSetLastRevisionInfo
650
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
651
return self.request.execute(
652
'', branch_token, repo_token, revno, revision_id)
654
def test_NoSuchRevision(self):
655
"""Branch.set_last_revision_info does not have to return
656
NoSuchRevision if the revision_id is absent.
658
raise tests.TestNotApplicable()
661
class TestSmartServerBranchRequestSetLastRevisionEx(
662
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
663
"""Tests for Branch.set_last_revision_ex verb."""
665
request_class = smart.branch.SmartServerBranchRequestSetLastRevisionEx
667
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
668
return self.request.execute(
669
'', branch_token, repo_token, revision_id, 0, 0)
671
def assertRequestSucceeds(self, revision_id, revno):
672
response = self.set_last_revision(revision_id, revno)
674
SuccessfulSmartServerResponse(('ok', revno, revision_id)),
677
def test_branch_last_revision_info_rewind(self):
678
"""A branch's tip can be set to a revision that is an ancestor of the
679
current tip, but only if allow_overwrite_descendant is passed.
681
self.make_tree_with_two_commits()
682
rev_id_utf8 = u'\xc8'.encode('utf-8')
684
(2, 'rev-2'), self.tree.branch.last_revision_info())
685
# If allow_overwrite_descendant flag is 0, then trying to set the tip
686
# to an older revision ID has no effect.
687
branch_token, repo_token = self.lock_branch()
688
response = self.request.execute(
689
'', branch_token, repo_token, rev_id_utf8, 0, 0)
691
SuccessfulSmartServerResponse(('ok', 2, 'rev-2')),
694
(2, 'rev-2'), self.tree.branch.last_revision_info())
696
# If allow_overwrite_descendant flag is 1, then setting the tip to an
698
response = self.request.execute(
699
'', branch_token, repo_token, rev_id_utf8, 0, 1)
701
SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)),
705
(1, rev_id_utf8), self.tree.branch.last_revision_info())
707
def make_branch_with_divergent_history(self):
708
"""Make a branch with divergent history in its repo.
710
The branch's tip will be 'child-2', and the repo will also contain
711
'child-1', which diverges from a common base revision.
713
self.tree.lock_write()
715
r1 = self.tree.commit('1st commit')
716
revno_1, revid_1 = self.tree.branch.last_revision_info()
717
r2 = self.tree.commit('2nd commit', rev_id='child-1')
718
# Undo the second commit
719
self.tree.branch.set_last_revision_info(revno_1, revid_1)
720
self.tree.set_parent_ids([revid_1])
721
# Make a new second commit, child-2. child-2 has diverged from
723
new_r2 = self.tree.commit('2nd commit', rev_id='child-2')
726
def test_not_allow_diverged(self):
727
"""If allow_diverged is not passed, then setting a divergent history
728
returns a Diverged error.
730
self.make_branch_with_divergent_history()
732
FailedSmartServerResponse(('Diverged',)),
733
self.set_last_revision('child-1', 2))
734
# The branch tip was not changed.
735
self.assertEqual('child-2', self.tree.branch.last_revision())
737
def test_allow_diverged(self):
738
"""If allow_diverged is passed, then setting a divergent history
741
self.make_branch_with_divergent_history()
742
branch_token, repo_token = self.lock_branch()
743
response = self.request.execute(
744
'', branch_token, repo_token, 'child-1', 1, 0)
746
SuccessfulSmartServerResponse(('ok', 2, 'child-1')),
749
# The branch tip was changed.
750
self.assertEqual('child-1', self.tree.branch.last_revision())
753
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
755
def test_get_parent_none(self):
756
base_branch = self.make_branch('base')
757
request = smart.branch.SmartServerBranchGetParent(self.get_transport())
758
response = request.execute('base')
760
SuccessfulSmartServerResponse(('',)), response)
762
def test_get_parent_something(self):
763
base_branch = self.make_branch('base')
764
base_branch.set_parent(self.get_url('foo'))
765
request = smart.branch.SmartServerBranchGetParent(self.get_transport())
766
response = request.execute('base')
768
SuccessfulSmartServerResponse(("../foo",)),
772
class TestSmartServerBranchRequestGetTagsBytes(tests.TestCaseWithMemoryTransport):
773
# Only called when the branch format and tags match [yay factory
774
# methods] so only need to test straight forward cases.
776
def test_get_bytes(self):
777
base_branch = self.make_branch('base')
778
request = smart.branch.SmartServerBranchGetTagsBytes(
779
self.get_transport())
780
response = request.execute('base')
782
SuccessfulSmartServerResponse(('',)), response)
785
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
787
def test_get_stacked_on_url(self):
788
base_branch = self.make_branch('base', format='1.6')
789
stacked_branch = self.make_branch('stacked', format='1.6')
790
# typically should be relative
791
stacked_branch.set_stacked_on_url('../base')
792
request = smart.branch.SmartServerBranchRequestGetStackedOnURL(
793
self.get_transport())
794
response = request.execute('stacked')
796
SmartServerResponse(('ok', '../base')),
800
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithMemoryTransport):
803
tests.TestCaseWithMemoryTransport.setUp(self)
280
request.execute(backing.local_abspath('')))
283
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
285
def test_empty(self):
286
backing = self.get_transport()
287
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
288
b = self.make_branch('.')
289
branch_token = b.lock_write()
290
repo_token = b.repository.lock_write()
291
b.repository.unlock()
293
self.assertEqual(SmartServerResponse(('ok',)),
295
backing.local_abspath(''), branch_token, repo_token,
300
def test_not_present_revision_id(self):
301
backing = self.get_transport()
302
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
303
b = self.make_branch('.')
304
branch_token = b.lock_write()
305
repo_token = b.repository.lock_write()
306
b.repository.unlock()
308
revision_id = 'non-existent revision'
310
SmartServerResponse(('NoSuchRevision', revision_id)),
312
backing.local_abspath(''), branch_token, repo_token,
317
def test_revision_id_present(self):
318
backing = self.get_transport()
319
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
320
tree = self.make_branch_and_memory_tree('.')
323
rev_id_utf8 = u'\xc8'.encode('utf-8')
324
r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
325
r2 = tree.commit('2nd commit')
327
branch_token = tree.branch.lock_write()
328
repo_token = tree.branch.repository.lock_write()
329
tree.branch.repository.unlock()
332
SmartServerResponse(('ok',)),
334
backing.local_abspath(''), branch_token, repo_token,
336
self.assertEqual([rev_id_utf8], tree.branch.revision_history())
340
def test_revision_id_present2(self):
341
backing = self.get_transport()
342
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
343
tree = self.make_branch_and_memory_tree('.')
346
rev_id_utf8 = u'\xc8'.encode('utf-8')
347
r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
348
r2 = tree.commit('2nd commit')
350
tree.branch.set_revision_history([])
351
branch_token = tree.branch.lock_write()
352
repo_token = tree.branch.repository.lock_write()
353
tree.branch.repository.unlock()
356
SmartServerResponse(('ok',)),
358
backing.local_abspath(''), branch_token, repo_token,
360
self.assertEqual([rev_id_utf8], tree.branch.revision_history())
365
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
368
tests.TestCaseWithTransport.setUp(self)
369
self.reduceLockdirTimeout()
805
371
def test_lock_write_on_unlocked_branch(self):
806
372
backing = self.get_transport()
807
373
request = smart.branch.SmartServerBranchRequestLockWrite(backing)
808
branch = self.make_branch('.', format='knit')
374
branch = self.make_branch('.')
809
375
repository = branch.repository
810
response = request.execute('')
376
response = request.execute(backing.local_abspath(''))
811
377
branch_nonce = branch.control_files._lock.peek().get('nonce')
812
378
repository_nonce = repository.control_files._lock.peek().get('nonce')
813
379
self.assertEqual(
1188
694
def test_lock_write_on_locked_repo(self):
1189
695
backing = self.get_transport()
1190
696
request = smart.repository.SmartServerRepositoryLockWrite(backing)
1191
repository = self.make_repository('.', format='knit')
697
repository = self.make_repository('.')
1192
698
repository.lock_write()
1193
699
repository.leave_lock_in_place()
1194
700
repository.unlock()
1195
response = request.execute('')
701
response = request.execute(backing.local_abspath(''))
1196
702
self.assertEqual(
1197
703
SmartServerResponse(('LockContention',)), response)
1199
705
def test_lock_write_on_readonly_transport(self):
1200
706
backing = self.get_readonly_transport()
1201
707
request = smart.repository.SmartServerRepositoryLockWrite(backing)
1202
repository = self.make_repository('.', format='knit')
1203
response = request.execute('')
1204
self.assertFalse(response.is_successful())
1205
self.assertEqual('LockFailed', response.args[0])
1208
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
1210
def make_empty_byte_stream(self, repo):
1211
byte_stream = smart.repository._stream_to_byte_stream([], repo._format)
1212
return ''.join(byte_stream)
1215
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
1217
def test_insert_stream_empty(self):
1218
backing = self.get_transport()
1219
request = smart.repository.SmartServerRepositoryInsertStream(backing)
1220
708
repository = self.make_repository('.')
1221
response = request.execute('', '')
1222
self.assertEqual(None, response)
1223
response = request.do_chunk(self.make_empty_byte_stream(repository))
1224
self.assertEqual(None, response)
1225
response = request.do_end()
1226
self.assertEqual(SmartServerResponse(('ok', )), response)
1229
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
1231
def test_insert_stream_empty(self):
1232
backing = self.get_transport()
1233
request = smart.repository.SmartServerRepositoryInsertStreamLocked(
1235
repository = self.make_repository('.', format='knit')
1236
lock_token = repository.lock_write()
1237
response = request.execute('', '', lock_token)
1238
self.assertEqual(None, response)
1239
response = request.do_chunk(self.make_empty_byte_stream(repository))
1240
self.assertEqual(None, response)
1241
response = request.do_end()
1242
self.assertEqual(SmartServerResponse(('ok', )), response)
1245
def test_insert_stream_with_wrong_lock_token(self):
1246
backing = self.get_transport()
1247
request = smart.repository.SmartServerRepositoryInsertStreamLocked(
1249
repository = self.make_repository('.', format='knit')
1250
lock_token = repository.lock_write()
1252
errors.TokenMismatch, request.execute, '', '', 'wrong-token')
1256
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
709
response = request.execute('')
711
SmartServerResponse(('UnlockableTransport',)), response)
714
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
1258
716
def setUp(self):
1259
tests.TestCaseWithMemoryTransport.setUp(self)
717
tests.TestCaseWithTransport.setUp(self)
718
self.reduceLockdirTimeout()
1261
720
def test_unlock_on_locked_repo(self):
1262
721
backing = self.get_transport()
1263
722
request = smart.repository.SmartServerRepositoryUnlock(backing)
1264
repository = self.make_repository('.', format='knit')
723
repository = self.make_repository('.')
1265
724
token = repository.lock_write()
1266
725
repository.leave_lock_in_place()
1267
726
repository.unlock()
1268
response = request.execute('', token)
727
response = request.execute(backing.local_abspath(''), token)
1269
728
self.assertEqual(
1270
729
SmartServerResponse(('ok',)), response)
1271
730
# The repository is now unlocked. Verify that with a new repository
1300
783
SmartServerResponse(('yes',)), response)
1303
class TestSmartServerRepositorySetMakeWorkingTrees(tests.TestCaseWithMemoryTransport):
1305
def test_set_false(self):
1306
backing = self.get_transport()
1307
repo = self.make_repository('.', shared=True)
1308
repo.set_make_working_trees(True)
1309
request_class = smart.repository.SmartServerRepositorySetMakeWorkingTrees
1310
request = request_class(backing)
1311
self.assertEqual(SuccessfulSmartServerResponse(('ok',)),
1312
request.execute('', 'False'))
1313
repo = repo.bzrdir.open_repository()
1314
self.assertFalse(repo.make_working_trees())
1316
def test_set_true(self):
1317
backing = self.get_transport()
1318
repo = self.make_repository('.', shared=True)
1319
repo.set_make_working_trees(False)
1320
request_class = smart.repository.SmartServerRepositorySetMakeWorkingTrees
1321
request = request_class(backing)
1322
self.assertEqual(SuccessfulSmartServerResponse(('ok',)),
1323
request.execute('', 'True'))
1324
repo = repo.bzrdir.open_repository()
1325
self.assertTrue(repo.make_working_trees())
1328
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
1330
def make_repo_needing_autopacking(self, path='.'):
1331
# Make a repo in need of autopacking.
1332
tree = self.make_branch_and_tree('.', format='pack-0.92')
1333
repo = tree.branch.repository
1334
# monkey-patch the pack collection to disable autopacking
1335
repo._pack_collection._max_pack_count = lambda count: count
1337
tree.commit('commit %s' % x)
1338
self.assertEqual(10, len(repo._pack_collection.names()))
1339
del repo._pack_collection._max_pack_count
1342
def test_autopack_needed(self):
1343
repo = self.make_repo_needing_autopacking()
1345
self.addCleanup(repo.unlock)
1346
backing = self.get_transport()
1347
request = smart.packrepository.SmartServerPackRepositoryAutopack(
1349
response = request.execute('')
1350
self.assertEqual(SmartServerResponse(('ok',)), response)
1351
repo._pack_collection.reload_pack_names()
1352
self.assertEqual(1, len(repo._pack_collection.names()))
1354
def test_autopack_not_needed(self):
1355
tree = self.make_branch_and_tree('.', format='pack-0.92')
1356
repo = tree.branch.repository
1358
self.addCleanup(repo.unlock)
1360
tree.commit('commit %s' % x)
1361
backing = self.get_transport()
1362
request = smart.packrepository.SmartServerPackRepositoryAutopack(
1364
response = request.execute('')
1365
self.assertEqual(SmartServerResponse(('ok',)), response)
1366
repo._pack_collection.reload_pack_names()
1367
self.assertEqual(9, len(repo._pack_collection.names()))
1369
def test_autopack_on_nonpack_format(self):
1370
"""A request to autopack a non-pack repo is a no-op."""
1371
repo = self.make_repository('.', format='knit')
1372
backing = self.get_transport()
1373
request = smart.packrepository.SmartServerPackRepositoryAutopack(
1375
response = request.execute('')
1376
self.assertEqual(SmartServerResponse(('ok',)), response)
1379
786
class TestHandlers(tests.TestCase):
1380
787
"""Tests for the request.request_handlers object."""
1382
def test_all_registrations_exist(self):
1383
"""All registered request_handlers can be found."""
1384
# If there's a typo in a register_lazy call, this loop will fail with
1385
# an AttributeError.
1386
for key, item in smart.request.request_handlers.iteritems():
1389
789
def test_registered_methods(self):
1390
790
"""Test that known methods are registered to the correct object."""
1391
791
self.assertEqual(
1392
792
smart.request.request_handlers.get('Branch.get_config_file'),
1393
793
smart.branch.SmartServerBranchGetConfigFile)
1394
794
self.assertEqual(
1395
smart.request.request_handlers.get('Branch.get_parent'),
1396
smart.branch.SmartServerBranchGetParent)
1398
smart.request.request_handlers.get('Branch.get_tags_bytes'),
1399
smart.branch.SmartServerBranchGetTagsBytes)
1401
795
smart.request.request_handlers.get('Branch.lock_write'),
1402
796
smart.branch.SmartServerBranchRequestLockWrite)
1403
797
self.assertEqual(
1407
801
smart.request.request_handlers.get('Branch.revision_history'),
1408
802
smart.branch.SmartServerRequestRevisionHistory)
1409
803
self.assertEqual(
1410
smart.request.request_handlers.get('Branch.set_config_option'),
1411
smart.branch.SmartServerBranchRequestSetConfigOption)
1413
804
smart.request.request_handlers.get('Branch.set_last_revision'),
1414
805
smart.branch.SmartServerBranchRequestSetLastRevision)
1415
806
self.assertEqual(
1416
smart.request.request_handlers.get('Branch.set_last_revision_info'),
1417
smart.branch.SmartServerBranchRequestSetLastRevisionInfo)
1419
807
smart.request.request_handlers.get('Branch.unlock'),
1420
808
smart.branch.SmartServerBranchRequestUnlock)
1421
809
self.assertEqual(
1422
810
smart.request.request_handlers.get('BzrDir.find_repository'),
1423
smart.bzrdir.SmartServerRequestFindRepositoryV1)
1425
smart.request.request_handlers.get('BzrDir.find_repositoryV2'),
1426
smart.bzrdir.SmartServerRequestFindRepositoryV2)
811
smart.bzrdir.SmartServerRequestFindRepository)
1427
812
self.assertEqual(
1428
813
smart.request.request_handlers.get('BzrDirFormat.initialize'),
1429
814
smart.bzrdir.SmartServerRequestInitializeBzrDir)
1430
815
self.assertEqual(
1431
smart.request.request_handlers.get('BzrDir.cloning_metadir'),
1432
smart.bzrdir.SmartServerBzrDirRequestCloningMetaDir)
1434
816
smart.request.request_handlers.get('BzrDir.open_branch'),
1435
817
smart.bzrdir.SmartServerRequestOpenBranch)
1436
818
self.assertEqual(
1437
smart.request.request_handlers.get('BzrDir.open_branchV2'),
1438
smart.bzrdir.SmartServerRequestOpenBranchV2)
1440
smart.request.request_handlers.get('PackRepository.autopack'),
1441
smart.packrepository.SmartServerPackRepositoryAutopack)
1443
819
smart.request.request_handlers.get('Repository.gather_stats'),
1444
820
smart.repository.SmartServerRepositoryGatherStats)
1445
821
self.assertEqual(
1446
smart.request.request_handlers.get('Repository.get_parent_map'),
1447
smart.repository.SmartServerRepositoryGetParentMap)
1449
smart.request.request_handlers.get(
1450
'Repository.get_revision_graph'),
822
smart.request.request_handlers.get('Repository.get_revision_graph'),
1451
823
smart.repository.SmartServerRepositoryGetRevisionGraph)
1452
824
self.assertEqual(
1453
smart.request.request_handlers.get('Repository.get_stream'),
1454
smart.repository.SmartServerRepositoryGetStream)
1456
825
smart.request.request_handlers.get('Repository.has_revision'),
1457
826
smart.repository.SmartServerRequestHasRevision)
1458
827
self.assertEqual(
1459
smart.request.request_handlers.get('Repository.insert_stream'),
1460
smart.repository.SmartServerRepositoryInsertStream)
1462
smart.request.request_handlers.get('Repository.insert_stream_locked'),
1463
smart.repository.SmartServerRepositoryInsertStreamLocked)
1465
828
smart.request.request_handlers.get('Repository.is_shared'),
1466
829
smart.repository.SmartServerRepositoryIsShared)
1467
830
self.assertEqual(
1468
831
smart.request.request_handlers.get('Repository.lock_write'),
1469
832
smart.repository.SmartServerRepositoryLockWrite)
1470
833
self.assertEqual(
834
smart.request.request_handlers.get('Repository.unlock'),
835
smart.repository.SmartServerRepositoryUnlock)
1471
837
smart.request.request_handlers.get('Repository.tarball'),
1472
838
smart.repository.SmartServerRepositoryTarball)
1473
839
self.assertEqual(
1474
smart.request.request_handlers.get('Repository.unlock'),
1475
smart.repository.SmartServerRepositoryUnlock)
1477
840
smart.request.request_handlers.get('Transport.is_readonly'),
1478
841
smart.request.SmartServerIsReadonly)