~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart_transport.py

  • Committer: Andrew Bennetts
  • Date: 2008-05-07 10:33:00 UTC
  • mto: This revision was merged to the branch mainline in revision 3428.
  • Revision ID: andrew.bennetts@canonical.com-20080507103300-d0vr775rbjj83xte
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1230
1230
    and the request dispatching.
1231
1231
 
1232
1232
    Note: these tests are rudimentary versions of the command object tests in
1233
 
    test_remote.py.
 
1233
    test_smart.py.
1234
1234
    """
1235
1235
        
1236
1236
    def test_hello(self):
1369
1369
        
1370
1370
    def test_use_connection_factory(self):
1371
1371
        # We want to be able to pass a client as a parameter to RemoteTransport.
1372
 
        input = StringIO('ok\x011\n' + 'ok\n3\nbardone\n')
 
1372
        input = StringIO('ok\n3\nbardone\n')
1373
1373
        output = StringIO()
1374
1374
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1375
1375
        transport = remote.RemoteTransport(
1376
1376
            'bzr://localhost/', medium=client_medium)
 
1377
        # Disable version detection.
 
1378
        transport._client._protocol_version = 1
1377
1379
 
1378
1380
        # We want to make sure the client is used when the first remote
1379
1381
        # method is called.  No data should have been sent, or read.
1380
1382
        self.assertEqual(0, input.tell())
1381
1383
        self.assertEqual('', output.getvalue())
1382
1384
 
1383
 
        # Explicitly probe for the server version now, so that it doesn't
1384
 
        # happen implicitly when we call our first remote method.
1385
 
        client_medium.protocol_version()
1386
 
        output.seek(0)
1387
 
        output.truncate()
1388
 
 
1389
1385
        # Now call a method that should result in one request: as the
1390
1386
        # transport makes its own protocol instances, we check on the wire.
1391
1387
        # XXX: TODO: give the transport a protocol factory, which can make
1392
1388
        # an instrumented protocol for us.
1393
1389
        self.assertEqual('bar', transport.get_bytes('foo'))
1394
1390
        # only the needed data should have been sent/received.
1395
 
        self.assertEqual(5 + 13, input.tell())
 
1391
        self.assertEqual(13, input.tell())
1396
1392
        self.assertEqual('get\x01/foo\n', output.getvalue())
1397
1393
 
1398
1394
    def test__translate_error_readonly(self):
1430
1426
        """
1431
1427
        # This is very similar to
1432
1428
        # bzrlib.smart.client._SmartClient._build_client_protocol
 
1429
        # XXX: make this use _SmartClient!
1433
1430
        if input_bytes is None:
1434
1431
            input = StringIO()
1435
1432
        else:
1445
1442
            assert self.response_decoder is not None
1446
1443
            requester = self.request_encoder(request)
1447
1444
            response_handler = message.ConventionalResponseHandler()
1448
 
            response_protocol = self.response_decoder(response_handler)
 
1445
            response_protocol = self.response_decoder(
 
1446
                response_handler, expect_version_marker=True)
1449
1447
            response_handler.setProtoAndMediumRequest(
1450
1448
                response_protocol, request)
1451
1449
            return requester, response_handler, output
2431
2429
        correct bytes for that invocation.
2432
2430
        """
2433
2431
        requester, output = self.make_client_encoder_and_output()
2434
 
        requester.call('one arg', headers={'header name': 'header value'})
 
2432
        requester.set_headers({'header name': 'header value'})
 
2433
        requester.call('one arg')
2435
2434
        self.assertEquals(
2436
2435
            'bzr message 3 (bzr 1.3)\n' # protocol version
2437
2436
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
2439
2438
            'e', # end
2440
2439
            output.getvalue())
2441
2440
 
2442
 
    def test_call_default_headers(self):
2443
 
        """ProtocolThreeRequester.call by default sends a 'Software
2444
 
        version' header.
2445
 
        """
2446
 
        requester, output = self.make_client_encoder_and_output()
2447
 
        requester.call('foo')
2448
 
        # XXX: using assertContainsRe is a pretty poor way to assert this.
2449
 
        self.assertContainsRe(output.getvalue(), 'Software version')
2450
 
        
2451
2441
    def test_call_with_body_bytes_smoke_test(self):
2452
2442
        """A smoke test for ProtocolThreeRequester.call_with_body_bytes.
2453
2443
 
2455
2445
        call_with_body_bytes emits the correct bytes for that invocation.
