HTTP routing and implements will be in the same place. This idea was inspired 
from Flask and Bottle of Python and JAX-RS of Java. This modification keeps 
backward compatibility.

Signed-off-by: Satoshi Kobayashi <[email protected]>
---
 ryu/app/wsgi.py                 |   33 ++++++++++++++
 ryu/tests/unit/app/test_wsgi.py |   89 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+), 0 deletions(-)
 create mode 100644 ryu/tests/unit/app/__init__.py
 create mode 100644 ryu/tests/unit/app/test_wsgi.py

diff --git a/ryu/app/wsgi.py b/ryu/app/wsgi.py
index 28bada0..c9a9f96 100644
--- a/ryu/app/wsgi.py
+++ b/ryu/app/wsgi.py
@@ -14,6 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import inspect
+
 from oslo.config import cfg
 import webob.dec
 
@@ -32,6 +34,18 @@ HEX_PATTERN = r'0x[0-9a-z]+'
 DIGIT_PATTERN = r'[1-9][0-9]*'
 
 
+def route(name, path, methods=None, requirements=None):
+    def _route(controller_method):
+        controller_method.routing_info = {
+            'name': name,
+            'path': path,
+            'methods': methods,
+            'requirements': requirements,
+        }
+        return controller_method
+    return _route
+
+
 class ControllerBase(object):
     special_vars = ['action', 'controller']
 
@@ -79,6 +93,25 @@ class WSGIApplication(object):
         controller = match['controller'](req, link, data, **self.config)
         return controller(req)
 
+    def register(self, controller):
+        methods = inspect.getmembers(controller,
+                                     lambda v: inspect.ismethod(v) and
+                                     hasattr(v, 'routing_info'))
+        for method_name, method in methods:
+            routing_info = getattr(method, 'routing_info')
+            name = routing_info['name']
+            path = routing_info['path']
+            conditions = {}
+            if routing_info.get('methods'):
+                conditions['method'] = routing_info['methods']
+            requirements = routing_info.get('requirements') or {}
+            self.mapper.connect(name,
+                                path,
+                                controller=controller,
+                                requirements=requirements,
+                                action=method_name,
+                                conditions=conditions)
+
 
 class WSGIServer(hub.WSGIServer):
     def __init__(self, application, **config):
diff --git a/ryu/tests/unit/app/__init__.py b/ryu/tests/unit/app/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ryu/tests/unit/app/test_wsgi.py b/ryu/tests/unit/app/test_wsgi.py
new file mode 100644
index 0000000..0e5b219
--- /dev/null
+++ b/ryu/tests/unit/app/test_wsgi.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2013 Stratosphere 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.
+
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import unittest
+import logging
+from nose.tools import *
+
+from ryu.app.wsgi import ControllerBase, WSGIApplication, route
+from webob.response import Response
+from ryu.lib import dpid as dpidlib
+
+LOG = logging.getLogger('test_wsgi')
+
+
+class _TestController(ControllerBase):
+
+    @route('test', '/test/{dpid}',
+           methods=['GET'], requirements={'dpid': dpidlib.DPID_PATTERN})
+    def test_get_dpid(self, req, dpid, **_kwargs):
+        return Response(status=200, body=dpid)
+
+    @route('test', '/test')
+    def test_root(self, req, **_kwargs):
+        return Response(status=200, body='root')
+
+
+class Test_wsgi(unittest.TestCase):
+
+    """ Test case for wsgi
+    """
+
+    def setUp(self):
+        self.wsgi_app = WSGIApplication()
+        self.wsgi_app.register(_TestController)
+
+    def tearDown(self):
+        pass
+
+    def test_wsgi_decorator_ok(self):
+        r = self.wsgi_app({'REQUEST_METHOD': 'GET',
+                           'PATH_INFO': '/test/0123456789abcdef'},
+                          lambda s, _: eq_(s, '200 OK'))
+        eq_(r[0], ('0123456789abcdef'))
+
+    def test_wsgi_decorator_ng_path(self):
+        self.wsgi_app({'REQUEST_METHOD': 'GET',
+                       'PATH_INFO': '/'},
+                      lambda s, _: eq_(s, '404 Not Found'))
+
+    def test_wsgi_decorator_ng_method(self):
+        # XXX: If response code is "405 Method Not Allowed", it is better.
+        self.wsgi_app({'REQUEST_METHOD': 'PUT',
+                       'PATH_INFO': '/test/0123456789abcdef'},
+                      lambda s, _: eq_(s, '404 Not Found'))
+
+    def test_wsgi_decorator_ng_requirements(self):
+        # XXX: If response code is "400 Bad Request", it is better.
+        self.wsgi_app({'REQUEST_METHOD': 'GET',
+                       'PATH_INFO': '/test/hogehoge'},
+                      lambda s, _: eq_(s, '404 Not Found'))
+
+    def test_wsgi_decorator_ok_any_method(self):
+        self.wsgi_app({'REQUEST_METHOD': 'GET',
+                       'PATH_INFO': '/test'},
+                      lambda s, _: eq_(s, '200 OK'))
+        self.wsgi_app({'REQUEST_METHOD': 'POST',
+                       'PATH_INFO': '/test'},
+                      lambda s, _: eq_(s, '200 OK'))
+        self.wsgi_app({'REQUEST_METHOD': 'PUT',
+                       'PATH_INFO': '/test'},
+                      lambda s, _: eq_(s, '200 OK'))
+        r = self.wsgi_app({'REQUEST_METHOD': 'DELETE',
+                           'PATH_INFO': '/test'},
+                          lambda s, _: eq_(s, '200 OK'))
+        eq_(r[0], 'root')
-- 
1.7.1


------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60133471&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to