| Index: third_party/gsutil/third_party/protorpc/protorpc/transport_test.py
|
| diff --git a/third_party/gsutil/third_party/protorpc/protorpc/transport_test.py b/third_party/gsutil/third_party/protorpc/protorpc/transport_test.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..8fa39c3d464c5f6700bfc79285955ddee77d7492
|
| --- /dev/null
|
| +++ b/third_party/gsutil/third_party/protorpc/protorpc/transport_test.py
|
| @@ -0,0 +1,493 @@
|
| +#!/usr/bin/env python
|
| +#
|
| +# Copyright 2010 Google Inc.
|
| +#
|
| +# Licensed under the Apache License, Version 2.0 (the "License");
|
| +# you may not use this file except in compliance with the License.
|
| +# You may obtain a copy of the License at
|
| +#
|
| +# http://www.apache.org/licenses/LICENSE-2.0
|
| +#
|
| +# Unless required by applicable law or agreed to in writing, software
|
| +# distributed under the License is distributed on an "AS IS" BASIS,
|
| +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +# See the License for the specific language governing permissions and
|
| +# limitations under the License.
|
| +#
|
| +
|
| +import errno
|
| +import six.moves.http_client
|
| +import os
|
| +import socket
|
| +import unittest
|
| +
|
| +from protorpc import messages
|
| +from protorpc import protobuf
|
| +from protorpc import protojson
|
| +from protorpc import remote
|
| +from protorpc import test_util
|
| +from protorpc import transport
|
| +from protorpc import webapp_test_util
|
| +from protorpc.wsgi import util as wsgi_util
|
| +
|
| +import mox
|
| +
|
| +package = 'transport_test'
|
| +
|
| +
|
| +class ModuleInterfaceTest(test_util.ModuleInterfaceTest,
|
| + test_util.TestCase):
|
| +
|
| + MODULE = transport
|
| +
|
| +
|
| +class Message(messages.Message):
|
| +
|
| + value = messages.StringField(1)
|
| +
|
| +
|
| +class Service(remote.Service):
|
| +
|
| + @remote.method(Message, Message)
|
| + def method(self, request):
|
| + pass
|
| +
|
| +
|
| +# Remove when RPC is no longer subclasses.
|
| +class TestRpc(transport.Rpc):
|
| +
|
| + waited = False
|
| +
|
| + def _wait_impl(self):
|
| + self.waited = True
|
| +
|
| +
|
| +class RpcTest(test_util.TestCase):
|
| +
|
| + def setUp(self):
|
| + self.request = Message(value=u'request')
|
| + self.response = Message(value=u'response')
|
| + self.status = remote.RpcStatus(state=remote.RpcState.APPLICATION_ERROR,
|
| + error_message='an error',
|
| + error_name='blam')
|
| +
|
| + self.rpc = TestRpc(self.request)
|
| +
|
| + def testConstructor(self):
|
| + self.assertEquals(self.request, self.rpc.request)
|
| + self.assertEquals(remote.RpcState.RUNNING, self.rpc.state)
|
| + self.assertEquals(None, self.rpc.error_message)
|
| + self.assertEquals(None, self.rpc.error_name)
|
| +
|
| + def response(self):
|
| + self.assertFalse(self.rpc.waited)
|
| + self.assertEquals(None, self.rpc.response)
|
| + self.assertTrue(self.rpc.waited)
|
| +
|
| + def testSetResponse(self):
|
| + self.rpc.set_response(self.response)
|
| +
|
| + self.assertEquals(self.request, self.rpc.request)
|
| + self.assertEquals(remote.RpcState.OK, self.rpc.state)
|
| + self.assertEquals(self.response, self.rpc.response)
|
| + self.assertEquals(None, self.rpc.error_message)
|
| + self.assertEquals(None, self.rpc.error_name)
|
| +
|
| + def testSetResponseAlreadySet(self):
|
| + self.rpc.set_response(self.response)
|
| +
|
| + self.assertRaisesWithRegexpMatch(
|
| + transport.RpcStateError,
|
| + 'RPC must be in RUNNING state to change to OK',
|
| + self.rpc.set_response,
|
| + self.response)
|
| +
|
| + def testSetResponseAlreadyError(self):
|
| + self.rpc.set_status(self.status)
|
| +
|
| + self.assertRaisesWithRegexpMatch(
|
| + transport.RpcStateError,
|
| + 'RPC must be in RUNNING state to change to OK',
|
| + self.rpc.set_response,
|
| + self.response)
|
| +
|
| + def testSetStatus(self):
|
| + self.rpc.set_status(self.status)
|
| +
|
| + self.assertEquals(self.request, self.rpc.request)
|
| + self.assertEquals(remote.RpcState.APPLICATION_ERROR, self.rpc.state)
|
| + self.assertEquals('an error', self.rpc.error_message)
|
| + self.assertEquals('blam', self.rpc.error_name)
|
| + self.assertRaisesWithRegexpMatch(remote.ApplicationError,
|
| + 'an error',
|
| + getattr, self.rpc, 'response')
|
| +
|
| + def testSetStatusAlreadySet(self):
|
| + self.rpc.set_response(self.response)
|
| +
|
| + self.assertRaisesWithRegexpMatch(
|
| + transport.RpcStateError,
|
| + 'RPC must be in RUNNING state to change to OK',
|
| + self.rpc.set_response,
|
| + self.response)
|
| +
|
| + def testSetNonMessage(self):
|
| + self.assertRaisesWithRegexpMatch(
|
| + TypeError,
|
| + 'Expected Message type, received 10',
|
| + self.rpc.set_response,
|
| + 10)
|
| +
|
| + def testSetStatusAlreadyError(self):
|
| + self.rpc.set_status(self.status)
|
| +
|
| + self.assertRaisesWithRegexpMatch(
|
| + transport.RpcStateError,
|
| + 'RPC must be in RUNNING state to change to OK',
|
| + self.rpc.set_response,
|
| + self.response)
|
| +
|
| + def testSetUninitializedStatus(self):
|
| + self.assertRaises(messages.ValidationError,
|
| + self.rpc.set_status,
|
| + remote.RpcStatus())
|
| +
|
| +
|
| +class TransportTest(test_util.TestCase):
|
| +
|
| + def setUp(self):
|
| + remote.Protocols.set_default(remote.Protocols.new_default())
|
| +
|
| + def do_test(self, protocol, trans):
|
| + request = Message()
|
| + request.value = u'request'
|
| +
|
| + response = Message()
|
| + response.value = u'response'
|
| +
|
| + encoded_request = protocol.encode_message(request)
|
| + encoded_response = protocol.encode_message(response)
|
| +
|
| + self.assertEquals(protocol, trans.protocol)
|
| +
|
| + received_rpc = [None]
|
| + def transport_rpc(remote, rpc_request):
|
| + self.assertEquals(remote, Service.method.remote)
|
| + self.assertEquals(request, rpc_request)
|
| + rpc = TestRpc(request)
|
| + rpc.set_response(response)
|
| + return rpc
|
| + trans._start_rpc = transport_rpc
|
| +
|
| + rpc = trans.send_rpc(Service.method.remote, request)
|
| + self.assertEquals(response, rpc.response)
|
| +
|
| + def testDefaultProtocol(self):
|
| + trans = transport.Transport()
|
| + self.do_test(protobuf, trans)
|
| + self.assertEquals(protobuf, trans.protocol_config.protocol)
|
| + self.assertEquals('default', trans.protocol_config.name)
|
| +
|
| + def testAlternateProtocol(self):
|
| + trans = transport.Transport(protocol=protojson)
|
| + self.do_test(protojson, trans)
|
| + self.assertEquals(protojson, trans.protocol_config.protocol)
|
| + self.assertEquals('default', trans.protocol_config.name)
|
| +
|
| + def testProtocolConfig(self):
|
| + protocol_config = remote.ProtocolConfig(
|
| + protojson, 'protoconfig', 'image/png')
|
| + trans = transport.Transport(protocol=protocol_config)
|
| + self.do_test(protojson, trans)
|
| + self.assertTrue(trans.protocol_config is protocol_config)
|
| +
|
| + def testProtocolByName(self):
|
| + remote.Protocols.get_default().add_protocol(
|
| + protojson, 'png', 'image/png', ())
|
| + trans = transport.Transport(protocol='png')
|
| + self.do_test(protojson, trans)
|
| +
|
| +
|
| +@remote.method(Message, Message)
|
| +def my_method(self, request):
|
| + self.fail('self.my_method should not be directly invoked.')
|
| +
|
| +
|
| +class FakeConnectionClass(object):
|
| +
|
| + def __init__(self, mox):
|
| + self.request = mox.CreateMockAnything()
|
| + self.response = mox.CreateMockAnything()
|
| +
|
| +
|
| +class HttpTransportTest(webapp_test_util.WebServerTestBase):
|
| +
|
| + def setUp(self):
|
| + # Do not need much parent construction functionality.
|
| +
|
| + self.schema = 'http'
|
| + self.server = None
|
| +
|
| + self.request = Message(value=u'The request value')
|
| + self.encoded_request = protojson.encode_message(self.request)
|
| +
|
| + self.response = Message(value=u'The response value')
|
| + self.encoded_response = protojson.encode_message(self.response)
|
| +
|
| + def testCallSucceeds(self):
|
| + self.ResetServer(wsgi_util.static_page(self.encoded_response,
|
| + content_type='application/json'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + self.assertEquals(self.response, rpc.response)
|
| +
|
| + def testHttps(self):
|
| + self.schema = 'https'
|
| + self.ResetServer(wsgi_util.static_page(self.encoded_response,
|
| + content_type='application/json'))
|
| +
|
| + # Create a fake https connection function that really just calls http.
|
| + self.used_https = False
|
| + def https_connection(*args, **kwargs):
|
| + self.used_https = True
|
| + return six.moves.http_client.HTTPConnection(*args, **kwargs)
|
| +
|
| + original_https_connection = six.moves.http_client.HTTPSConnection
|
| + six.moves.http_client.HTTPSConnection = https_connection
|
| + try:
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + finally:
|
| + six.moves.http_client.HTTPSConnection = original_https_connection
|
| + self.assertEquals(self.response, rpc.response)
|
| + self.assertTrue(self.used_https)
|
| +
|
| + def testHttpSocketError(self):
|
| + self.ResetServer(wsgi_util.static_page(self.encoded_response,
|
| + content_type='application/json'))
|
| +
|
| + bad_transport = transport.HttpTransport('http://localhost:-1/blar')
|
| + try:
|
| + bad_transport.send_rpc(my_method.remote, self.request)
|
| + except remote.NetworkError as err:
|
| + self.assertTrue(str(err).startswith('Socket error: error ('))
|
| + self.assertEquals(errno.ECONNREFUSED, err.cause.errno)
|
| + else:
|
| + self.fail('Expected error')
|
| +
|
| + def testHttpRequestError(self):
|
| + self.ResetServer(wsgi_util.static_page(self.encoded_response,
|
| + content_type='application/json'))
|
| +
|
| + def request_error(*args, **kwargs):
|
| + raise TypeError('Generic Error')
|
| + original_request = six.moves.http_client.HTTPConnection.request
|
| + six.moves.http_client.HTTPConnection.request = request_error
|
| + try:
|
| + try:
|
| + self.connection.send_rpc(my_method.remote, self.request)
|
| + except remote.NetworkError as err:
|
| + self.assertEquals('Error communicating with HTTP server', str(err))
|
| + self.assertEquals(TypeError, type(err.cause))
|
| + self.assertEquals('Generic Error', str(err.cause))
|
| + else:
|
| + self.fail('Expected error')
|
| + finally:
|
| + six.moves.http_client.HTTPConnection.request = original_request
|
| +
|
| + def testHandleGenericServiceError(self):
|
| + self.ResetServer(wsgi_util.error(six.moves.http_client.INTERNAL_SERVER_ERROR,
|
| + 'arbitrary error',
|
| + content_type='text/plain'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + try:
|
| + rpc.response
|
| + except remote.ServerError as err:
|
| + self.assertEquals('HTTP Error 500: arbitrary error', str(err).strip())
|
| + else:
|
| + self.fail('Expected ServerError')
|
| +
|
| + def testHandleGenericServiceErrorNoMessage(self):
|
| + self.ResetServer(wsgi_util.error(six.moves.http_client.NOT_IMPLEMENTED,
|
| + ' ',
|
| + content_type='text/plain'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + try:
|
| + rpc.response
|
| + except remote.ServerError as err:
|
| + self.assertEquals('HTTP Error 501: Not Implemented', str(err).strip())
|
| + else:
|
| + self.fail('Expected ServerError')
|
| +
|
| + def testHandleStatusContent(self):
|
| + self.ResetServer(wsgi_util.static_page('{"state": "REQUEST_ERROR",'
|
| + ' "error_message": "a request error"'
|
| + '}',
|
| + status=six.moves.http_client.BAD_REQUEST,
|
| + content_type='application/json'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + try:
|
| + rpc.response
|
| + except remote.RequestError as err:
|
| + self.assertEquals('a request error', str(err))
|
| + else:
|
| + self.fail('Expected RequestError')
|
| +
|
| + def testHandleApplicationError(self):
|
| + self.ResetServer(wsgi_util.static_page('{"state": "APPLICATION_ERROR",'
|
| + ' "error_message": "an app error",'
|
| + ' "error_name": "MY_ERROR_NAME"}',
|
| + status=six.moves.http_client.BAD_REQUEST,
|
| + content_type='application/json'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + try:
|
| + rpc.response
|
| + except remote.ApplicationError as err:
|
| + self.assertEquals('an app error', str(err))
|
| + self.assertEquals('MY_ERROR_NAME', err.error_name)
|
| + else:
|
| + self.fail('Expected RequestError')
|
| +
|
| + def testHandleUnparsableErrorContent(self):
|
| + self.ResetServer(wsgi_util.static_page('oops',
|
| + status=six.moves.http_client.BAD_REQUEST,
|
| + content_type='application/json'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + try:
|
| + rpc.response
|
| + except remote.ServerError as err:
|
| + self.assertEquals('HTTP Error 400: oops', str(err))
|
| + else:
|
| + self.fail('Expected ServerError')
|
| +
|
| + def testHandleEmptyBadRpcStatus(self):
|
| + self.ResetServer(wsgi_util.static_page('{"error_message": "x"}',
|
| + status=six.moves.http_client.BAD_REQUEST,
|
| + content_type='application/json'))
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + try:
|
| + rpc.response
|
| + except remote.ServerError as err:
|
| + self.assertEquals('HTTP Error 400: {"error_message": "x"}', str(err))
|
| + else:
|
| + self.fail('Expected ServerError')
|
| +
|
| + def testUseProtocolConfigContentType(self):
|
| + expected_content_type = 'image/png'
|
| + def expect_content_type(environ, start_response):
|
| + self.assertEquals(expected_content_type, environ['CONTENT_TYPE'])
|
| + app = wsgi_util.static_page('', content_type=environ['CONTENT_TYPE'])
|
| + return app(environ, start_response)
|
| +
|
| + self.ResetServer(expect_content_type)
|
| +
|
| + protocol_config = remote.ProtocolConfig(protojson, 'json', 'image/png')
|
| + self.connection = self.CreateTransport(self.service_url, protocol_config)
|
| +
|
| + rpc = self.connection.send_rpc(my_method.remote, self.request)
|
| + self.assertEquals(Message(), rpc.response)
|
| +
|
| +
|
| +class SimpleRequest(messages.Message):
|
| +
|
| + content = messages.StringField(1)
|
| +
|
| +
|
| +class SimpleResponse(messages.Message):
|
| +
|
| + content = messages.StringField(1)
|
| + factory_value = messages.StringField(2)
|
| + remote_host = messages.StringField(3)
|
| + remote_address = messages.StringField(4)
|
| + server_host = messages.StringField(5)
|
| + server_port = messages.IntegerField(6)
|
| +
|
| +
|
| +class LocalService(remote.Service):
|
| +
|
| + def __init__(self, factory_value='default'):
|
| + self.factory_value = factory_value
|
| +
|
| + @remote.method(SimpleRequest, SimpleResponse)
|
| + def call_method(self, request):
|
| + return SimpleResponse(content=request.content,
|
| + factory_value=self.factory_value,
|
| + remote_host=self.request_state.remote_host,
|
| + remote_address=self.request_state.remote_address,
|
| + server_host=self.request_state.server_host,
|
| + server_port=self.request_state.server_port)
|
| +
|
| + @remote.method()
|
| + def raise_totally_unexpected(self, request):
|
| + raise TypeError('Kablam')
|
| +
|
| + @remote.method()
|
| + def raise_unexpected(self, request):
|
| + raise remote.RequestError('Huh?')
|
| +
|
| + @remote.method()
|
| + def raise_application_error(self, request):
|
| + raise remote.ApplicationError('App error', 10)
|
| +
|
| +
|
| +class LocalTransportTest(test_util.TestCase):
|
| +
|
| + def CreateService(self, factory_value='default'):
|
| + return
|
| +
|
| + def testBasicCallWithClass(self):
|
| + stub = LocalService.Stub(transport.LocalTransport(LocalService))
|
| + response = stub.call_method(content='Hello')
|
| + self.assertEquals(SimpleResponse(content='Hello',
|
| + factory_value='default',
|
| + remote_host=os.uname()[1],
|
| + remote_address='127.0.0.1',
|
| + server_host=os.uname()[1],
|
| + server_port=-1),
|
| + response)
|
| +
|
| + def testBasicCallWithFactory(self):
|
| + stub = LocalService.Stub(
|
| + transport.LocalTransport(LocalService.new_factory('assigned')))
|
| + response = stub.call_method(content='Hello')
|
| + self.assertEquals(SimpleResponse(content='Hello',
|
| + factory_value='assigned',
|
| + remote_host=os.uname()[1],
|
| + remote_address='127.0.0.1',
|
| + server_host=os.uname()[1],
|
| + server_port=-1),
|
| + response)
|
| +
|
| + def testTotallyUnexpectedError(self):
|
| + stub = LocalService.Stub(transport.LocalTransport(LocalService))
|
| + self.assertRaisesWithRegexpMatch(
|
| + remote.ServerError,
|
| + 'Unexpected error TypeError: Kablam',
|
| + stub.raise_totally_unexpected)
|
| +
|
| + def testUnexpectedError(self):
|
| + stub = LocalService.Stub(transport.LocalTransport(LocalService))
|
| + self.assertRaisesWithRegexpMatch(
|
| + remote.ServerError,
|
| + 'Unexpected error RequestError: Huh?',
|
| + stub.raise_unexpected)
|
| +
|
| + def testApplicationError(self):
|
| + stub = LocalService.Stub(transport.LocalTransport(LocalService))
|
| + self.assertRaisesWithRegexpMatch(
|
| + remote.ApplicationError,
|
| + 'App error',
|
| + stub.raise_application_error)
|
| +
|
| +
|
| +def main():
|
| + unittest.main()
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + main()
|
|
|