2456
2446
        """
2457
2447
        requester, output = self.make_client_encoder_and_output()
2458
 
        requester.call_with_body_bytes(
2459
 
            ('one arg',), 'body bytes',
2460
 
            headers={'header name': 'header value'})
 
2448
        requester.set_headers({'header name': 'header value'})
 
2449
        requester.call_with_body_bytes(('one arg',), 'body bytes')
2461
2450
        self.assertEquals(
2462
2451
            'bzr message 3 (bzr 1.3)\n' # protocol version
2463
2452
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
2527
2516
        self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
2528
2517
 
2529
2518
 
 
2519
class MockMediumProtocolThree(object):
 
2520
 
 
2521
    def __init__(self):
 
2522
        self._history = []
 
2523
        self.base = 'dummy base'
 
2524
        
 
2525
    def get_request(self):
 
2526
        return MockMediumRequestThree(self)
 
2527
 
 
2528
 
 
2529
class MockMediumRequestThree(object):
 
2530
 
 
2531
    def __init__(self, mock_medium):
 
2532
        self._medium = mock_medium
 
2533
        self._history = mock_medium._history
 
2534
        self._bytes = ''
 
2535
 
 
2536
    def accept_bytes(self, bytes):
 
2537
        self._bytes += bytes
 
2538
 
 
2539
    def finished_writing(self):
 
2540
        self._history.append(('request', 'finished_writing', self._bytes))
 
2541
 
 
2542
    def finished_reading(self):
 
2543
        self._history.append(('request', 'finished_reading'))
 
2544
 
 
2545
    def read_bytes(self, size):
 
2546
        self._history.append(('request', 'read_bytes'))
 
2547
        return (protocol.MESSAGE_VERSION_THREE +
 
2548
                '\0\0\0\x02des\0\0\0\x13l14:response valueee')
 
2549
 
 
2550
 
 
2551
class MockMediumProtocolTwo(object):
 
2552
 
 
2553
    def __init__(self):
 
2554
        self._history = []
 
2555
        self.base = 'dummy base'
 
2556
        self._request = MockMediumRequestTwo(self)
 
2557
        
 
2558
    def get_request(self):
 
2559
        return self._request
 
2560
 
 
2561
    def disconnect(self):
 
2562
        self._history.append(('medium', 'disconnect'))
 
2563
        self._request._read_bytes = ''
 
2564
        self._request._response = 'bzr response 2\nsuccess\nresponse value\n'
 
2565
 
 
2566
 
 
2567
class MockMediumRequestTwo(object):
 
2568
 
 
2569
    def __init__(self, mock_medium):
 
2570
        self._medium = mock_medium
 
2571
        self._history = mock_medium._history
 
2572
        self._written_bytes = ''
 
2573
        self._read_bytes = ''
 
2574
        self._response = 'bzr response 2\nfailed\n\n'
 
2575
 
 
2576
    def accept_bytes(self, bytes):
 
2577
        self._written_bytes += bytes
 
2578
 
 
2579
    def finished_writing(self):
 
2580
        self._history.append(
 
2581
            ('request', 'finished_writing', self._written_bytes))
 
2582
        self._written_bytes = ''
 
2583
 
 
2584
    def finished_reading(self):
 
2585
        self._history.append(('request', 'finished_reading', self._read_bytes))
 
2586
        self._read_bytes = ''
 
2587
 
 
2588
    def read_bytes(self, size):
 
2589
        resp = self._response
 
2590
        bytes, resp = resp[:size], resp[size:]
 
2591
        self._response = resp
 
2592
        self._read_bytes += bytes
 
2593
        return bytes
 
2594
 
 
2595
    def read_line(self):
 
2596
        resp = self._response
 
2597
        try:
 
2598
            line, resp = resp.split('\n', 1)
 
2599
            line += '\n'
 
2600
        except ValueError:
 
2601
            line, resp = resp, ''
 
2602
        self._response = resp
 
2603
        self._read_bytes += line
 
2604
        return line
 
2605
 
 
2606
 
 
2607
class Test_SmartClientVersionDetection(tests.TestCase):
 
2608
 
 
2609
    def test_version_three_server(self):
 
2610
        medium = MockMediumProtocolThree()
 
2611
        smart_client = client._SmartClient(medium, 'base', headers={})
 
2612
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
 
2613
        self.assertEqual(('response value',), result)
 
2614
        self.assertEqual(
 
2615
            [('request', 'finished_writing', 'bzr message 3 (bzr 1.3)\n\x00\x00\x00\x02des\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee'),
 
2616
             ('request', 'read_bytes'),
 
2617
             ('request', 'finished_reading'),],
 
2618
            medium._history)
 
2619
        # After the first successful call, we know the version
 
2620
        self.assertEqual(3, smart_client._protocol_version)
 
2621
 
 
2622
    def test_version_two_server(self):
 
2623
        medium = MockMediumProtocolTwo()
 
2624
        smart_client = client._SmartClient(medium, 'base', headers={})
 
2625
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
 
2626
        self.assertEqual(('response value',), result)
 
2627
        self.assertEqual(
 
2628
            [('request', 'finished_writing',
 
2629
              'bzr message 3 (bzr 1.3)\n\x00\x00\x00\x02de' +
 
2630
              's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee'),
 
2631
             ('medium', 'disconnect'),
 
2632
             ('request', 'finished_writing',
 
2633
              'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n'),
 
2634
             ('request', 'finished_reading',
 
2635
              'bzr response 2\nsuccess\nresponse value\n'),
 
2636
             ],
 
2637
            medium._history)
 
2638
        # After the first successful call, we know the version
 
2639
        self.assertEqual(2, smart_client._protocol_version)
 
2640
 
 
2641
 
 
2642
class Test_SmartClient(tests.TestCase):
 
2643
 
 
2644
    def test_call_default_headers(self):
 
2645
        """ProtocolThreeRequester.call by default sends a 'Software
 
2646
        version' header.
 
2647
        """
 
2648
        smart_client = client._SmartClient(medium, 'base')
 
2649
        self.assertTrue('Software version' in smart_client._headers)
 
2650
        # XXX: need a test that smart_client._headers is passed to the request
 
2651
        # encoder.
 
2652
 
 
2653
 
2530
2654
class LengthPrefixedBodyDecoder(tests.TestCase):
2531
2655
 
2532
2656
    # XXX: TODO: make accept_reading_trailer invoke translate_response or