/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Aaron Bentley
  • Date: 2008-02-24 16:42:13 UTC
  • mfrom: (3234 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3235.
  • Revision ID: aaron@aaronbentley.com-20080224164213-eza1lzru5bwuwmmj
Merge with bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
These tests correspond to tests.test_smart, which exercises the server side.
24
24
"""
25
25
 
 
26
import bz2
26
27
from cStringIO import StringIO
27
28
 
28
29
from bzrlib import (
29
 
    bzrdir,
30
30
    errors,
 
31
    graph,
31
32
    pack,
32
33
    remote,
33
34
    repository,
108
109
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
109
110
 
110
111
    def __init__(self, body, fake_client):
111
 
        self._body_buffer = StringIO(body)
 
112
        self.body = body
 
113
        self._body_buffer = None
112
114
        self._fake_client = fake_client
113
115
 
114
116
    def read_body_bytes(self, count=-1):
 
117
        if self._body_buffer is None:
 
118
            self._body_buffer = StringIO(self.body)
115
119
        bytes = self._body_buffer.read(count)
116
120
        if self._body_buffer.tell() == len(self._body_buffer.getvalue()):
117
121
            self._fake_client.expecting_body = False
120
124
    def cancel_read_body(self):
121
125
        self._fake_client.expecting_body = False
122
126
 
 
127
    def read_streamed_body(self):
 
128
        return self.body
 
129
 
123
130
 
124
131
class FakeClient(_SmartClient):
125
132
    """Lookalike for _SmartClient allowing testing."""
126
133
    
127
 
    def __init__(self, responses):
128
 
        # We don't call the super init because there is no medium.
 
134
    def __init__(self, responses, fake_medium_base='fake base'):
129
135
        """Create a FakeClient.
130
136
 
131
 
        :param respones: A list of response-tuple, body-data pairs to be sent
 
137
        :param responses: A list of response-tuple, body-data pairs to be sent
132
138
            back to callers.
133
139
        """
134
140
        self.responses = responses
135
141
        self._calls = []
136
142
        self.expecting_body = False
 
143
        _SmartClient.__init__(self, FakeMedium(fake_medium_base, self._calls))
137
144
 
138
145
    def call(self, method, *args):
139
146
        self._calls.append(('call', method, args))
145
152
        self.expecting_body = True
146
153
        return result[0], FakeProtocol(result[1], self)
147
154
 
 
155
    def call_with_body_bytes_expecting_body(self, method, args, body):
 
156
        self._calls.append(('call_with_body_bytes_expecting_body', method,
 
157
            args, body))
 
158
        result = self.responses.pop(0)
 
159
        self.expecting_body = True
 
160
        return result[0], FakeProtocol(result[1], self)
 
161
 
 
162
 
 
163
class FakeMedium(object):
 
164
 
 
165
    def __init__(self, base, client_calls):
 
166
        self.base = base
 
167
        self.connection = FakeConnection(client_calls)
 
168
        self._client_calls = client_calls
 
169
 
 
170
 
 
171
class FakeConnection(object):
 
172
 
 
173
    def __init__(self, client_calls):
 
174
        self._remote_is_at_least_1_2 = True
 
175
        self._client_calls = client_calls
 
176
 
 
177
    def disconnect(self):
 
178
        self._client_calls.append(('disconnect medium',))
 
179
 
 
180
 
 
181
class TestVfsHas(tests.TestCase):
 
182
 
 
183
    def test_unicode_path(self):
 
184
        client = FakeClient([(('yes',), )], '/')
 
185
        transport = RemoteTransport('bzr://localhost/', _client=client)
 
186
        filename = u'/hell\u00d8'.encode('utf8')
 
187
        result = transport.has(filename)
 
188
        self.assertEqual(
 
189
            [('call', 'has', (filename,))],
 
190
            client._calls)
 
191
        self.assertTrue(result)
 
192
 
148
193
 
149
194
class TestBzrDirOpenBranch(tests.TestCase):
150
195
 
151
196
    def test_branch_present(self):
152
 
        client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no'), )])
153
197
        transport = MemoryTransport()
154
198
        transport.mkdir('quack')
155
199
        transport = transport.clone('quack')
 
200
        client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no', 'no'), )],
 
201
                            transport.base)
156
202
        bzrdir = RemoteBzrDir(transport, _client=client)
157
203
        result = bzrdir.open_branch()
158
204
        self.assertEqual(
159
 
            [('call', 'BzrDir.open_branch', ('///quack/',)),
160
 
             ('call', 'BzrDir.find_repository', ('///quack/',))],
 
205
            [('call', 'BzrDir.open_branch', ('quack/',)),
 
206
             ('call', 'BzrDir.find_repositoryV2', ('quack/',))],
161
207
            client._calls)
162
208
        self.assertIsInstance(result, RemoteBranch)
163
209
        self.assertEqual(bzrdir, result.bzrdir)
164
210
 
165
211
    def test_branch_missing(self):
166
 
        client = FakeClient([(('nobranch',), )])
167
212
        transport = MemoryTransport()
168
213
        transport.mkdir('quack')
169
214
        transport = transport.clone('quack')
 
215
        client = FakeClient([(('nobranch',), )], transport.base)
170
216
        bzrdir = RemoteBzrDir(transport, _client=client)
171
217
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
172
218
        self.assertEqual(
173
 
            [('call', 'BzrDir.open_branch', ('///quack/',))],
174
 
            client._calls)
175
 
 
176
 
    def check_open_repository(self, rich_root, subtrees):
 
219
            [('call', 'BzrDir.open_branch', ('quack/',))],
 
220
            client._calls)
 
221
 
 
222
    def test__get_tree_branch(self):
 
223
        # _get_tree_branch is a form of open_branch, but it should only ask for
 
224
        # branch opening, not any other network requests.
 
225
        calls = []
 
226
        def open_branch():
 
227
            calls.append("Called")
 
228
            return "a-branch"
 
229
        transport = MemoryTransport()
 
230
        # no requests on the network - catches other api calls being made.
 
231
        client = FakeClient([], transport.base)
 
232
        bzrdir = RemoteBzrDir(transport, _client=client)
 
233
        # patch the open_branch call to record that it was called.
 
234
        bzrdir.open_branch = open_branch
 
235
        self.assertEqual((None, "a-branch"), bzrdir._get_tree_branch())
 
236
        self.assertEqual(["Called"], calls)
 
237
        self.assertEqual([], client._calls)
 
238
 
 
239
    def test_url_quoting_of_path(self):
 
240
        # Relpaths on the wire should not be URL-escaped.  So "~" should be
 
241
        # transmitted as "~", not "%7E".
 
242
        transport = RemoteTransport('bzr://localhost/~hello/')
 
243
        client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no', 'no'), )],
 
244
                            transport.base)
 
245
        bzrdir = RemoteBzrDir(transport, _client=client)
 
246
        result = bzrdir.open_branch()
 
247
        self.assertEqual(
 
248
            [('call', 'BzrDir.open_branch', ('~hello/',)),
 
249
             ('call', 'BzrDir.find_repositoryV2', ('~hello/',))],
 
250
            client._calls)
 
251
 
 
252
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
 
253
        transport = MemoryTransport()
 
254
        transport.mkdir('quack')
 
255
        transport = transport.clone('quack')
177
256
        if rich_root:
178
257
            rich_response = 'yes'
179
258
        else:
182
261
            subtree_response = 'yes'
183
262
        else:
184
263
            subtree_response = 'no'
185
 
        client = FakeClient([(('ok', '', rich_response, subtree_response), ),])
186
 
        transport = MemoryTransport()
187
 
        transport.mkdir('quack')
188
 
        transport = transport.clone('quack')
 
264
        client = FakeClient(
 
265
            [(('ok', '', rich_response, subtree_response, external_lookup), ),],
 
266
            transport.base)
189
267
        bzrdir = RemoteBzrDir(transport, _client=client)
190
268
        result = bzrdir.open_repository()
191
269
        self.assertEqual(
192
 
            [('call', 'BzrDir.find_repository', ('///quack/',))],
 
270
            [('call', 'BzrDir.find_repositoryV2', ('quack/',))],
193
271
            client._calls)
194
272
        self.assertIsInstance(result, RemoteRepository)
195
273
        self.assertEqual(bzrdir, result.bzrdir)
201
279
        self.check_open_repository(False, True)
202
280
        self.check_open_repository(True, False)
203
281
        self.check_open_repository(False, False)
 
282
        self.check_open_repository(False, False, 'yes')
204
283
 
205
284
    def test_old_server(self):
206
285
        """RemoteBzrDirFormat should fail to probe if the server version is too
239
318
 
240
319
    def test_empty_branch(self):
241
320
        # in an empty branch we decode the response properly
242
 
        client = FakeClient([(('ok', '0', 'null:'), )])
243
321
        transport = MemoryTransport()
 
322
        client = FakeClient([(('ok', '0', 'null:'), )], transport.base)
244
323
        transport.mkdir('quack')
245
324
        transport = transport.clone('quack')
246
325
        # we do not want bzrdir to make any remote calls
249
328
        result = branch.last_revision_info()
250
329
 
251
330
        self.assertEqual(
252
 
            [('call', 'Branch.last_revision_info', ('///quack/',))],
 
331
            [('call', 'Branch.last_revision_info', ('quack/',))],
253
332
            client._calls)
254
333
        self.assertEqual((0, NULL_REVISION), result)
255
334
 
256
335
    def test_non_empty_branch(self):
257
336
        # in a non-empty branch we also decode the response properly
258
337
        revid = u'\xc8'.encode('utf8')
259
 
        client = FakeClient([(('ok', '2', revid), )])
260
338
        transport = MemoryTransport()
 
339
        client = FakeClient([(('ok', '2', revid), )], transport.base)
261
340
        transport.mkdir('kwaak')
262
341
        transport = transport.clone('kwaak')
263
342
        # we do not want bzrdir to make any remote calls
266
345
        result = branch.last_revision_info()
267
346
 
268
347
        self.assertEqual(
269
 
            [('call', 'Branch.last_revision_info', ('///kwaak/',))],
 
348
            [('call', 'Branch.last_revision_info', ('kwaak/',))],
270
349
            client._calls)
271
350
        self.assertEqual((2, revid), result)
272
351
 
276
355
    def test_set_empty(self):
277
356
        # set_revision_history([]) is translated to calling
278
357
        # Branch.set_last_revision(path, '') on the wire.
 
358
        transport = MemoryTransport()
 
359
        transport.mkdir('branch')
 
360
        transport = transport.clone('branch')
 
361
 
279
362
        client = FakeClient([
280
363
            # lock_write
281
364
            (('ok', 'branch token', 'repo token'), ),
282
365
            # set_last_revision
283
366
            (('ok',), ),
284
367
            # unlock
285
 
            (('ok',), )])
286
 
        transport = MemoryTransport()
287
 
        transport.mkdir('branch')
288
 
        transport = transport.clone('branch')
289
 
 
 
368
            (('ok',), )],
 
