Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Unified Diff: third_party/gsutil/third_party/protorpc/protorpc/webapp_test_util.py

Issue 1377933002: [catapult] - Copy Telemetry's gsutilz over to third_party. (Closed) Base URL: https://github.com/catapult-project/catapult.git@master
Patch Set: Rename to gsutil. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/gsutil/third_party/protorpc/protorpc/webapp_test_util.py
diff --git a/third_party/gsutil/third_party/protorpc/protorpc/webapp_test_util.py b/third_party/gsutil/third_party/protorpc/protorpc/webapp_test_util.py
new file mode 100755
index 0000000000000000000000000000000000000000..2431855e5e54565685364a0294d71a4ab11948f4
--- /dev/null
+++ b/third_party/gsutil/third_party/protorpc/protorpc/webapp_test_util.py
@@ -0,0 +1,398 @@
+#!/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.
+#
+
+"""Testing utilities for the webapp libraries.
+
+ GetDefaultEnvironment: Method for easily setting up CGI environment.
+ RequestHandlerTestBase: Base class for setting up handler tests.
+"""
+
+__author__ = 'rafek@google.com (Rafe Kaplan)'
+
+import cStringIO
+import threading
+import urllib2
+from wsgiref import simple_server
+from wsgiref import validate
+
+from . import protojson
+from . import remote
+from . import test_util
+from . import transport
+from .webapp import service_handlers
+from .webapp.google_imports import webapp
+
+
+class TestService(remote.Service):
+ """Service used to do end to end tests with."""
+
+ @remote.method(test_util.OptionalMessage,
+ test_util.OptionalMessage)
+ def optional_message(self, request):
+ if request.string_value:
+ request.string_value = '+%s' % request.string_value
+ return request
+
+
+def GetDefaultEnvironment():
+ """Function for creating a default CGI environment."""
+ return {
+ 'LC_NUMERIC': 'C',
+ 'wsgi.multiprocess': True,
+ 'SERVER_PROTOCOL': 'HTTP/1.0',
+ 'SERVER_SOFTWARE': 'Dev AppServer 0.1',
+ 'SCRIPT_NAME': '',
+ 'LOGNAME': 'nickjohnson',
+ 'USER': 'nickjohnson',
+ 'QUERY_STRING': 'foo=bar&foo=baz&foo2=123',
+ 'PATH': '/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11',
+ 'LANG': 'en_US',
+ 'LANGUAGE': 'en',
+ 'REMOTE_ADDR': '127.0.0.1',
+ 'LC_MONETARY': 'C',
+ 'CONTENT_TYPE': 'application/x-www-form-urlencoded',
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'HOME': '/home/mruser',
+ 'USERNAME': 'mruser',
+ 'CONTENT_LENGTH': '',
+ 'USER_IS_ADMIN': '1',
+ 'PYTHONPATH': '/tmp/setup',
+ 'LC_TIME': 'C',
+ 'HTTP_USER_AGENT': 'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; '
+ 'rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6',
+ 'wsgi.multithread': False,
+ 'wsgi.version': (1, 0),
+ 'USER_EMAIL': 'test@example.com',
+ 'USER_EMAIL': '112',
+ 'wsgi.input': cStringIO.StringIO(),
+ 'PATH_TRANSLATED': '/tmp/request.py',
+ 'SERVER_NAME': 'localhost',
+ 'GATEWAY_INTERFACE': 'CGI/1.1',
+ 'wsgi.run_once': True,
+ 'LC_COLLATE': 'C',
+ 'HOSTNAME': 'myhost',
+ 'wsgi.errors': cStringIO.StringIO(),
+ 'PWD': '/tmp',
+ 'REQUEST_METHOD': 'GET',
+ 'MAIL': '/dev/null',
+ 'MAILCHECK': '0',
+ 'USER_NICKNAME': 'test',
+ 'HTTP_COOKIE': 'dev_appserver_login="test:test@example.com:True"',
+ 'PATH_INFO': '/tmp/myhandler'
+ }
+
+
+class RequestHandlerTestBase(test_util.TestCase):
+ """Base class for writing RequestHandler tests.
+
+ To test a specific request handler override CreateRequestHandler.
+ To change the environment for that handler override GetEnvironment.
+ """
+
+ def setUp(self):
+ """Set up test for request handler."""
+ self.ResetHandler()
+
+ def GetEnvironment(self):
+ """Get environment.
+
+ Override for more specific configurations.
+
+ Returns:
+ dict of CGI environment.
+ """
+ return GetDefaultEnvironment()
+
+ def CreateRequestHandler(self):
+ """Create RequestHandler instances.
+
+ Override to create more specific kinds of RequestHandler instances.
+
+ Returns:
+ RequestHandler instance used in test.
+ """
+ return webapp.RequestHandler()
+
+ def CheckResponse(self,
+ expected_status,
+ expected_headers,
+ expected_content):
+ """Check that the web response is as expected.
+
+ Args:
+ expected_status: Expected status message.
+ expected_headers: Dictionary of expected headers. Will ignore unexpected
+ headers and only check the value of those expected.
+ expected_content: Expected body.
+ """
+ def check_content(content):
+ self.assertEquals(expected_content, content)
+
+ def start_response(status, headers):
+ self.assertEquals(expected_status, status)
+
+ found_keys = set()
+ for name, value in headers:
+ name = name.lower()
+ try:
+ expected_value = expected_headers[name]
+ except KeyError:
+ pass
+ else:
+ found_keys.add(name)
+ self.assertEquals(expected_value, value)
+
+ missing_headers = set(expected_headers.keys()) - found_keys
+ if missing_headers:
+ self.fail('Expected keys %r not found' % (list(missing_headers),))
+
+ return check_content
+
+ self.handler.response.wsgi_write(start_response)
+
+ def ResetHandler(self, change_environ=None):
+ """Reset this tests environment with environment changes.
+
+ Resets the entire test with a new handler which includes some changes to
+ the default request environment.
+
+ Args:
+ change_environ: Dictionary of values that are added to default
+ environment.
+ """
+ environment = self.GetEnvironment()
+ environment.update(change_environ or {})
+
+ self.request = webapp.Request(environment)
+ self.response = webapp.Response()
+ self.handler = self.CreateRequestHandler()
+ self.handler.initialize(self.request, self.response)
+
+
+class SyncedWSGIServer(simple_server.WSGIServer):
+ pass
+
+
+class ServerThread(threading.Thread):
+ """Thread responsible for managing wsgi server.
+
+ This server does not just attach to the socket and listen for requests. This
+ is because the server classes in Python 2.5 or less have no way to shut them
+ down. Instead, the thread must be notified of how many requests it will
+ receive so that it listens for each one individually. Tests should tell how
+ many requests to listen for using the handle_request method.
+ """
+
+ def __init__(self, server, *args, **kwargs):
+ """Constructor.
+
+ Args:
+ server: The WSGI server that is served by this thread.
+ As per threading.Thread base class.
+
+ State:
+ __serving: Server is still expected to be serving. When False server
+ knows to shut itself down.
+ """
+ self.server = server
+ # This timeout is for the socket when a connection is made.
+ self.server.socket.settimeout(None)
+ # This timeout is for when waiting for a connection. The allows
+ # server.handle_request() to listen for a short time, then timeout,
+ # allowing the server to check for shutdown.
+ self.server.timeout = 0.05
+ self.__serving = True
+
+ super(ServerThread, self).__init__(*args, **kwargs)
+
+ def shutdown(self):
+ """Notify server that it must shutdown gracefully."""
+ self.__serving = False
+
+ def run(self):
+ """Handle incoming requests until shutdown."""
+ while self.__serving:
+ self.server.handle_request()
+
+ self.server = None
+
+
+class TestService(remote.Service):
+ """Service used to do end to end tests with."""
+
+ def __init__(self, message='uninitialized'):
+ self.__message = message
+
+ @remote.method(test_util.OptionalMessage, test_util.OptionalMessage)
+ def optional_message(self, request):
+ if request.string_value:
+ request.string_value = '+%s' % request.string_value
+ return request
+
+ @remote.method(response_type=test_util.OptionalMessage)
+ def init_parameter(self, request):
+ return test_util.OptionalMessage(string_value=self.__message)
+
+ @remote.method(test_util.NestedMessage, test_util.NestedMessage)
+ def nested_message(self, request):
+ request.string_value = '+%s' % request.string_value
+ return request
+
+ @remote.method()
+ def raise_application_error(self, request):
+ raise remote.ApplicationError('This is an application error', 'ERROR_NAME')
+
+ @remote.method()
+ def raise_unexpected_error(self, request):
+ raise TypeError('Unexpected error')
+
+ @remote.method()
+ def raise_rpc_error(self, request):
+ raise remote.NetworkError('Uncaught network error')
+
+ @remote.method(response_type=test_util.NestedMessage)
+ def return_bad_message(self, request):
+ return test_util.NestedMessage()
+
+
+class AlternateService(remote.Service):
+ """Service used to requesting non-existant methods."""
+
+ @remote.method()
+ def does_not_exist(self, request):
+ raise NotImplementedError('Not implemented')
+
+
+class WebServerTestBase(test_util.TestCase):
+
+ SERVICE_PATH = '/my/service'
+
+ def setUp(self):
+ self.server = None
+ self.schema = 'http'
+ self.ResetServer()
+
+ self.bad_path_connection = self.CreateTransport(self.service_url + '_x')
+ self.bad_path_stub = TestService.Stub(self.bad_path_connection)
+ super(WebServerTestBase, self).setUp()
+
+ def tearDown(self):
+ self.server.shutdown()
+ super(WebServerTestBase, self).tearDown()
+
+ def ResetServer(self, application=None):
+ """Reset web server.
+
+ Shuts down existing server if necessary and starts a new one.
+
+ Args:
+ application: Optional WSGI function. If none provided will use
+ tests CreateWsgiApplication method.
+ """
+ if self.server:
+ self.server.shutdown()
+
+ self.port = test_util.pick_unused_port()
+ self.server, self.application = self.StartWebServer(self.port, application)
+
+ self.connection = self.CreateTransport(self.service_url)
+
+ def CreateTransport(self, service_url, protocol=protojson):
+ """Create a new transportation object."""
+ return transport.HttpTransport(service_url, protocol=protocol)
+
+ def StartWebServer(self, port, application=None):
+ """Start web server.
+
+ Args:
+ port: Port to start application on.
+ application: Optional WSGI function. If none provided will use
+ tests CreateWsgiApplication method.
+
+ Returns:
+ A tuple (server, application):
+ server: An instance of ServerThread.
+ application: Application that web server responds with.
+ """
+ if not application:
+ application = self.CreateWsgiApplication()
+ validated_application = validate.validator(application)
+ server = simple_server.make_server('localhost', port, validated_application)
+ server = ServerThread(server)
+ server.start()
+ return server, application
+
+ def make_service_url(self, path):
+ """Make service URL using current schema and port."""
+ return '%s://localhost:%d%s' % (self.schema, self.port, path)
+
+ @property
+ def service_url(self):
+ return self.make_service_url(self.SERVICE_PATH)
+
+
+class EndToEndTestBase(WebServerTestBase):
+
+ # Sub-classes may override to create alternate configurations.
+ DEFAULT_MAPPING = service_handlers.service_mapping(
+ [('/my/service', TestService),
+ ('/my/other_service', TestService.new_factory('initialized')),
+ ])
+
+ def setUp(self):
+ super(EndToEndTestBase, self).setUp()
+
+ self.stub = TestService.Stub(self.connection)
+
+ self.other_connection = self.CreateTransport(self.other_service_url)
+ self.other_stub = TestService.Stub(self.other_connection)
+
+ self.mismatched_stub = AlternateService.Stub(self.connection)
+
+ @property
+ def other_service_url(self):
+ return 'http://localhost:%d/my/other_service' % self.port
+
+ def CreateWsgiApplication(self):
+ """Create WSGI application used on the server side for testing."""
+ return webapp.WSGIApplication(self.DEFAULT_MAPPING, True)
+
+ def DoRawRequest(self,
+ method,
+ content='',
+ content_type='application/json',
+ headers=None):
+ headers = headers or {}
+ headers.update({'content-length': len(content or ''),
+ 'content-type': content_type,
+ })
+ request = urllib2.Request('%s.%s' % (self.service_url, method),
+ content,
+ headers)
+ return urllib2.urlopen(request)
+
+ def RawRequestError(self,
+ method,
+ content=None,
+ content_type='application/json',
+ headers=None):
+ try:
+ self.DoRawRequest(method, content, content_type, headers)
+ self.fail('Expected HTTP error')
+ except urllib2.HTTPError as err:
+ return err.code, err.read(), err.headers

Powered by Google App Engine
This is Rietveld 408576698