From 799481ea22c95e714f511a17dfe0370cd56e7f49 Mon Sep 17 00:00:00 2001 From: Bill Prin Date: Tue, 26 Apr 2016 16:46:50 -0700 Subject: [PATCH] Add Async Sample Code --- appengine/urlfetch/async/app.yaml | 7 +++ appengine/urlfetch/async/rpc.py | 81 ++++++++++++++++++++++++++++ appengine/urlfetch/async/rpc_test.py | 50 +++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 appengine/urlfetch/async/app.yaml create mode 100644 appengine/urlfetch/async/rpc.py create mode 100644 appengine/urlfetch/async/rpc_test.py diff --git a/appengine/urlfetch/async/app.yaml b/appengine/urlfetch/async/app.yaml new file mode 100644 index 00000000000..e93e25d8389 --- /dev/null +++ b/appengine/urlfetch/async/app.yaml @@ -0,0 +1,7 @@ +runtime: python27 +api_version: 1 +threadsafe: yes + +handlers: +- url: .* + script: rpc.app diff --git a/appengine/urlfetch/async/rpc.py b/appengine/urlfetch/async/rpc.py new file mode 100644 index 00000000000..79bd7c5398e --- /dev/null +++ b/appengine/urlfetch/async/rpc.py @@ -0,0 +1,81 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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 functools +import logging + +# [START urlfetch-import] +from google.appengine.api import urlfetch +# [END urlfetch-import] +import webapp2 + + +class UrlFetchRpcHandler(webapp2.RequestHandler): + """ Demonstrates an asynchronous HTTP query using urlfetch""" + + def get(self): + # [START urlfetch-rpc] + rpc = urlfetch.create_rpc() + urlfetch.make_fetch_call(rpc, "http://www.google.com/") + + # ... do other things ... + try: + result = rpc.get_result() + if result.status_code == 200: + text = result.content + self.response.write(text) + else: + self.response.status_code = result.status_code + logging.error("Error making RPC request") + except urlfetch.DownloadError: + logging.error("Error fetching URL0") + # [END urlfetch-rpc] + + +class UrlFetchRpcCallbackHandler(webapp2.RequestHandler): + """ Demonstrates an asynchronous HTTP query with a callback using + urlfetch""" + + def get(self): + # [START urlfetch-rpc-callback] + def handle_result(rpc): + result = rpc.get_result() + self.response.write(result.content) + logging.info("Handling RPC in callback: result {}".format(result)) + + urls = ['http://www.google.com', + 'http://www.github.com', + 'http://www.travis-ci.org'] + rpcs = [] + for url in urls: + rpc = urlfetch.create_rpc() + rpc.callback = functools.partial(handle_result, rpc) + urlfetch.make_fetch_call(rpc, url) + rpcs.append(rpc) + + # ... do other things ... + + # Finish all RPCs, and let callbacks process the results. + + for rpc in rpcs: + rpc.wait() + + logging.info("Done waiting for RPCs") + # [END urlfetch-rpc-callback] + + +app = webapp2.WSGIApplication([ + ('/', UrlFetchRpcHandler), + ('/callback', UrlFetchRpcCallbackHandler), +], debug=True) diff --git a/appengine/urlfetch/async/rpc_test.py b/appengine/urlfetch/async/rpc_test.py new file mode 100644 index 00000000000..b97ff98c86d --- /dev/null +++ b/appengine/urlfetch/async/rpc_test.py @@ -0,0 +1,50 @@ +# Copyright 2016 Google Inc. All rights reserved. +# +# 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 mock +import pytest +import rpc +import webtest + + +@pytest.fixture +def app(): + return webtest.TestApp(rpc.app) + + +@mock.patch("rpc.urlfetch") +def test_url_fetch(urlfetch_mock, app): + get_result_mock = mock.Mock( + return_value=mock.Mock(status_code=200, + content="I'm Feeling Lucky")) + urlfetch_mock.create_rpc = mock.Mock( + return_value=mock.Mock(get_result=get_result_mock)) + response = app.get('/') + assert response.status_int == 200 + assert "I'm Feeling Lucky" in response.body + + +@mock.patch("rpc.urlfetch") +def test_url_post(urlfetch_mock, app): + get_result_mock = mock.Mock( + return_value=mock.Mock(status_code=200, + content="I'm Feeling Lucky")) + urlfetch_mock.create_rpc = mock.Mock( + return_value=mock.Mock(get_result=get_result_mock)) + + rpc_mock = mock.Mock() + urlfetch_mock.create_rpc.return_value = rpc_mock + + app.get('/callback') + rpc_mock.wait.assert_called_with()