369
            transport.base)
290
370
        bzrdir = RemoteBzrDir(transport, _client=False)
291
371
        branch = RemoteBranch(bzrdir, None, _client=client)
292
372
        # This is a hack to work around the problem that RemoteBranch currently
297
377
        result = branch.set_revision_history([])
298
378
        self.assertEqual(
299
379
            [('call', 'Branch.set_last_revision',
300
 
                ('///branch/', 'branch token', 'repo token', 'null:'))],
 
380
                ('branch/', 'branch token', 'repo token', 'null:'))],
301
381
            client._calls)
302
382
        branch.unlock()
303
383
        self.assertEqual(None, result)
305
385
    def test_set_nonempty(self):
306
386
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
307
387
        # Branch.set_last_revision(path, rev-idN) on the wire.
 
388
        transport = MemoryTransport()
 
389
        transport.mkdir('branch')
 
390
        transport = transport.clone('branch')
 
391
 
308
392
        client = FakeClient([
309
393
            # lock_write
310
394
            (('ok', 'branch token', 'repo token'), ),
311
395
            # set_last_revision
312
396
            (('ok',), ),
313
397
            # unlock
314
 
            (('ok',), )])
315
 
        transport = MemoryTransport()
316
 
        transport.mkdir('branch')
317
 
        transport = transport.clone('branch')
