103
104
# the default or a parameterized class, but rather use the
104
105
# TestCaseWithTransport infrastructure to set up a smart server and
106
self.transport_server = self.make_transport_server
108
def make_transport_server(self):
109
return test_server.SmartTCPServer_for_testing('-' + self.id())
107
self.transport_server = smart.server.SmartTCPServer_for_testing
111
109
def get_smart_medium(self):
112
110
"""Get a smart medium to use in tests."""
113
111
return self.get_transport().get_smart_medium()
116
class TestByteStreamToStream(tests.TestCase):
118
def test_repeated_substreams_same_kind_are_one_stream(self):
119
# Make a stream - an iterable of bytestrings.
120
stream = [('text', [versionedfile.FulltextContentFactory(('k1',), None,
121
None, 'foo')]),('text', [
122
versionedfile.FulltextContentFactory(('k2',), None, None, 'bar')])]
123
fmt = bzrdir.format_registry.get('pack-0.92')().repository_format
124
bytes = smart_repo._stream_to_byte_stream(stream, fmt)
126
# Iterate the resulting iterable; checking that we get only one stream
128
fmt, stream = smart_repo._byte_stream_to_stream(bytes)
129
for kind, substream in stream:
130
streams.append((kind, list(substream)))
131
self.assertLength(1, streams)
132
self.assertLength(2, streams[0][1])
135
114
class TestSmartServerResponse(tests.TestCase):
137
116
def test__eq__(self):
138
self.assertEqual(smart_req.SmartServerResponse(('ok', )),
139
smart_req.SmartServerResponse(('ok', )))
140
self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
141
smart_req.SmartServerResponse(('ok', ), 'body'))
142
self.assertNotEqual(smart_req.SmartServerResponse(('ok', )),
143
smart_req.SmartServerResponse(('notok', )))
144
self.assertNotEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
145
smart_req.SmartServerResponse(('ok', )))
117
self.assertEqual(SmartServerResponse(('ok', )),
118
SmartServerResponse(('ok', )))
119
self.assertEqual(SmartServerResponse(('ok', ), 'body'),
120
SmartServerResponse(('ok', ), 'body'))
121
self.assertNotEqual(SmartServerResponse(('ok', )),
122
SmartServerResponse(('notok', )))
123
self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
124
SmartServerResponse(('ok', )))
146
125
self.assertNotEqual(None,
147
smart_req.SmartServerResponse(('ok', )))
126
SmartServerResponse(('ok', )))
149
128
def test__str__(self):
150
129
"""SmartServerResponses can be stringified."""
151
130
self.assertEqual(
152
"<SuccessfulSmartServerResponse args=('args',) body='body'>",
153
str(smart_req.SuccessfulSmartServerResponse(('args',), 'body')))
131
"<SmartServerResponse status=OK args=('args',) body='body'>",
132
str(SuccessfulSmartServerResponse(('args',), 'body')))
154
133
self.assertEqual(
155
"<FailedSmartServerResponse args=('args',) body='body'>",
156
str(smart_req.FailedSmartServerResponse(('args',), 'body')))
134
"<SmartServerResponse status=ERR args=('args',) body='body'>",
135
str(FailedSmartServerResponse(('args',), 'body')))
159
138
class TestSmartServerRequest(tests.TestCaseWithMemoryTransport):
161
140
def test_translate_client_path(self):
162
141
transport = self.get_transport()
163
request = smart_req.SmartServerRequest(transport, 'foo/')
142
request = SmartServerRequest(transport, 'foo/')
164
143
self.assertEqual('./', request.translate_client_path('foo/'))
165
144
self.assertRaises(
166
145
errors.InvalidURLJoin, request.translate_client_path, 'foo/..')
169
148
self.assertRaises(
170
149
errors.PathNotChild, request.translate_client_path, 'bar/')
171
150
self.assertEqual('./baz', request.translate_client_path('foo/baz'))
172
e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
173
self.assertEqual('./' + urlutils.escape(e_acute),
174
request.translate_client_path('foo/' + e_acute))
176
def test_translate_client_path_vfs(self):
177
"""VfsRequests receive escaped paths rather than raw UTF-8."""
178
transport = self.get_transport()
179
request = vfs.VfsRequest(transport, 'foo/')
180
e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
181
escaped = urlutils.escape('foo/' + e_acute)
182
self.assertEqual('./' + urlutils.escape(e_acute),
183
request.translate_client_path(escaped))
185
152
def test_transport_from_client_path(self):
186
153
transport = self.get_transport()
187
request = smart_req.SmartServerRequest(transport, 'foo/')
154
request = SmartServerRequest(transport, 'foo/')
188
155
self.assertEqual(
190
157
request.transport_from_client_path('foo/').base)
193
class TestSmartServerBzrDirRequestCloningMetaDir(
194
tests.TestCaseWithMemoryTransport):
195
"""Tests for BzrDir.cloning_metadir."""
197
def test_cloning_metadir(self):
198
"""When there is a bzrdir present, the call succeeds."""
199
backing = self.get_transport()
200
dir = self.make_bzrdir('.')
201
local_result = dir.cloning_metadir()
202
request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
203
request = request_class(backing)
204
expected = smart_req.SuccessfulSmartServerResponse(
205
(local_result.network_name(),
206
local_result.repository_format.network_name(),
207
('branch', local_result.get_branch_format().network_name())))
208
self.assertEqual(expected, request.execute('', 'False'))
210
def test_cloning_metadir_reference(self):
211
"""The request fails when bzrdir contains a branch reference."""
212
backing = self.get_transport()
213
referenced_branch = self.make_branch('referenced')
214
dir = self.make_bzrdir('.')
215
local_result = dir.cloning_metadir()
216
reference = _mod_branch.BranchReferenceFormat().initialize(
217
dir, target_branch=referenced_branch)
218
reference_url = _mod_branch.BranchReferenceFormat().get_reference(dir)
219
# The server shouldn't try to follow the branch reference, so it's fine
220
# if the referenced branch isn't reachable.
221
backing.rename('referenced', 'moved')
222
request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
223
request = request_class(backing)
224
expected = smart_req.FailedSmartServerResponse(('BranchReference',))
225
self.assertEqual(expected, request.execute('', 'False'))
228
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
229
"""Tests for BzrDir.create_repository."""
231
def test_makes_repository(self):
232
"""When there is a bzrdir present, the call succeeds."""
233
backing = self.get_transport()
234
self.make_bzrdir('.')
235
request_class = smart_dir.SmartServerRequestCreateRepository
236
request = request_class(backing)
237
reference_bzrdir_format = bzrdir.format_registry.get('pack-0.92')()
238
reference_format = reference_bzrdir_format.repository_format
239
network_name = reference_format.network_name()
240
expected = smart_req.SuccessfulSmartServerResponse(
241
('ok', 'no', 'no', 'no', network_name))
242
self.assertEqual(expected, request.execute('', network_name, 'True'))
245
160
class TestSmartServerRequestFindRepository(tests.TestCaseWithMemoryTransport):
246
161
"""Tests for BzrDir.find_repository."""
378
256
def test_missing_dir(self):
379
257
"""Initializing a missing directory should fail like the bzrdir api."""
380
258
backing = self.get_transport()
381
request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
259
request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
382
260
self.assertRaises(errors.NoSuchFile,
383
261
request.execute, 'subdir')
385
263
def test_initialized_dir(self):
386
264
"""Initializing an extant bzrdir should fail like the bzrdir api."""
387
265
backing = self.get_transport()
388
request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
266
request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
389
267
self.make_bzrdir('subdir')
390
268
self.assertRaises(errors.FileExists,
391
269
request.execute, 'subdir')
394
class TestSmartServerRequestBzrDirInitializeEx(
395
tests.TestCaseWithMemoryTransport):
396
"""Basic tests for BzrDir.initialize_ex_1.16 in the smart server.
398
The main unit tests in test_bzrdir exercise the API comprehensively.
401
def test_empty_dir(self):
402
"""Initializing an empty dir should succeed and do it."""
403
backing = self.get_transport()
404
name = self.make_bzrdir('reference')._format.network_name()
405
request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
407
smart_req.SmartServerResponse(('', '', '', '', '', '', name,
408
'False', '', '', '')),
409
request.execute(name, '', 'True', 'False', 'False', '', '', '', '',
411
made_dir = bzrdir.BzrDir.open_from_transport(backing)
412
# no branch, tree or repository is expected with the current
414
self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
415
self.assertRaises(errors.NotBranchError, made_dir.open_branch)
416
self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
418
def test_missing_dir(self):
419
"""Initializing a missing directory should fail like the bzrdir api."""
420
backing = self.get_transport()
421
name = self.make_bzrdir('reference')._format.network_name()
422
request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
423
self.assertRaises(errors.NoSuchFile, request.execute, name,
424
'subdir/dir', 'False', 'False', 'False', '', '', '', '', 'False')
426
def test_initialized_dir(self):
427
"""Initializing an extant directory should fail like the bzrdir api."""
428
backing = self.get_transport()
429
name = self.make_bzrdir('reference')._format.network_name()
430
request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
431
self.make_bzrdir('subdir')
432
self.assertRaises(errors.FileExists, request.execute, name, 'subdir',
433
'False', 'False', 'False', '', '', '', '', 'False')
436
class TestSmartServerRequestOpenBzrDir(tests.TestCaseWithMemoryTransport):
438
def test_no_directory(self):
439
backing = self.get_transport()
440
request = smart_dir.SmartServerRequestOpenBzrDir(backing)
441
self.assertEqual(smart_req.SmartServerResponse(('no', )),
442
request.execute('does-not-exist'))
444
def test_empty_directory(self):
445
backing = self.get_transport()
446
backing.mkdir('empty')
447
request = smart_dir.SmartServerRequestOpenBzrDir(backing)
448
self.assertEqual(smart_req.SmartServerResponse(('no', )),
449
request.execute('empty'))
451
def test_outside_root_client_path(self):
452
backing = self.get_transport()
453
request = smart_dir.SmartServerRequestOpenBzrDir(backing,
454
root_client_path='root')
455
self.assertEqual(smart_req.SmartServerResponse(('no', )),
456
request.execute('not-root'))
459
class TestSmartServerRequestOpenBzrDir_2_1(tests.TestCaseWithMemoryTransport):
461
def test_no_directory(self):
462
backing = self.get_transport()
463
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
464
self.assertEqual(smart_req.SmartServerResponse(('no', )),
465
request.execute('does-not-exist'))
467
def test_empty_directory(self):
468
backing = self.get_transport()
469
backing.mkdir('empty')
470
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
471
self.assertEqual(smart_req.SmartServerResponse(('no', )),
472
request.execute('empty'))
474
def test_present_without_workingtree(self):
475
backing = self.get_transport()
476
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
477
self.make_bzrdir('.')
478
self.assertEqual(smart_req.SmartServerResponse(('yes', 'no')),
481
def test_outside_root_client_path(self):
482
backing = self.get_transport()
483
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing,
484
root_client_path='root')
485
self.assertEqual(smart_req.SmartServerResponse(('no',)),
486
request.execute('not-root'))
489
class TestSmartServerRequestOpenBzrDir_2_1_disk(TestCaseWithChrootedTransport):
491
def test_present_with_workingtree(self):
492
self.vfs_transport_factory = test_server.LocalURLServer
493
backing = self.get_transport()
494
request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
495
bd = self.make_bzrdir('.')
496
bd.create_repository()
498
bd.create_workingtree()
499
self.assertEqual(smart_req.SmartServerResponse(('yes', 'yes')),
503
272
class TestSmartServerRequestOpenBranch(TestCaseWithChrootedTransport):
505
274
def test_no_branch(self):
506
275
"""When there is no branch, ('nobranch', ) is returned."""
507
276
backing = self.get_transport()
508
request = smart_dir.SmartServerRequestOpenBranch(backing)
277
request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
509
278
self.make_bzrdir('.')
510
self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
279
self.assertEqual(SmartServerResponse(('nobranch', )),
511
280
request.execute(''))
513
282
def test_branch(self):
514
283
"""When there is a branch, 'ok' is returned."""
515
284
backing = self.get_transport()
516
request = smart_dir.SmartServerRequestOpenBranch(backing)
285
request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
517
286
self.make_branch('.')
518
self.assertEqual(smart_req.SmartServerResponse(('ok', '')),
287
self.assertEqual(SmartServerResponse(('ok', '')),
519
288
request.execute(''))
521
290
def test_branch_reference(self):
522
291
"""When there is a branch reference, the reference URL is returned."""
523
self.vfs_transport_factory = test_server.LocalURLServer
524
292
backing = self.get_transport()
525
request = smart_dir.SmartServerRequestOpenBranch(backing)
293
request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
526
294
branch = self.make_branch('branch')
527
295
checkout = branch.create_checkout('reference',lightweight=True)
528
reference_url = _mod_branch.BranchReferenceFormat().get_reference(
296
reference_url = BranchReferenceFormat().get_reference(checkout.bzrdir)
530
297
self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
531
self.assertEqual(smart_req.SmartServerResponse(('ok', reference_url)),
298
self.assertEqual(SmartServerResponse(('ok', reference_url)),
532
299
request.execute('reference'))
534
def test_notification_on_branch_from_repository(self):
535
"""When there is a repository, the error should return details."""
536
backing = self.get_transport()
537
request = smart_dir.SmartServerRequestOpenBranch(backing)
538
repo = self.make_repository('.')
539
self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
543
class TestSmartServerRequestOpenBranchV2(TestCaseWithChrootedTransport):
545
def test_no_branch(self):
546
"""When there is no branch, ('nobranch', ) is returned."""
547
backing = self.get_transport()
548
self.make_bzrdir('.')
549
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
550
self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
553
def test_branch(self):
554
"""When there is a branch, 'ok' is returned."""
555
backing = self.get_transport()
556
expected = self.make_branch('.')._format.network_name()
557
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
558
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
559
('branch', expected)),
562
def test_branch_reference(self):
563
"""When there is a branch reference, the reference URL is returned."""
564
self.vfs_transport_factory = test_server.LocalURLServer
565
backing = self.get_transport()
566
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
567
branch = self.make_branch('branch')
568
checkout = branch.create_checkout('reference',lightweight=True)
569
reference_url = _mod_branch.BranchReferenceFormat().get_reference(
571
self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
572
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
573
('ref', reference_url)),
574
request.execute('reference'))
576
def test_stacked_branch(self):
577
"""Opening a stacked branch does not open the stacked-on branch."""
578
trunk = self.make_branch('trunk')
579
feature = self.make_branch('feature')
580
feature.set_stacked_on_url(trunk.base)
582
_mod_branch.Branch.hooks.install_named_hook(
583
'open', opened_branches.append, None)
584
backing = self.get_transport()
585
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
588
response = request.execute('feature')
590
request.teardown_jail()
591
expected_format = feature._format.network_name()
592
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
593
('branch', expected_format)),
595
self.assertLength(1, opened_branches)
597
def test_notification_on_branch_from_repository(self):
598
"""When there is a repository, the error should return details."""
599
backing = self.get_transport()
600
request = smart_dir.SmartServerRequestOpenBranchV2(backing)
601
repo = self.make_repository('.')
602
self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
606
class TestSmartServerRequestOpenBranchV3(TestCaseWithChrootedTransport):
608
def test_no_branch(self):
609
"""When there is no branch, ('nobranch', ) is returned."""
610
backing = self.get_transport()
611
self.make_bzrdir('.')
612
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
613
self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
616
def test_branch(self):
617
"""When there is a branch, 'ok' is returned."""
618
backing = self.get_transport()
619
expected = self.make_branch('.')._format.network_name()
620
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
621
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
622
('branch', expected)),
625
def test_branch_reference(self):
626
"""When there is a branch reference, the reference URL is returned."""
627
self.vfs_transport_factory = test_server.LocalURLServer
628
backing = self.get_transport()
629
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
630
branch = self.make_branch('branch')
631
checkout = branch.create_checkout('reference',lightweight=True)
632
reference_url = _mod_branch.BranchReferenceFormat().get_reference(
634
self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
635
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
636
('ref', reference_url)),
637
request.execute('reference'))
639
def test_stacked_branch(self):
640
"""Opening a stacked branch does not open the stacked-on branch."""
641
trunk = self.make_branch('trunk')
642
feature = self.make_branch('feature')
643
feature.set_stacked_on_url(trunk.base)
645
_mod_branch.Branch.hooks.install_named_hook(
646
'open', opened_branches.append, None)
647
backing = self.get_transport()
648
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
651
response = request.execute('feature')
653
request.teardown_jail()
654
expected_format = feature._format.network_name()
655
self.assertEqual(smart_req.SuccessfulSmartServerResponse(
656
('branch', expected_format)),
658
self.assertLength(1, opened_branches)
660
def test_notification_on_branch_from_repository(self):
661
"""When there is a repository, the error should return details."""
662
backing = self.get_transport()
663
request = smart_dir.SmartServerRequestOpenBranchV3(backing)
664
repo = self.make_repository('.')
665
self.assertEqual(smart_req.SmartServerResponse(
666
('nobranch', 'location is a repository')),
670
302
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
672
304
def test_empty(self):
673
305
"""For an empty branch, the body is empty."""
674
306
backing = self.get_transport()
675
request = smart_branch.SmartServerRequestRevisionHistory(backing)
307
request = smart.branch.SmartServerRequestRevisionHistory(backing)
676
308
self.make_branch('.')
677
self.assertEqual(smart_req.SmartServerResponse(('ok', ), ''),
309
self.assertEqual(SmartServerResponse(('ok', ), ''),
678
310
request.execute(''))
680
312
def test_not_empty(self):
681
313
"""For a non-empty branch, the body is empty."""
682
314
backing = self.get_transport()
683
request = smart_branch.SmartServerRequestRevisionHistory(backing)
315
request = smart.branch.SmartServerRequestRevisionHistory(backing)
684
316
tree = self.make_branch_and_memory_tree('.')
685
317
tree.lock_write()
735
366
r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
737
368
self.assertEqual(
738
smart_req.SmartServerResponse(('ok', '2', rev_id_utf8)),
369
SmartServerResponse(('ok', '2', rev_id_utf8)),
739
370
request.execute(''))
742
class TestSmartServerBranchRequestGetConfigFile(
743
tests.TestCaseWithMemoryTransport):
373
class TestSmartServerBranchRequestGetConfigFile(tests.TestCaseWithMemoryTransport):
745
375
def test_default(self):
746
376
"""With no file, we get empty content."""
747
377
backing = self.get_transport()
748
request = smart_branch.SmartServerBranchGetConfigFile(backing)
378
request = smart.branch.SmartServerBranchGetConfigFile(backing)
749
379
branch = self.make_branch('.')
750
380
# there should be no file by default
752
self.assertEqual(smart_req.SmartServerResponse(('ok', ), content),
382
self.assertEqual(SmartServerResponse(('ok', ), content),
753
383
request.execute(''))
755
385
def test_with_content(self):
756
386
# SmartServerBranchGetConfigFile should return the content from
757
387
# branch.control_files.get('branch.conf') for now - in the future it may
758
# perform more complex processing.
388
# perform more complex processing.
759
389
backing = self.get_transport()
760
request = smart_branch.SmartServerBranchGetConfigFile(backing)
390
request = smart.branch.SmartServerBranchGetConfigFile(backing)
761
391
branch = self.make_branch('.')
762
branch._transport.put_bytes('branch.conf', 'foo bar baz')
763
self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'foo bar baz'),
392
branch.control_files.put_utf8('branch.conf', 'foo bar baz')
393
self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
764
394
request.execute(''))
767
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
769
def get_lock_tokens(self, branch):
770
branch_token = branch.lock_write()
771
repo_token = branch.repository.lock_write()
772
branch.repository.unlock()
773
return branch_token, repo_token
776
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
778
def test_value_name(self):
779
branch = self.make_branch('.')
780
request = smart_branch.SmartServerBranchRequestSetConfigOption(
781
branch.bzrdir.root_transport)
782
branch_token, repo_token = self.get_lock_tokens(branch)
783
config = branch._get_config()
784
result = request.execute('', branch_token, repo_token, 'bar', 'foo',
786
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
787
self.assertEqual('bar', config.get_option('foo'))
791
def test_value_name_section(self):
792
branch = self.make_branch('.')
793
request = smart_branch.SmartServerBranchRequestSetConfigOption(
794
branch.bzrdir.root_transport)
795
branch_token, repo_token = self.get_lock_tokens(branch)
796
config = branch._get_config()
797
result = request.execute('', branch_token, repo_token, 'bar', 'foo',
799
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
800
self.assertEqual('bar', config.get_option('foo', 'gam'))
805
class TestSmartServerBranchRequestSetTagsBytes(TestLockedBranch):
806
# Only called when the branch format and tags match [yay factory
807
# methods] so only need to test straight forward cases.
809
def test_set_bytes(self):
810
base_branch = self.make_branch('base')
811
tag_bytes = base_branch._get_tags_bytes()
812
# get_lock_tokens takes out a lock.
813
branch_token, repo_token = self.get_lock_tokens(base_branch)
814
request = smart_branch.SmartServerBranchSetTagsBytes(
815
self.get_transport())
816
response = request.execute('base', branch_token, repo_token)
817
self.assertEqual(None, response)
818
response = request.do_chunk(tag_bytes)
819
self.assertEqual(None, response)
820
response = request.do_end()
822
smart_req.SuccessfulSmartServerResponse(()), response)
825
def test_lock_failed(self):
826
base_branch = self.make_branch('base')
827
base_branch.lock_write()
828
tag_bytes = base_branch._get_tags_bytes()
829
request = smart_branch.SmartServerBranchSetTagsBytes(
830
self.get_transport())
831
self.assertRaises(errors.TokenMismatch, request.execute,
832
'base', 'wrong token', 'wrong token')
833
# The request handler will keep processing the message parts, so even
834
# if the request fails immediately do_chunk and do_end are still
836
request.do_chunk(tag_bytes)
842
class SetLastRevisionTestBase(TestLockedBranch):
843
"""Base test case for verbs that implement set_last_revision."""
846
tests.TestCaseWithMemoryTransport.setUp(self)
847
backing_transport = self.get_transport()
848
self.request = self.request_class(backing_transport)
849
self.tree = self.make_branch_and_memory_tree('.')
851
def lock_branch(self):
852
return self.get_lock_tokens(self.tree.branch)
854
def unlock_branch(self):
855
self.tree.branch.unlock()
857
def set_last_revision(self, revision_id, revno):
858
branch_token, repo_token = self.lock_branch()
859
response = self._set_last_revision(
860
revision_id, revno, branch_token, repo_token)
864
def assertRequestSucceeds(self, revision_id, revno):
865
response = self.set_last_revision(revision_id, revno)
866
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
870
class TestSetLastRevisionVerbMixin(object):
871
"""Mixin test case for verbs that implement set_last_revision."""
873
def test_set_null_to_null(self):
874
"""An empty branch can have its last revision set to 'null:'."""
875
self.assertRequestSucceeds('null:', 0)
877
def test_NoSuchRevision(self):
878
"""If the revision_id is not present, the verb returns NoSuchRevision.
880
revision_id = 'non-existent revision'
881
self.assertEqual(smart_req.FailedSmartServerResponse(('NoSuchRevision',
883
self.set_last_revision(revision_id, 1))
885
def make_tree_with_two_commits(self):
886
self.tree.lock_write()
888
rev_id_utf8 = u'\xc8'.encode('utf-8')
889
r1 = self.tree.commit('1st commit', rev_id=rev_id_utf8)
890
r2 = self.tree.commit('2nd commit', rev_id='rev-2')
893
def test_branch_last_revision_info_is_updated(self):
894
"""A branch's tip can be set to a revision that is present in its
897
# Make a branch with an empty revision history, but two revisions in
899
self.make_tree_with_two_commits()
900
rev_id_utf8 = u'\xc8'.encode('utf-8')
901
self.tree.branch.set_revision_history([])
903
(0, 'null:'), self.tree.branch.last_revision_info())
904
# We can update the branch to a revision that is present in the
906
self.assertRequestSucceeds(rev_id_utf8, 1)
908
(1, rev_id_utf8), self.tree.branch.last_revision_info())
910
def test_branch_last_revision_info_rewind(self):
911
"""A branch's tip can be set to a revision that is an ancestor of the
914
self.make_tree_with_two_commits()
915
rev_id_utf8 = u'\xc8'.encode('utf-8')
917
(2, 'rev-2'), self.tree.branch.last_revision_info())
918
self.assertRequestSucceeds(rev_id_utf8, 1)
920
(1, rev_id_utf8), self.tree.branch.last_revision_info())
922
def test_TipChangeRejected(self):
923
"""If a pre_change_branch_tip hook raises TipChangeRejected, the verb
924
returns TipChangeRejected.
926
rejection_message = u'rejection message\N{INTERROBANG}'
927
def hook_that_rejects(params):
928
raise errors.TipChangeRejected(rejection_message)
929
_mod_branch.Branch.hooks.install_named_hook(
930
'pre_change_branch_tip', hook_that_rejects, None)
932
smart_req.FailedSmartServerResponse(
933
('TipChangeRejected', rejection_message.encode('utf-8'))),
934
self.set_last_revision('null:', 0))
937
class TestSmartServerBranchRequestSetLastRevision(
938
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
939
"""Tests for Branch.set_last_revision verb."""
941
request_class = smart_branch.SmartServerBranchRequestSetLastRevision
943
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
944
return self.request.execute(
945
'', branch_token, repo_token, revision_id)
948
class TestSmartServerBranchRequestSetLastRevisionInfo(
949
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
950
"""Tests for Branch.set_last_revision_info verb."""
952
request_class = smart_branch.SmartServerBranchRequestSetLastRevisionInfo
954
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
955
return self.request.execute(
956
'', branch_token, repo_token, revno, revision_id)
958
def test_NoSuchRevision(self):
959
"""Branch.set_last_revision_info does not have to return
960
NoSuchRevision if the revision_id is absent.
962
raise tests.TestNotApplicable()
965
class TestSmartServerBranchRequestSetLastRevisionEx(
966
SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
967
"""Tests for Branch.set_last_revision_ex verb."""
969
request_class = smart_branch.SmartServerBranchRequestSetLastRevisionEx
971
def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
972
return self.request.execute(
973
'', branch_token, repo_token, revision_id, 0, 0)
975
def assertRequestSucceeds(self, revision_id, revno):
976
response = self.set_last_revision(revision_id, revno)
978
smart_req.SuccessfulSmartServerResponse(('ok', revno, revision_id)),
981
def test_branch_last_revision_info_rewind(self):
982
"""A branch's tip can be set to a revision that is an ancestor of the
983
current tip, but only if allow_overwrite_descendant is passed.
985
self.make_tree_with_two_commits()
986
rev_id_utf8 = u'\xc8'.encode('utf-8')
988
(2, 'rev-2'), self.tree.branch.last_revision_info())
989
# If allow_overwrite_descendant flag is 0, then trying to set the tip
990
# to an older revision ID has no effect.
991
branch_token, repo_token = self.lock_branch()
992
response = self.request.execute(
993
'', branch_token, repo_token, rev_id_utf8, 0, 0)
995
smart_req.SuccessfulSmartServerResponse(('ok', 2, 'rev-2')),
998
(2, 'rev-2'), self.tree.branch.last_revision_info())
1000
# If allow_overwrite_descendant flag is 1, then setting the tip to an
1002
response = self.request.execute(
1003
'', branch_token, repo_token, rev_id_utf8, 0, 1)
1005
smart_req.SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)),
1007
self.unlock_branch()
1009
(1, rev_id_utf8), self.tree.branch.last_revision_info())
1011
def make_branch_with_divergent_history(self):
1012
"""Make a branch with divergent history in its repo.
1014
The branch's tip will be 'child-2', and the repo will also contain
1015
'child-1', which diverges from a common base revision.
1017
self.tree.lock_write()
1019
r1 = self.tree.commit('1st commit')
1020
revno_1, revid_1 = self.tree.branch.last_revision_info()
1021
r2 = self.tree.commit('2nd commit', rev_id='child-1')
1022
# Undo the second commit
1023
self.tree.branch.set_last_revision_info(revno_1, revid_1)
1024
self.tree.set_parent_ids([revid_1])
1025
# Make a new second commit, child-2. child-2 has diverged from
1027
new_r2 = self.tree.commit('2nd commit', rev_id='child-2')
1030
def test_not_allow_diverged(self):
1031
"""If allow_diverged is not passed, then setting a divergent history
1032
returns a Diverged error.
1034
self.make_branch_with_divergent_history()
1036
smart_req.FailedSmartServerResponse(('Diverged',)),
1037
self.set_last_revision('child-1', 2))
1038
# The branch tip was not changed.
1039
self.assertEqual('child-2', self.tree.branch.last_revision())
1041
def test_allow_diverged(self):
1042
"""If allow_diverged is passed, then setting a divergent history
1045
self.make_branch_with_divergent_history()
1046
branch_token, repo_token = self.lock_branch()
1047
response = self.request.execute(
1048
'', branch_token, repo_token, 'child-1', 1, 0)
1050
smart_req.SuccessfulSmartServerResponse(('ok', 2, 'child-1')),
1052
self.unlock_branch()
1053
# The branch tip was changed.
1054
self.assertEqual('child-1', self.tree.branch.last_revision())
1057
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
1059
def test_get_parent_none(self):
1060
base_branch = self.make_branch('base')
1061
request = smart_branch.SmartServerBranchGetParent(self.get_transport())
1062
response = request.execute('base')
1064
smart_req.SuccessfulSmartServerResponse(('',)), response)
1066
def test_get_parent_something(self):
1067
base_branch = self.make_branch('base')
1068
base_branch.set_parent(self.get_url('foo'))
1069
request = smart_branch.SmartServerBranchGetParent(self.get_transport())
1070
response = request.execute('base')
1072
smart_req.SuccessfulSmartServerResponse(("../foo",)),
1076
class TestSmartServerBranchRequestSetParent(tests.TestCaseWithMemoryTransport):
1078
def test_set_parent_none(self):
1079
branch = self.make_branch('base', format="1.9")
1081
branch._set_parent_location('foo')
1083
request = smart_branch.SmartServerBranchRequestSetParentLocation(
1084
self.get_transport())
1085
branch_token = branch.lock_write()
1086
repo_token = branch.repository.lock_write()
1088
response = request.execute('base', branch_token, repo_token, '')
1090
branch.repository.unlock()
1092
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
1093
self.assertEqual(None, branch.get_parent())
1095
def test_set_parent_something(self):
1096
branch = self.make_branch('base', format="1.9")
1097
request = smart_branch.SmartServerBranchRequestSetParentLocation(
1098
self.get_transport())
1099
branch_token = branch.lock_write()
1100
repo_token = branch.repository.lock_write()
1102
response = request.execute('base', branch_token, repo_token,
1105
branch.repository.unlock()
1107
self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
1108
self.assertEqual('http://bar/', branch.get_parent())
1111
class TestSmartServerBranchRequestGetTagsBytes(
1112
tests.TestCaseWithMemoryTransport):
1113
# Only called when the branch format and tags match [yay factory
1114
# methods] so only need to test straight forward cases.
1116
def test_get_bytes(self):
1117
base_branch = self.make_branch('base')
1118
request = smart_branch.SmartServerBranchGetTagsBytes(
1119
self.get_transport())
1120
response = request.execute('base')
1122
smart_req.SuccessfulSmartServerResponse(('',)), response)
1125
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
1127
def test_get_stacked_on_url(self):
1128
base_branch = self.make_branch('base', format='1.6')
1129
stacked_branch = self.make_branch('stacked', format='1.6')
1130
# typically should be relative
1131
stacked_branch.set_stacked_on_url('../base')
1132
request = smart_branch.SmartServerBranchRequestGetStackedOnURL(
1133
self.get_transport())
1134
response = request.execute('stacked')
1136
smart_req.SmartServerResponse(('ok', '../base')),
397
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithMemoryTransport):
399
def test_empty(self):
400
backing = self.get_transport()
401
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
402
b = self.make_branch('.')
403
branch_token = b.lock_write()
404
repo_token = b.repository.lock_write()
405
b.repository.unlock()
407
self.assertEqual(SmartServerResponse(('ok',)),
409
'', branch_token, repo_token,
414
def test_not_present_revision_id(self):
415
backing = self.get_transport()
416
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
417
b = self.make_branch('.')
418
branch_token = b.lock_write()
419
repo_token = b.repository.lock_write()
420
b.repository.unlock()
422
revision_id = 'non-existent revision'
424
SmartServerResponse(('NoSuchRevision', revision_id)),
426
'', branch_token, repo_token,
431
def test_revision_id_present(self):
432
backing = self.get_transport()
433
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
434
tree = self.make_branch_and_memory_tree('.')
437
rev_id_utf8 = u'\xc8'.encode('utf-8')
438
r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
439
r2 = tree.commit('2nd commit')
441
branch_token = tree.branch.lock_write()
442
repo_token = tree.branch.repository.lock_write()
443
tree.branch.repository.unlock()
446
SmartServerResponse(('ok',)),
448
'', branch_token, repo_token,
450
self.assertEqual([rev_id_utf8], tree.branch.revision_history())
454
def test_revision_id_present2(self):
455
backing = self.get_transport()
456
request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
457
tree = self.make_branch_and_memory_tree('.')
460
rev_id_utf8 = u'\xc8'.encode('utf-8')
461
r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
462
r2 = tree.commit('2nd commit')
464
tree.branch.set_revision_history([])
465
branch_token = tree.branch.lock_write()
466
repo_token = tree.branch.repository.lock_write()
467
tree.branch.repository.unlock()
470
SmartServerResponse(('ok',)),
472
'', branch_token, repo_token,
474
self.assertEqual([rev_id_utf8], tree.branch.revision_history())
1140
479
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithMemoryTransport):
1398
693
# Note that it still returns body (of zero bytes).
1399
self.assertEqual(smart_req.SmartServerResponse(
1400
('nosuchrevision', 'missingrevision', ), ''),
1401
request.execute('', 'missingrevision'))
1404
class TestSmartServerRepositoryGetRevIdForRevno(
1405
tests.TestCaseWithMemoryTransport):
1407
def test_revno_found(self):
1408
backing = self.get_transport()
1409
request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
1410
tree = self.make_branch_and_memory_tree('.')
1413
rev1_id_utf8 = u'\xc8'.encode('utf-8')
1414
rev2_id_utf8 = u'\xc9'.encode('utf-8')
1415
tree.commit('1st commit', rev_id=rev1_id_utf8)
1416
tree.commit('2nd commit', rev_id=rev2_id_utf8)
1419
self.assertEqual(smart_req.SmartServerResponse(('ok', rev1_id_utf8)),
1420
request.execute('', 1, (2, rev2_id_utf8)))
1422
def test_known_revid_missing(self):
1423
backing = self.get_transport()
1424
request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
1425
repo = self.make_repository('.')
1427
smart_req.FailedSmartServerResponse(('nosuchrevision', 'ghost')),
1428
request.execute('', 1, (2, 'ghost')))
1430
def test_history_incomplete(self):
1431
backing = self.get_transport()
1432
request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
1433
parent = self.make_branch_and_memory_tree('parent', format='1.9')
1435
parent.add([''], ['TREE_ROOT'])
1436
r1 = parent.commit(message='first commit')
1437
r2 = parent.commit(message='second commit')
1439
local = self.make_branch_and_memory_tree('local', format='1.9')
1440
local.branch.pull(parent.branch)
1441
local.set_parent_ids([r2])
1442
r3 = local.commit(message='local commit')
1443
local.branch.create_clone_on_transport(
1444
self.get_transport('stacked'), stacked_on=self.get_url('parent'))
1446
smart_req.SmartServerResponse(('history-incomplete', 2, r2)),
1447
request.execute('stacked', 1, (3, r3)))
1450
class TestSmartServerRepositoryGetStream(tests.TestCaseWithMemoryTransport):
1452
def make_two_commit_repo(self):
1453
tree = self.make_branch_and_memory_tree('.')
1456
r1 = tree.commit('1st commit')
1457
r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
1459
repo = tree.branch.repository
1462
def test_ancestry_of(self):
1463
"""The search argument may be a 'ancestry-of' some heads'."""
1464
backing = self.get_transport()
1465
request = smart_repo.SmartServerRepositoryGetStream(backing)
1466
repo, r1, r2 = self.make_two_commit_repo()
1467
fetch_spec = ['ancestry-of', r2]
1468
lines = '\n'.join(fetch_spec)
1469
request.execute('', repo._format.network_name())
1470
response = request.do_body(lines)
1471
self.assertEqual(('ok',), response.args)
1472
stream_bytes = ''.join(response.body_stream)
1473
self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
1475
def test_search(self):
1476
"""The search argument may be a 'search' of some explicit keys."""
1477
backing = self.get_transport()
1478
request = smart_repo.SmartServerRepositoryGetStream(backing)
1479
repo, r1, r2 = self.make_two_commit_repo()
1480
fetch_spec = ['search', '%s %s' % (r1, r2), 'null:', '2']
1481
lines = '\n'.join(fetch_spec)
1482
request.execute('', repo._format.network_name())
1483
response = request.do_body(lines)
1484
self.assertEqual(('ok',), response.args)
1485
stream_bytes = ''.join(response.body_stream)
1486
self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
695
SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
696
request.execute('', 'missingrevision'))
1489
699
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
1575
790
def test_is_shared(self):
1576
791
"""For a shared repository, ('yes', ) is returned."""
1577
792
backing = self.get_transport()
1578
request = smart_repo.SmartServerRepositoryIsShared(backing)
793
request = smart.repository.SmartServerRepositoryIsShared(backing)
1579
794
self.make_repository('.', shared=True)
1580
self.assertEqual(smart_req.SmartServerResponse(('yes', )),
795
self.assertEqual(SmartServerResponse(('yes', )),
1581
796
request.execute('', ))
1583
798
def test_is_not_shared(self):
1584
799
"""For a shared repository, ('no', ) is returned."""
1585
800
backing = self.get_transport()
1586
request = smart_repo.SmartServerRepositoryIsShared(backing)
801
request = smart.repository.SmartServerRepositoryIsShared(backing)
1587
802
self.make_repository('.', shared=False)
1588
self.assertEqual(smart_req.SmartServerResponse(('no', )),
803
self.assertEqual(SmartServerResponse(('no', )),
1589
804
request.execute('', ))
1592
807
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
810
tests.TestCaseWithMemoryTransport.setUp(self)
1594
812
def test_lock_write_on_unlocked_repo(self):
1595
813
backing = self.get_transport()
1596
request = smart_repo.SmartServerRepositoryLockWrite(backing)
814
request = smart.repository.SmartServerRepositoryLockWrite(backing)
1597
815
repository = self.make_repository('.', format='knit')
1598
816
response = request.execute('')
1599
817
nonce = repository.control_files._lock.peek().get('nonce')
1600
self.assertEqual(smart_req.SmartServerResponse(('ok', nonce)), response)
818
self.assertEqual(SmartServerResponse(('ok', nonce)), response)
1601
819
# The repository is now locked. Verify that with a new repository
1603
821
new_repo = repository.bzrdir.open_repository()
1604
822
self.assertRaises(errors.LockContention, new_repo.lock_write)
1606
request = smart_repo.SmartServerRepositoryUnlock(backing)
1607
response = request.execute('', nonce)
1609
824
def test_lock_write_on_locked_repo(self):
1610
825
backing = self.get_transport()
1611
request = smart_repo.SmartServerRepositoryLockWrite(backing)
826
request = smart.repository.SmartServerRepositoryLockWrite(backing)
1612
827
repository = self.make_repository('.', format='knit')
1613
repo_token = repository.lock_write()
828
repository.lock_write()
1614
829
repository.leave_lock_in_place()
1615
830
repository.unlock()
1616
831
response = request.execute('')
1617
832
self.assertEqual(
1618
smart_req.SmartServerResponse(('LockContention',)), response)
1620
repository.lock_write(repo_token)
1621
repository.dont_leave_lock_in_place()
833
SmartServerResponse(('LockContention',)), response)
1624
835
def test_lock_write_on_readonly_transport(self):
1625
836
backing = self.get_readonly_transport()
1626
request = smart_repo.SmartServerRepositoryLockWrite(backing)
837
request = smart.repository.SmartServerRepositoryLockWrite(backing)
1627
838
repository = self.make_repository('.', format='knit')
1628
839
response = request.execute('')
1629
840
self.assertFalse(response.is_successful())
1630
841
self.assertEqual('LockFailed', response.args[0])
1633
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
1635
def make_empty_byte_stream(self, repo):
1636
byte_stream = smart_repo._stream_to_byte_stream([], repo._format)
1637
return ''.join(byte_stream)
1640
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
1642
def test_insert_stream_empty(self):
1643
backing = self.get_transport()
1644
request = smart_repo.SmartServerRepositoryInsertStream(backing)
1645
repository = self.make_repository('.')
1646
response = request.execute('', '')
1647
self.assertEqual(None, response)
1648
response = request.do_chunk(self.make_empty_byte_stream(repository))
1649
self.assertEqual(None, response)
1650
response = request.do_end()
1651
self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
1654
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
1656
def test_insert_stream_empty(self):
1657
backing = self.get_transport()
1658
request = smart_repo.SmartServerRepositoryInsertStreamLocked(
1660
repository = self.make_repository('.', format='knit')
1661
lock_token = repository.lock_write()
1662
response = request.execute('', '', lock_token)
1663
self.assertEqual(None, response)
1664
response = request.do_chunk(self.make_empty_byte_stream(repository))
1665
self.assertEqual(None, response)
1666
response = request.do_end()
1667
self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
1670
def test_insert_stream_with_wrong_lock_token(self):
1671
backing = self.get_transport()
1672
request = smart_repo.SmartServerRepositoryInsertStreamLocked(
1674
repository = self.make_repository('.', format='knit')
1675
lock_token = repository.lock_write()
1677
errors.TokenMismatch, request.execute, '', '', 'wrong-token')
1681
844
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
1683
846
def setUp(self):
1702
865
def test_unlock_on_unlocked_repo(self):
1703
866
backing = self.get_transport()
1704
request = smart_repo.SmartServerRepositoryUnlock(backing)
867
request = smart.repository.SmartServerRepositoryUnlock(backing)
1705
868
repository = self.make_repository('.', format='knit')
1706
869
response = request.execute('', 'some token')
1707
870
self.assertEqual(
1708
smart_req.SmartServerResponse(('TokenMismatch',)), response)
871
SmartServerResponse(('TokenMismatch',)), response)
874
class TestSmartServerRepositoryTarball(tests.TestCaseWithTransport):
876
def test_repository_tarball(self):
877
backing = self.get_transport()
878
request = smart.repository.SmartServerRepositoryTarball(backing)
879
repository = self.make_repository('.')
880
# make some extraneous junk in the repository directory which should
882
self.build_tree(['.bzr/repository/extra-junk'])
883
response = request.execute('', 'bz2')
884
self.assertEqual(('ok',), response.args)
885
# body should be a tbz2
886
body_file = StringIO(response.body)
887
body_tar = tarfile.open('body_tar.tbz2', fileobj=body_file,
889
# let's make sure there are some key repository components inside it.
890
# the tarfile returns directories with trailing slashes...
891
names = set([n.rstrip('/') for n in body_tar.getnames()])
892
self.assertTrue('.bzr/repository/lock' in names)
893
self.assertTrue('.bzr/repository/format' in names)
894
self.assertTrue('.bzr/repository/extra-junk' not in names,
895
"extraneous file present in tar file")
898
class TestSmartServerRepositoryStreamKnitData(tests.TestCaseWithMemoryTransport):
900
def test_fetch_revisions(self):
901
backing = self.get_transport()
902
request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
903
tree = self.make_branch_and_memory_tree('.')
906
rev_id1_utf8 = u'\xc8'.encode('utf-8')
907
rev_id2_utf8 = u'\xc9'.encode('utf-8')
908
r1 = tree.commit('1st commit', rev_id=rev_id1_utf8)
909
r1 = tree.commit('2nd commit', rev_id=rev_id2_utf8)
912
response = request.execute('', rev_id2_utf8)
913
self.assertEqual(('ok',), response.args)
914
unpacker = pack.ContainerReader(StringIO(response.body))
916
for [name], read_bytes in unpacker.iter_records():
918
bytes = read_bytes(None)
919
# The bytes should be a valid bencoded string.
920
bencode.bdecode(bytes)
921
# XXX: assert that the bencoded knit records have the right
924
def test_no_such_revision_error(self):
925
backing = self.get_transport()
926
request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
927
repo = self.make_repository('.')
928
rev_id1_utf8 = u'\xc8'.encode('utf-8')
929
response = request.execute('', rev_id1_utf8)
931
SmartServerResponse(('NoSuchRevision', rev_id1_utf8)),
935
class TestSmartServerRepositoryStreamRevisionsChunked(tests.TestCaseWithMemoryTransport):
937
def test_fetch_revisions(self):
938
backing = self.get_transport()
939
request = smart.repository.SmartServerRepositoryStreamRevisionsChunked(
941
tree = self.make_branch_and_memory_tree('.')
944
rev_id1_utf8 = u'\xc8'.encode('utf-8')
945
rev_id2_utf8 = u'\xc9'.encode('utf-8')
946
tree.commit('1st commit', rev_id=rev_id1_utf8)
947
tree.commit('2nd commit', rev_id=rev_id2_utf8)
950
response = request.execute('')
951
self.assertEqual(None, response)
952
response = request.do_body("%s\n%s\n1" % (rev_id2_utf8, rev_id1_utf8))
953
self.assertEqual(('ok',), response.args)
954
parser = pack.ContainerPushParser()
956
for stream_bytes in response.body_stream:
957
parser.accept_bytes(stream_bytes)
958
for [name], record_bytes in parser.read_pending_records():
960
# The bytes should be a valid bencoded string.
961
bencode.bdecode(record_bytes)
962
# XXX: assert that the bencoded knit records have the right
965
def test_no_such_revision_error(self):
966
backing = self.get_transport()
967
request = smart.repository.SmartServerRepositoryStreamRevisionsChunked(
969
repo = self.make_repository('.')
970
rev_id1_utf8 = u'\xc8'.encode('utf-8')
971
response = request.execute('')
972
self.assertEqual(None, response)
973
response = request.do_body("%s\n\n1" % (rev_id1_utf8,))
975
FailedSmartServerResponse(('NoSuchRevision', )),
1711
979
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
1713
981
def test_is_readonly_no(self):
1714
982
backing = self.get_transport()
1715
request = smart_req.SmartServerIsReadonly(backing)
983
request = smart.request.SmartServerIsReadonly(backing)
1716
984
response = request.execute()
1717
985
self.assertEqual(
1718
smart_req.SmartServerResponse(('no',)), response)
986
SmartServerResponse(('no',)), response)
1720
988
def test_is_readonly_yes(self):
1721
989
backing = self.get_readonly_transport()
1722
request = smart_req.SmartServerIsReadonly(backing)
990
request = smart.request.SmartServerIsReadonly(backing)
1723
991
response = request.execute()
1724
992
self.assertEqual(
1725
smart_req.SmartServerResponse(('yes',)), response)
1728
class TestSmartServerRepositorySetMakeWorkingTrees(
1729
tests.TestCaseWithMemoryTransport):
1731
def test_set_false(self):
1732
backing = self.get_transport()
1733
repo = self.make_repository('.', shared=True)
1734
repo.set_make_working_trees(True)
1735
request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
1736
request = request_class(backing)
1737
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
1738
request.execute('', 'False'))
1739
repo = repo.bzrdir.open_repository()
1740
self.assertFalse(repo.make_working_trees())
1742
def test_set_true(self):
1743
backing = self.get_transport()
1744
repo = self.make_repository('.', shared=True)
1745
repo.set_make_working_trees(False)
1746
request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
1747
request = request_class(backing)
1748
self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
1749
request.execute('', 'True'))
1750
repo = repo.bzrdir.open_repository()
1751
self.assertTrue(repo.make_working_trees())
1754
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
1756
def make_repo_needing_autopacking(self, path='.'):
1757
# Make a repo in need of autopacking.
1758
tree = self.make_branch_and_tree('.', format='pack-0.92')
1759
repo = tree.branch.repository
1760
# monkey-patch the pack collection to disable autopacking
1761
repo._pack_collection._max_pack_count = lambda count: count
1763
tree.commit('commit %s' % x)
1764
self.assertEqual(10, len(repo._pack_collection.names()))
1765
del repo._pack_collection._max_pack_count
1768
def test_autopack_needed(self):
1769
repo = self.make_repo_needing_autopacking()
1771
self.addCleanup(repo.unlock)
1772
backing = self.get_transport()
1773
request = smart_packrepo.SmartServerPackRepositoryAutopack(
1775
response = request.execute('')
1776
self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
1777
repo._pack_collection.reload_pack_names()
1778
self.assertEqual(1, len(repo._pack_collection.names()))
1780
def test_autopack_not_needed(self):
1781
tree = self.make_branch_and_tree('.', format='pack-0.92')
1782
repo = tree.branch.repository
1784
self.addCleanup(repo.unlock)
1786
tree.commit('commit %s' % x)
1787
backing = self.get_transport()
1788
request = smart_packrepo.SmartServerPackRepositoryAutopack(
1790
response = request.execute('')
1791
self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
1792
repo._pack_collection.reload_pack_names()
1793
self.assertEqual(9, len(repo._pack_collection.names()))
1795
def test_autopack_on_nonpack_format(self):
1796
"""A request to autopack a non-pack repo is a no-op."""
1797
repo = self.make_repository('.', format='knit')
1798
backing = self.get_transport()
1799
request = smart_packrepo.SmartServerPackRepositoryAutopack(
1801
response = request.execute('')
1802
self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
1805
class TestSmartServerVfsGet(tests.TestCaseWithMemoryTransport):
1807
def test_unicode_path(self):
1808
"""VFS requests expect unicode paths to be escaped."""
1809
filename = u'foo\N{INTERROBANG}'
1810
filename_escaped = urlutils.escape(filename)
1811
backing = self.get_transport()
1812
request = vfs.GetRequest(backing)
1813
backing.put_bytes_non_atomic(filename_escaped, 'contents')
1814
self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'contents'),
1815
request.execute(filename_escaped))
993
SmartServerResponse(('yes',)), response)
1818
996
class TestHandlers(tests.TestCase):
1819
997
"""Tests for the request.request_handlers object."""
1821
def test_all_registrations_exist(self):
1822
"""All registered request_handlers can be found."""
1823
# If there's a typo in a register_lazy call, this loop will fail with
1824
# an AttributeError.
1825
for key, item in smart_req.request_handlers.iteritems():
1828
def assertHandlerEqual(self, verb, handler):
1829
self.assertEqual(smart_req.request_handlers.get(verb), handler)
1831
999
def test_registered_methods(self):
1832
1000
"""Test that known methods are registered to the correct object."""
1833
self.assertHandlerEqual('Branch.get_config_file',
1834
smart_branch.SmartServerBranchGetConfigFile)
1835
self.assertHandlerEqual('Branch.get_parent',
1836
smart_branch.SmartServerBranchGetParent)
1837
self.assertHandlerEqual('Branch.get_tags_bytes',
1838
smart_branch.SmartServerBranchGetTagsBytes)
1839
self.assertHandlerEqual('Branch.lock_write',
1840
smart_branch.SmartServerBranchRequestLockWrite)
1841
self.assertHandlerEqual('Branch.last_revision_info',
1842
smart_branch.SmartServerBranchRequestLastRevisionInfo)
1843
self.assertHandlerEqual('Branch.revision_history',
1844
smart_branch.SmartServerRequestRevisionHistory)
1845
self.assertHandlerEqual('Branch.set_config_option',
1846
smart_branch.SmartServerBranchRequestSetConfigOption)
1847
self.assertHandlerEqual('Branch.set_last_revision',
1848
smart_branch.SmartServerBranchRequestSetLastRevision)
1849
self.assertHandlerEqual('Branch.set_last_revision_info',
1850
smart_branch.SmartServerBranchRequestSetLastRevisionInfo)
1851
self.assertHandlerEqual('Branch.set_last_revision_ex',
1852
smart_branch.SmartServerBranchRequestSetLastRevisionEx)
1853
self.assertHandlerEqual('Branch.set_parent_location',
1854
smart_branch.SmartServerBranchRequestSetParentLocation)
1855
self.assertHandlerEqual('Branch.unlock',
1856
smart_branch.SmartServerBranchRequestUnlock)
1857
self.assertHandlerEqual('BzrDir.find_repository',
1858
smart_dir.SmartServerRequestFindRepositoryV1)
1859
self.assertHandlerEqual('BzrDir.find_repositoryV2',
1860
smart_dir.SmartServerRequestFindRepositoryV2)
1861
self.assertHandlerEqual('BzrDirFormat.initialize',
1862
smart_dir.SmartServerRequestInitializeBzrDir)
1863
self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
1864
smart_dir.SmartServerRequestBzrDirInitializeEx)
1865
self.assertHandlerEqual('BzrDir.cloning_metadir',
1866
smart_dir.SmartServerBzrDirRequestCloningMetaDir)
1867
self.assertHandlerEqual('BzrDir.get_config_file',
1868
smart_dir.SmartServerBzrDirRequestConfigFile)
1869
self.assertHandlerEqual('BzrDir.open_branch',
1870
smart_dir.SmartServerRequestOpenBranch)
1871
self.assertHandlerEqual('BzrDir.open_branchV2',
1872
smart_dir.SmartServerRequestOpenBranchV2)
1873
self.assertHandlerEqual('BzrDir.open_branchV3',
1874
smart_dir.SmartServerRequestOpenBranchV3)
1875
self.assertHandlerEqual('PackRepository.autopack',
1876
smart_packrepo.SmartServerPackRepositoryAutopack)
1877
self.assertHandlerEqual('Repository.gather_stats',
1878
smart_repo.SmartServerRepositoryGatherStats)
1879
self.assertHandlerEqual('Repository.get_parent_map',
1880
smart_repo.SmartServerRepositoryGetParentMap)
1881
self.assertHandlerEqual('Repository.get_rev_id_for_revno',
1882
smart_repo.SmartServerRepositoryGetRevIdForRevno)
1883
self.assertHandlerEqual('Repository.get_revision_graph',
1884
smart_repo.SmartServerRepositoryGetRevisionGraph)
1885
self.assertHandlerEqual('Repository.get_stream',
1886
smart_repo.SmartServerRepositoryGetStream)
1887
self.assertHandlerEqual('Repository.has_revision',
1888
smart_repo.SmartServerRequestHasRevision)
1889
self.assertHandlerEqual('Repository.insert_stream',
1890
smart_repo.SmartServerRepositoryInsertStream)
1891
self.assertHandlerEqual('Repository.insert_stream_locked',
1892
smart_repo.SmartServerRepositoryInsertStreamLocked)
1893
self.assertHandlerEqual('Repository.is_shared',
1894
smart_repo.SmartServerRepositoryIsShared)
1895
self.assertHandlerEqual('Repository.lock_write',
1896
smart_repo.SmartServerRepositoryLockWrite)
1897
self.assertHandlerEqual('Repository.tarball',
1898
smart_repo.SmartServerRepositoryTarball)
1899
self.assertHandlerEqual('Repository.unlock',
1900
smart_repo.SmartServerRepositoryUnlock)
1901
self.assertHandlerEqual('Transport.is_readonly',
1902
smart_req.SmartServerIsReadonly)
1002
smart.request.request_handlers.get('Branch.get_config_file'),
1003
smart.branch.SmartServerBranchGetConfigFile)
1005
smart.request.request_handlers.get('Branch.lock_write'),
1006
smart.branch.SmartServerBranchRequestLockWrite)
1008
smart.request.request_handlers.get('Branch.last_revision_info'),
1009
smart.branch.SmartServerBranchRequestLastRevisionInfo)
1011
smart.request.request_handlers.get('Branch.revision_history'),
1012
smart.branch.SmartServerRequestRevisionHistory)
1014
smart.request.request_handlers.get('Branch.set_last_revision'),
1015
smart.branch.SmartServerBranchRequestSetLastRevision)
1017
smart.request.request_handlers.get('Branch.unlock'),
1018
smart.branch.SmartServerBranchRequestUnlock)
1020
smart.request.request_handlers.get('BzrDir.find_repository'),
1021
smart.bzrdir.SmartServerRequestFindRepositoryV1)
1023
smart.request.request_handlers.get('BzrDir.find_repositoryV2'),
1024
smart.bzrdir.SmartServerRequestFindRepositoryV2)
1026
smart.request.request_handlers.get('BzrDirFormat.initialize'),
1027
smart.bzrdir.SmartServerRequestInitializeBzrDir)
1029
smart.request.request_handlers.get('BzrDir.open_branch'),
1030
smart.bzrdir.SmartServerRequestOpenBranch)
1032
smart.request.request_handlers.get('Repository.gather_stats'),
1033
smart.repository.SmartServerRepositoryGatherStats)
1035
smart.request.request_handlers.get('Repository.get_parent_map'),
1036
smart.repository.SmartServerRepositoryGetParentMap)
1038
smart.request.request_handlers.get(
1039
'Repository.get_revision_graph'),
1040
smart.repository.SmartServerRepositoryGetRevisionGraph)
1042
smart.request.request_handlers.get('Repository.has_revision'),
1043
smart.repository.SmartServerRequestHasRevision)
1045
smart.request.request_handlers.get('Repository.is_shared'),
1046
smart.repository.SmartServerRepositoryIsShared)
1048
smart.request.request_handlers.get('Repository.lock_write'),
1049
smart.repository.SmartServerRepositoryLockWrite)
1051
smart.request.request_handlers.get('Repository.tarball'),
1052
smart.repository.SmartServerRepositoryTarball)
1054
smart.request.request_handlers.get('Repository.unlock'),
1055
smart.repository.SmartServerRepositoryUnlock)
1057
smart.request.request_handlers.get('Transport.is_readonly'),
1058
smart.request.SmartServerIsReadonly)