2
# Copyright 2012, Big Switch Networks, Inc.
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
17
"""Test server mocking a REST based network ctrl.
19
Used for NeutronRestProxy tests
21
from __future__ import print_function
25
from oslo.serialization import jsonutils
27
from wsgiref import simple_server
30
class TestNetworkCtrl(object):
32
def __init__(self, host='', port=8000,
33
default_status='404 Not Found',
34
default_response='404 Not Found',
38
self.default_status = default_status
39
self.default_response = default_response
41
self.debug_env = False
42
self.debug_resp = False
45
def match(self, prior, method_regexp, uri_regexp, handler, data=None,
47
"""Add to the list of expected inputs.
49
The incoming request is matched in the order of priority. For same
50
priority, match the oldest match request first.
52
:param prior: integer priority of this match (e.g. 100)
53
:param method_regexp: regexp to match method (e.g. 'PUT|POST')
54
:param uri_regexp: regexp to match uri (e.g. '/quantum/v?.?/')
55
:param handler: function with signature:
56
lambda(method, uri, body, **kwargs) : status, body
58
- method: HTTP method for this request
59
- uri: URI for this HTTP request
60
- body: body of this HTTP request
62
- data: data object that was in the match call
63
- node: TestNetworkCtrl object itself
64
- id: offset of the matching tuple
67
- status: HTTP resp status (e.g. '200 OK').
68
If None, use default_status
69
- body: HTTP resp body. If None, use ''
71
assert int(prior) == prior, 'Priority should an integer be >= 0'
72
assert prior >= 0, 'Priority should an integer be >= 0'
74
lo, hi = 0, len(self.matches)
77
if prior < self.matches[mid][0]:
81
self.matches.insert(lo, (prior, method_regexp, uri_regexp, handler,
84
def remove_id(self, id_):
85
assert id_ >= 0, 'remove_id: id < 0'
86
assert id_ <= len(self.matches), 'remove_id: id > len()'
89
def request_handler(self, method, uri, body):
90
retstatus = self.default_status
91
retbody = self.default_response
92
for i in moves.xrange(len(self.matches)):
93
(unused_prior, method_regexp, uri_regexp, handler, data,
94
multi) = self.matches[i]
95
if re.match(method_regexp, method) and re.match(uri_regexp, uri):
101
retstatus, retbody = handler(method, uri, body, **kwargs)
107
return (retstatus, retbody)
110
def app(environ, start_response):
111
uri = environ['PATH_INFO']
112
method = environ['REQUEST_METHOD']
113
headers = [('Content-type', 'text/json')]
114
content_len_str = environ['CONTENT_LENGTH']
119
content_len = int(content_len_str)
120
request_data = environ.get('wsgi.input').read(content_len)
123
request_data = jsonutils.loads(request_data)
125
# OK for it not to be json! Ignore it
132
for (key, value) in sorted(environ.iteritems()):
133
print(' %16s : %s' % (key, value))
135
print('%s %s' % (method, uri))
139
request_data, sort_keys=True, indent=4))
141
status, body = self.request_handler(method, uri, None)
145
body_data = jsonutils.loads(body)
147
# OK for it not to be json! Ignore it
150
start_response(status, headers)
153
print('%s: %s' % ('Response',
155
body_data, sort_keys=True, indent=4)))
157
return simple_server.make_server(self.host, self.port, app)
160
print("Serving on port %d ..." % self.port)
162
self.server().serve_forever()
163
except KeyboardInterrupt:
167
if __name__ == "__main__":
171
if len(sys.argv) > 1:
172
port = int(sys.argv[1])
175
if len(sys.argv) > 2:
176
if sys.argv[2].lower() in ['debug', 'true']:
179
ctrl = TestNetworkCtrl(port=port,
180
default_status='200 OK',
181
default_response='{"status":"200 OK"}',
183
ctrl.match(100, 'GET', '/test',
184
lambda m, u, b, **k: ('200 OK', '["200 OK"]'))