318
 
 
 
398
            (('ok',), )],
 
399
            transport.base)
319
400
        bzrdir = RemoteBzrDir(transport, _client=False)
320
401
        branch = RemoteBranch(bzrdir, None, _client=client)
321
402
        # This is a hack to work around the problem that RemoteBranch currently
328
409
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
329
410
        self.assertEqual(
330
411
            [('call', 'Branch.set_last_revision',
331
 
                ('///branch/', 'branch token', 'repo token', 'rev-id2'))],
 
412
                ('branch/', 'branch token', 'repo token', 'rev-id2'))],
332
413
            client._calls)
333
414
        branch.unlock()
334
415
        self.assertEqual(None, result)
368
449
 
369
450
    def test_get_branch_conf(self):
370
451
        # in an empty branch we decode the response properly
371
 
        client = FakeClient([(('ok', ), 'config file body')])
 
452
        client = FakeClient([(('ok', ), 'config file body')], self.get_url())
372
453
        # we need to make a real branch because the remote_branch.control_files
373
454
        # will trigger _ensure_real.
374
455
        branch = self.make_branch('quack')
378
459
        branch = RemoteBranch(bzrdir, None, _client=client)
379
460
        result = branch.control_files.get('branch.conf')
380
461
        self.assertEqual(
381
 
            [('call_expecting_body', 'Branch.get_config_file', ('///quack/',))],
 
462
            [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
382
463
            client._calls)
383
464
        self.assertEqual('config file body', result.read())
384
465
 
386
467
class TestBranchLockWrite(tests.TestCase):
387
468
 
388
469
    def test_lock_write_unlockable(self):
389
 
        client = FakeClient([(('UnlockableTransport', ), '')])
390
470
        transport = MemoryTransport()
 
471
        client = FakeClient([(('UnlockableTransport', ), '')], transport.base)
391
472
        transport.mkdir('quack')
392
473
        transport = transport.clone('quack')
393
474
        # we do not want bzrdir to make any remote calls
395
476
        branch = RemoteBranch(bzrdir, None, _client=client)
396
477
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
397
478
        self.assertEqual(
398
 
            [('call', 'Branch.lock_write', ('///quack/', '', ''))],
 
479
            [('call', 'Branch.lock_write', ('quack/', '', ''))],
399
480
            client._calls)
400
481
 
401
482
 
468
549
        :param transport_path: Path below the root of the MemoryTransport
469
550
            where the repository will be created.
470
551
        """
471
 
        client = FakeClient(responses)
472
552
        transport = MemoryTransport()
473
553
        transport.mkdir(transport_path)
 
554
        client = FakeClient(responses, transport.base)
474
555
        transport = transport.clone(transport_path)
475
556
        # we do not want bzrdir to make any remote calls
476
557
        bzrdir = RemoteBzrDir(transport, _client=False)
489
570
        result = repo.gather_stats(None)
490
571
        self.assertEqual(
491
572
            [('call_expecting_body', 'Repository.gather_stats',
492
 
             ('///quack/','','no'))],
 
573
             ('quack/','','no'))],
493
574
            client._calls)
494
575
        self.assertEqual({'revisions': 2, 'size': 18}, result)
495
576
 
507
588
        result = repo.gather_stats(revid)
508
589
        self.assertEqual(
509
590
            [('call_expecting_body', 'Repository.gather_stats',
510
 
              ('///quick/', revid, 'no'))],
 
591
              ('quick/', revid, 'no'))],
511
592
            client._calls)
512
593
        self.assertEqual({'revisions': 2, 'size': 18,
513
594
                          'firstrev': (123456.300, 3600),
529
610
        result = repo.gather_stats(revid, True)
530
611
        self.assertEqual(
531
612
            [('call_expecting_body', 'Repository.gather_stats',
532
 
              ('///buick/', revid, 'yes'))],
 
613
              ('buick/', revid, 'yes'))],
533
614
            client._calls)
534
615
        self.assertEqual({'revisions': 2, 'size': 18,
535
616
                          'committers': 128,
538
619
                         result)
539
620
 
540
621
 
 
622
class TestRepositoryGetGraph(TestRemoteRepository):
 
623
 
 
624
    def test_get_graph(self):
 
625
        # get_graph returns a graph with the repository as the
 
626
        # parents_provider.
 
627
        responses = []
 
628
        transport_path = 'quack'
 
629
        repo, client = self.setup_fake_client_and_repository(
 
630
            responses, transport_path)
 
631
        graph = repo.get_graph()
 
632
        self.assertEqual(graph._parents_provider, repo)
 
633
 
 
634
 
 
635
class TestRepositoryGetParentMap(TestRemoteRepository):
 
636
 
 
637
    def test_get_parent_map_caching(self):
 
638
        # get_parent_map returns from cache until unlock()
 
639
        # setup a reponse with two revisions
 
640
        r1 = u'\u0e33'.encode('utf8')
 
641
        r2 = u'\u0dab'.encode('utf8')
 
642
        lines = [' '.join([r2, r1]), r1]
 
643
        encoded_body = bz2.compress('\n'.join(lines))
 
644
        responses = [(('ok', ), encoded_body), (('ok', ), encoded_body)]
 
645
 
 
646
        transport_path = 'quack'
 
647
        repo, client = self.setup_fake_client_and_repository(
 
648
            responses, transport_path)
 
649
        repo.lock_read()
 
650
        graph = repo.get_graph()
 
651
        parents = graph.get_parent_map([r2])
 
652
        self.assertEqual({r2: (r1,)}, parents)
 
653
        # locking and unlocking deeper should not reset
 
654
        repo.lock_read()
 
655
        repo.unlock()
 
656
        parents = graph.get_parent_map([r1])
 
657
        self.assertEqual({r1: (NULL_REVISION,)}, parents)
 
658
        self.assertEqual(
 
659
            [('call_with_body_bytes_expecting_body',
 
660
              'Repository.get_parent_map', ('quack/', r2), '\n\n0')],
 
661
            client._calls)
 
662
        repo.unlock()
 
663
        # now we call again, and it should use the second response.
 
664
        repo.lock_read()
 
665
        graph = repo.get_graph()
 
666
        parents = graph.get_parent_map([r1])
 
667
        self.assertEqual({r1: (NULL_REVISION,)}, parents)
 
668
        self.assertEqual(
 
669
            [('call_with_body_bytes_expecting_body',
 
670
              'Repository.get_parent_map', ('quack/', r2), '\n\n0'),
 
671
             ('call_with_body_bytes_expecting_body',
 
672
              'Repository.get_parent_map', ('quack/', r1), '\n\n0'),
 
673
            ],
 
674
            client._calls)
 
675
        repo.unlock()
 
676
 
 
677
    def test_get_parent_map_reconnects_if_unknown_method(self):
 
678
        error_msg = (
 
679
            "Generic bzr smart protocol error: "
 
680
            "bad request 'Repository.get_parent_map'")
 
681
        responses = [
 
682
            (('error', error_msg), ''),
 
683
            (('ok',), '')]
 
684
        transport_path = 'quack'
 
685
        repo, client = self.setup_fake_client_and_repository(
 
686
            responses, transport_path)
 
687
        rev_id = 'revision-id'
 
688
        parents = repo.get_parent_map([rev_id])
 
689
        self.assertEqual(
 
690
            [('call_with_body_bytes_expecting_body',
 
691
              'Repository.get_parent_map', ('quack/', rev_id), '\n\n0'),
 
692
             ('disconnect medium',),
 
693
             ('call_expecting_body', 'Repository.get_revision_graph',
 
694
              ('quack/', ''))],
 
695
            client._calls)
 
696
 
 
697
 
 
698
 
541
699
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
542
700
    
543
701
    def test_null_revision(self):
565
723
        result = repo.get_revision_graph()
566
724
        self.assertEqual(
567
725
            [('call_expecting_body', 'Repository.get_revision_graph',
568
 
             ('///sinhala/', ''))],
 
726
             ('sinhala/', ''))],
569
727
            client._calls)
570
728
        self.assertEqual({r1: (), r2: (r1, )}, result)
571
729
 
585
743
        result = repo.get_revision_graph(r2)
586
744
        self.assertEqual(
587
745
            [('call_expecting_body', 'Repository.get_revision_graph',
588
 
             ('///sinhala/', r2))],
 
746
             ('sinhala/', r2))],
589
747
            client._calls)
590
748
        self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
591
749
 
600
758
            repo.get_revision_graph, revid)
601
759
        self.assertEqual(
602
760
            [('call_expecting_body', 'Repository.get_revision_graph',
603
 
             ('///sinhala/', revid))],
 
761
             ('sinhala/', revid))],
604
762
            client._calls)
605
763
 
606
764
        
614
772
            responses, transport_path)
615
773
        result = repo.is_shared()
616
774
        self.assertEqual(
617
 
            [('call', 'Repository.is_shared', ('///quack/',))],
 
775
            [('call', 'Repository.is_shared', ('quack/',))],
618
776
            client._calls)
619
777
        self.assertEqual(True, result)
620
778
 
626
784
            responses, transport_path)
627
785
        result = repo.is_shared()
628
786
        self.assertEqual(
629
 
            [('call', 'Repository.is_shared', ('///qwack/',))],
 
787
            [('call', 'Repository.is_shared', ('qwack/',))],
630
788
            client._calls)
631
789
        self.assertEqual(False, result)
632
790
 
640
798
            responses, transport_path)
641
799
        result = repo.lock_write()
642
800
        self.assertEqual(
643
 
            [('call', 'Repository.lock_write', ('///quack/', ''))],
 
801
            [('call', 'Repository.lock_write', ('quack/', ''))],
644
802
            client._calls)
645
803
        self.assertEqual('a token', result)
646
804
 
651
809
            responses, transport_path)
652
810
        self.assertRaises(errors.LockContention, repo.lock_write)
653
811
        self.assertEqual(
654
 
            [('call', 'Repository.lock_write', ('///quack/', ''))],
 
812
            [('call', 'Repository.lock_write', ('quack/', ''))],
655
813
            client._calls)
656
814
 
657
815
    def test_lock_write_unlockable(self):
661
819
            responses, transport_path)
662
820
        self.assertRaises(errors.UnlockableTransport, repo.lock_write)
663
821
        self.assertEqual(
664
 
            [('call', 'Repository.lock_write', ('///quack/', ''))],
 
822
            [('call', 'Repository.lock_write', ('quack/', ''))],
665
823
            client._calls)
666
824
 
667
825
 
676
834
        repo.lock_write()
677
835
        repo.unlock()
678
836
        self.assertEqual(
679
 
            [('call', 'Repository.lock_write', ('///quack/', '')),
680
 
             ('call', 'Repository.unlock', ('///quack/', 'a token'))],
 
837
            [('call', 'Repository.lock_write', ('quack/', '')),
 
838
             ('call', 'Repository.unlock', ('quack/', 'a token'))],
681
839
            client._calls)
682
840
 
683
841
    def test_unlock_wrong_token(self):
701
859
            responses, transport_path)
702
860
 
703
861
        # The null revision is always there, so has_revision(None) == True.
704
 
        self.assertEqual(True, repo.has_revision(None))
 
862
        self.assertEqual(True, repo.has_revision(NULL_REVISION))
705
863
 
706
864
        # The remote repo shouldn't be accessed.
707
865
        self.assertEqual([], client._calls)
731
889
        expected_responses = [(('ok',), self.tarball_content),
732
890
            ]
733
891
        expected_calls = [('call_expecting_body', 'Repository.tarball',
734
 
                           ('///repo/', 'bz2',),),
 
892
                           ('repo/', 'bz2',),),
735
893
            ]
736
894
        remote_repo, client = self.setup_fake_client_and_repository(
737
895
            expected_responses, transport_path)
775
933
        pack_file.seek(0)
776
934
        return pack_file
777
935
 
 
936
    def make_pack_stream(self, records):
 
937
        pack_serialiser = pack.ContainerSerialiser()
 
938
        yield pack_serialiser.begin()
 
939
        for bytes, names in records:
 
940
            yield pack_serialiser.bytes_record(bytes, names)
 
941
        yield pack_serialiser.end()
 
942
 
778
943
    def test_bad_pack_from_server(self):
779
944
        """A response with invalid data (e.g. it has a record with multiple
780
945
        names) triggers an exception.
783
948
        malformed data should be.
784
949
        """
785
950
        record = ('bytes', [('name1',), ('name2',)])
786
 
        pack_file = self.make_pack_file([record])
787
 
        responses = [(('ok',), pack_file.getvalue()), ]
 
951
        pack_stream = self.make_pack_stream([record])
 
952
        responses = [(('ok',), pack_stream), ]
788
953
        transport_path = 'quack'
789
954
        repo, client = self.setup_fake_client_and_repository(
790
955
            responses, transport_path)
791
 
        stream = repo.get_data_stream(['revid'])
 
956
        search = graph.SearchResult(set(['revid']), set(), 1, set(['revid']))
 
957
        stream = repo.get_data_stream_for_search(search)
792
958
        self.assertRaises(errors.SmartProtocolError, list, stream)
793
959
    
794
960
    def test_backwards_compatibility(self):
795
961
        """If the server doesn't recognise this request, fallback to VFS."""
796
962
        error_msg = (
797
963
            "Generic bzr smart protocol error: "
798
 
            "bad request 'Repository.stream_knit_data_for_revisions'")
 
964
            "bad request 'Repository.stream_revisions_chunked'")
799
965
        responses = [
800
966
            (('error', error_msg), '')]
801
967
        repo, client = self.setup_fake_client_and_repository(
802
968
            responses, 'path')
803
969
        self.mock_called = False
804
970
        repo._real_repository = MockRealRepository(self)
805
 
        repo.get_data_stream(['revid'])
 
971
        search = graph.SearchResult(set(['revid']), set(), 1, set(['revid']))
 
972
        repo.get_data_stream_for_search(search)
806
973
        self.assertTrue(self.mock_called)
807
974
        self.failIf(client.expecting_body,
808
975
            "The protocol has been left in an unclean state that will cause "
815
982
    def __init__(self, test):
816
983
        self.test = test
817
984
 
818
 
    def get_data_stream(self, revision_ids):
819
 
        self.test.assertEqual(['revid'], revision_ids)
 
985
    def get_data_stream_for_search(self, search):
 
986
        self.test.assertEqual(set(['revid']), search.get_keys())
820
987
        self.test.mock_called = True
821
988
 
822
989