14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Tests for the smart wire/domain protococl."""
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.
19
27
from StringIO import StringIO
23
from bzrlib import bzrdir, errors, smart, tests
31
from bzrlib import bzrdir, errors, pack, smart, tests
24
32
from bzrlib.smart.request import SmartServerResponse
25
33
import bzrlib.smart.bzrdir
26
34
import bzrlib.smart.branch
27
35
import bzrlib.smart.repository
36
from bzrlib.util import bencode
30
39
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
371
380
def test_lock_write_on_unlocked_branch(self):
372
381
backing = self.get_transport()
373
382
request = smart.branch.SmartServerBranchRequestLockWrite(backing)
374
branch = self.make_branch('.')
383
branch = self.make_branch('.', format='knit')
375
384
repository = branch.repository
376
385
response = request.execute(backing.local_abspath(''))
377
386
branch_nonce = branch.control_files._lock.peek().get('nonce')
398
407
def test_lock_write_with_tokens_on_locked_branch(self):
399
408
backing = self.get_transport()
400
409
request = smart.branch.SmartServerBranchRequestLockWrite(backing)
401
branch = self.make_branch('.')
410
branch = self.make_branch('.', format='knit')
402
411
branch_token = branch.lock_write()
403
412
repo_token = branch.repository.lock_write()
404
413
branch.repository.unlock()
413
422
def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
414
423
backing = self.get_transport()
415
424
request = smart.branch.SmartServerBranchRequestLockWrite(backing)
416
branch = self.make_branch('.')
425
branch = self.make_branch('.', format='knit')
417
426
branch_token = branch.lock_write()
418
427
repo_token = branch.repository.lock_write()
419
428
branch.repository.unlock()
428
437
def test_lock_write_on_locked_repo(self):
429
438
backing = self.get_transport()
430
439
request = smart.branch.SmartServerBranchRequestLockWrite(backing)
431
branch = self.make_branch('.')
440
branch = self.make_branch('.', format='knit')
432
441
branch.repository.lock_write()
433
442
branch.repository.leave_lock_in_place()
434
443
branch.repository.unlock()
441
450
request = smart.branch.SmartServerBranchRequestLockWrite(backing)
442
451
branch = self.make_branch('.')
443
452
response = request.execute('')
445
SmartServerResponse(('UnlockableTransport',)), response)
453
error_name, lock_str, why_str = response.args
454
self.assertFalse(response.is_successful())
455
self.assertEqual('LockFailed', error_name)
448
458
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
454
464
def test_unlock_on_locked_branch_and_repo(self):
455
465
backing = self.get_transport()
456
466
request = smart.branch.SmartServerBranchRequestUnlock(backing)
457
branch = self.make_branch('.')
467
branch = self.make_branch('.', format='knit')
458
468
# Lock the branch
459
469
branch_token = branch.lock_write()
460
470
repo_token = branch.repository.lock_write()
477
487
def test_unlock_on_unlocked_branch_unlocked_repo(self):
478
488
backing = self.get_transport()
479
489
request = smart.branch.SmartServerBranchRequestUnlock(backing)
480
branch = self.make_branch('.')
490
branch = self.make_branch('.', format='knit')
481
491
response = request.execute(
482
492
backing.local_abspath(''), 'branch token', 'repo token')
483
493
self.assertEqual(
486
496
def test_unlock_on_unlocked_branch_locked_repo(self):
487
497
backing = self.get_transport()
488
498
request = smart.branch.SmartServerBranchRequestUnlock(backing)
489
branch = self.make_branch('.')
499
branch = self.make_branch('.', format='knit')
490
500
# Lock the repository.
491
501
repo_token = branch.repository.lock_write()
492
502
branch.repository.leave_lock_in_place()
682
692
def test_lock_write_on_unlocked_repo(self):
683
693
backing = self.get_transport()
684
694
request = smart.repository.SmartServerRepositoryLockWrite(backing)
685
repository = self.make_repository('.')
695
repository = self.make_repository('.', format='knit')
686
696
response = request.execute(backing.local_abspath(''))
687
697
nonce = repository.control_files._lock.peek().get('nonce')
688
698
self.assertEqual(SmartServerResponse(('ok', nonce)), response)
694
704
def test_lock_write_on_locked_repo(self):
695
705
backing = self.get_transport()
696
706
request = smart.repository.SmartServerRepositoryLockWrite(backing)
697
repository = self.make_repository('.')
707
repository = self.make_repository('.', format='knit')
698
708
repository.lock_write()
699
709
repository.leave_lock_in_place()
700
710
repository.unlock()
705
715
def test_lock_write_on_readonly_transport(self):
706
716
backing = self.get_readonly_transport()
707
717
request = smart.repository.SmartServerRepositoryLockWrite(backing)
708
repository = self.make_repository('.')
718
repository = self.make_repository('.', format='knit')
709
719
response = request.execute('')
711
SmartServerResponse(('UnlockableTransport',)), response)
720
self.assertFalse(response.is_successful())
721
self.assertEqual('LockFailed', response.args[0])
714
724
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
720
730
def test_unlock_on_locked_repo(self):
721
731
backing = self.get_transport()
722
732
request = smart.repository.SmartServerRepositoryUnlock(backing)
723
repository = self.make_repository('.')
733
repository = self.make_repository('.', format='knit')
724
734
token = repository.lock_write()
725
735
repository.leave_lock_in_place()
726
736
repository.unlock()
736
746
def test_unlock_on_unlocked_repo(self):
737
747
backing = self.get_transport()
738
748
request = smart.repository.SmartServerRepositoryUnlock(backing)
739
repository = self.make_repository('.')
749
repository = self.make_repository('.', format='knit')
740
750
response = request.execute(backing.local_abspath(''), 'some token')
741
751
self.assertEqual(
742
752
SmartServerResponse(('TokenMismatch',)), response)
766
776
"extraneous file present in tar file")
779
class TestSmartServerRepositoryStreamKnitData(tests.TestCaseWithTransport):
781
def test_fetch_revisions(self):
782
backing = self.get_transport()
783
request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
784
tree = self.make_branch_and_memory_tree('.')
787
rev_id1_utf8 = u'\xc8'.encode('utf-8')
788
rev_id2_utf8 = u'\xc9'.encode('utf-8')
789
r1 = tree.commit('1st commit', rev_id=rev_id1_utf8)
790
r1 = tree.commit('2nd commit', rev_id=rev_id2_utf8)
793
response = request.execute(backing.local_abspath(''), rev_id2_utf8)
794
self.assertEqual(('ok',), response.args)
795
from cStringIO import StringIO
796
unpacker = pack.ContainerReader(StringIO(response.body))
798
for [name], read_bytes in unpacker.iter_records():
800
bytes = read_bytes(None)
801
# The bytes should be a valid bencoded string.
802
bencode.bdecode(bytes)
803
# XXX: assert that the bencoded knit records have the right
806
def test_no_such_revision_error(self):
807
backing = self.get_transport()
808
request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
809
repo = self.make_repository('.')
810
rev_id1_utf8 = u'\xc8'.encode('utf-8')
811
response = request.execute(backing.local_abspath(''), rev_id1_utf8)
813
SmartServerResponse(('NoSuchRevision', rev_id1_utf8)),
769
817
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
771
819
def test_is_readonly_no(self):
819
867
smart.request.request_handlers.get('Repository.gather_stats'),
820
868
smart.repository.SmartServerRepositoryGatherStats)
821
869
self.assertEqual(
822
smart.request.request_handlers.get('Repository.get_revision_graph'),
870
smart.request.request_handlers.get(
871
'Repository.get_revision_graph'),
823
872
smart.repository.SmartServerRepositoryGetRevisionGraph)
824
873
self.assertEqual(
825
874
smart.request.request_handlers.get('Repository.has_revision'),
831
880
smart.request.request_handlers.get('Repository.lock_write'),
832
881
smart.repository.SmartServerRepositoryLockWrite)
833
882
self.assertEqual(
883
smart.request.request_handlers.get(
884
'Repository.stream_knit_data_for_revisions'),
885
smart.repository.SmartServerRepositoryStreamKnitDataForRevisions)
887
smart.request.request_handlers.get('Repository.tarball'),
888
smart.repository.SmartServerRepositoryTarball)
834
890
smart.request.request_handlers.get('Repository.unlock'),
835
891
smart.repository.SmartServerRepositoryUnlock)
836
892
self.assertEqual(
837
smart.request.request_handlers.get('Repository.tarball'),
838
smart.repository.SmartServerRepositoryTarball)
840
893
smart.request.request_handlers.get('Transport.is_readonly'),
841
894
smart.request.SmartServerIsReadonly)