Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 14e83c9

Browse files
committed
Introduce a new middleware API
This changeset deeply changes the middleware API. The spirit stays the same, but everything has been (at least) renamed, pre-existing middlewares will unconditionally break. The new API: - is much more clear; - offers better instrumentation opportunities (e.g: call tracing or the Raven/Sentry middleware). The following hooks changed: - call_procedure has been replaced by server_before_exec and server_after_exec, there is two reasons for this: * while kinda elegant it wouldn't allow any context (like the request or reply event) to be passed to the middleware because it had to take the exact same argument as the real (i.e: the served) method to be called; * I think two hooks are more clear here. - inspect_error has been renamed to server_inspect_exception for clarity; - raise_error has been replaced by client_handle_remote_error, not only the name is more clear, but it also return the new exception instead of raising it, which leave the liberty to the middleware to just inspect the exception on the client side (by returning nothing); The hooks also receive much more context than before (mainly via request and reply events objects). Two new client hooks are introduced: - client_before_request: called before the request is sent to the server; - client_after_request: called when an answer or a timeout has been received from the server. Unit tests have been added and updated accordingly. Moreover, PUB/SUB tests showed errors which seem to be an independent problem from this changeset and originate from pyzmq/libzmq directly; thus they have been disabled (you can use nose --no-skip to run them).
1 parent e11347f commit 14e83c9

File tree

9 files changed

+966
-310
lines changed

9 files changed

+966
-310
lines changed

tests/test_middleware.py

Lines changed: 70 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
from zerorpc import zmq
3333
import zerorpc
34-
from testutils import teardown, random_ipc_endpoint
34+
from testutils import teardown, random_ipc_endpoint, skip
3535

3636

3737
def test_resolve_endpoint():
@@ -49,11 +49,11 @@ def resolve(endpoint):
4949
print 'registered_count:', cnt
5050
assert cnt == 1
5151

52-
print 'resolve titi:', c.middleware_resolve_endpoint('titi')
53-
assert c.middleware_resolve_endpoint('titi') == test_endpoint
52+
print 'resolve titi:', c.hook_resolve_endpoint('titi')
53+
assert c.hook_resolve_endpoint('titi') == test_endpoint
5454

55-
print 'resolve toto:', c.middleware_resolve_endpoint('toto')
56-
assert c.middleware_resolve_endpoint('toto') == 'toto'
55+
print 'resolve toto:', c.hook_resolve_endpoint('toto')
56+
assert c.hook_resolve_endpoint('toto') == 'toto'
5757

5858
class Resolver():
5959

@@ -66,16 +66,16 @@ def resolve_endpoint(self, endpoint):
6666
print 'registered_count:', cnt
6767
assert cnt == 1
6868

69-
print 'resolve titi:', c.middleware_resolve_endpoint('titi')
70-
assert c.middleware_resolve_endpoint('titi') == test_endpoint
71-
print 'resolve toto:', c.middleware_resolve_endpoint('toto')
72-
assert c.middleware_resolve_endpoint('toto') == test_endpoint
69+
print 'resolve titi:', c.hook_resolve_endpoint('titi')
70+
assert c.hook_resolve_endpoint('titi') == test_endpoint
71+
print 'resolve toto:', c.hook_resolve_endpoint('toto')
72+
assert c.hook_resolve_endpoint('toto') == test_endpoint
7373

7474
c2 = zerorpc.Context()
75-
print 'resolve titi:', c2.middleware_resolve_endpoint('titi')
76-
assert c2.middleware_resolve_endpoint('titi') == 'titi'
77-
print 'resolve toto:', c2.middleware_resolve_endpoint('toto')
78-
assert c2.middleware_resolve_endpoint('toto') == 'toto'
75+
print 'resolve titi:', c2.hook_resolve_endpoint('titi')
76+
assert c2.hook_resolve_endpoint('titi') == 'titi'
77+
print 'resolve toto:', c2.hook_resolve_endpoint('toto')
78+
assert c2.hook_resolve_endpoint('toto') == 'toto'
7979

8080

8181
def test_resolve_endpoint_events():
@@ -110,151 +110,6 @@ def hello(self):
110110
srv.close()
111111

112112

113-
def test_raise_error():
114-
endpoint = random_ipc_endpoint()
115-
c = zerorpc.Context()
116-
117-
class DummyRaiser():
118-
def raise_error(self, event):
119-
pass
120-
121-
class Srv(zerorpc.Server):
122-
pass
123-
124-
srv = Srv(context=c)
125-
srv.bind(endpoint)
126-
gevent.spawn(srv.run)
127-
128-
client = zerorpc.Client(context=c)
129-
client.connect(endpoint)
130-
131-
with assert_raises(zerorpc.RemoteError):
132-
client.donotexist()
133-
134-
cnt = c.register_middleware(DummyRaiser())
135-
assert cnt == 1
136-
137-
with assert_raises(zerorpc.RemoteError):
138-
client.donotexist()
139-
140-
class HorribleEvalRaiser():
141-
def raise_error(self, event):
142-
(name, msg, tb) = event.args
143-
etype = eval(name)
144-
e = etype(tb)
145-
raise e
146-
147-
cnt = c.register_middleware(HorribleEvalRaiser())
148-
assert cnt == 1
149-
150-
with assert_raises(NameError):
151-
try:
152-
client.donotexist()
153-
except NameError as e:
154-
print 'got it:', e
155-
raise
156-
157-
client.close()
158-
srv.close()
159-
160-
161-
def test_call_procedure():
162-
c = zerorpc.Context()
163-
164-
def test(argument):
165-
return 'ret_real:' + argument
166-
assert c.middleware_call_procedure(test, 'dummy') == 'ret_real:dummy'
167-
168-
def middleware_1(procedure, *args, **kwargs):
169-
return 'ret_middleware_1:' + procedure(*args, **kwargs)
170-
cnt = c.register_middleware({
171-
'call_procedure': middleware_1
172-
})
173-
assert cnt == 1
174-
assert c.middleware_call_procedure(test, 'dummy') == \
175-
'ret_middleware_1:ret_real:dummy'
176-
177-
def middleware_2(procedure, *args, **kwargs):
178-
return 'ret_middleware_2:' + procedure(*args, **kwargs)
179-
cnt = c.register_middleware({
180-
'call_procedure': middleware_2
181-
})
182-
assert cnt == 1
183-
assert c.middleware_call_procedure(test, 'dummy') == \
184-
'ret_middleware_2:ret_middleware_1:ret_real:dummy'
185-
186-
def mangle_arguments(procedure, *args, **kwargs):
187-
return procedure(args[0].upper())
188-
cnt = c.register_middleware({
189-
'call_procedure': mangle_arguments
190-
})
191-
assert cnt == 1
192-
assert c.middleware_call_procedure(test, 'dummy') == \
193-
'ret_middleware_2:ret_middleware_1:ret_real:DUMMY'
194-
195-
endpoint = random_ipc_endpoint()
196-
197-
# client/server
198-
class Server(zerorpc.Server):
199-
def test(self, argument):
200-
return 'ret_real:' + argument
201-
server = Server(heartbeat=1, context=c)
202-
server.bind(endpoint)
203-
gevent.spawn(server.run)
204-
client = zerorpc.Client(heartbeat=1, context=c)
205-
client.connect(endpoint)
206-
assert client.test('dummy') == \
207-
'ret_middleware_2:ret_middleware_1:ret_real:DUMMY'
208-
client.close()
209-
server.close()
210-
211-
# push/pull
212-
trigger = gevent.event.Event()
213-
class Puller(zerorpc.Puller):
214-
argument = None
215-
216-
def test(self, argument):
217-
self.argument = argument
218-
trigger.set()
219-
return self.argument
220-
221-
puller = Puller(context=c)
222-
puller.bind(endpoint)
223-
gevent.spawn(puller.run)
224-
pusher = zerorpc.Pusher(context=c)
225-
pusher.connect(endpoint)
226-
trigger.clear()
227-
pusher.test('dummy')
228-
trigger.wait()
229-
assert puller.argument == 'DUMMY'
230-
#FIXME: These seems to be broken
231-
# pusher.close()
232-
# puller.close()
233-
234-
# pub/sub
235-
trigger = gevent.event.Event()
236-
class Subscriber(zerorpc.Subscriber):
237-
argument = None
238-
239-
def test(self, argument):
240-
self.argument = argument
241-
trigger.set()
242-
return self.argument
243-
244-
subscriber = Subscriber(context=c)
245-
subscriber.bind(endpoint)
246-
gevent.spawn(subscriber.run)
247-
publisher = zerorpc.Publisher(context=c)
248-
publisher.connect(endpoint)
249-
trigger.clear()
250-
publisher.test('dummy')
251-
trigger.wait()
252-
assert subscriber.argument == 'DUMMY'
253-
#FIXME: These seems to be broken
254-
# publisher.close()
255-
# subscriber.close()
256-
257-
258113
class Tracer:
259114
'''Used by test_task_context_* tests'''
260115
def __init__(self, identity):
@@ -488,6 +343,7 @@ def echo(self, msg):
488343
]
489344

490345

346+
@skip("PUB/SUB is badly broken in ZMQ and make this test fails")
491347
def test_task_context_pubsub():
492348
endpoint = random_ipc_endpoint()
493349
subscriber_ctx = zerorpc.Context()
@@ -525,25 +381,38 @@ def echo(self, msg):
525381
('load', publisher_tracer.trace_id),
526382
]
527383

528-
def test_inspect_error_middleware():
529384

530-
class InspectErrorMiddleware(Tracer):
531-
def __init__(self):
532-
self.called = False
533-
Tracer.__init__(self, identity='[server]')
385+
class InspectExceptionMiddleware(Tracer):
386+
def __init__(self, barrier=None):
387+
self.called = False
388+
self._barrier = barrier
389+
Tracer.__init__(self, identity='[server]')
390+
391+
def server_inspect_exception(self, request_event, reply_event, task_context, exc_info):
392+
assert 'trace_id' in task_context
393+
assert request_event.name == 'echo'
394+
if self._barrier: # Push/Pull
395+
assert reply_event is None
396+
else: # Req/Rep or Req/Stream
397+
assert reply_event.name == 'ERR'
398+
exc_type, exc_value, exc_traceback = exc_info
399+
self.called = True
400+
if self._barrier:
401+
self._barrier.set()
534402

535-
def inspect_error(self, task_context, exc_info):
536-
assert 'trace_id' in task_context
537-
exc_type, exc_value, exc_traceback = exc_info
538-
self.called = True
403+
class Srv(object):
539404

540-
class Srv(object):
541-
def echo(self, msg):
542-
raise RuntimeError(msg)
405+
def echo(self, msg):
406+
raise RuntimeError(msg)
543407

408+
@zerorpc.stream
409+
def echoes(self, msg):
410+
raise RuntimeError(msg)
411+
412+
def test_server_inspect_exception_middleware():
544413
endpoint = random_ipc_endpoint()
545414

546-
middleware = InspectErrorMiddleware()
415+
middleware = InspectExceptionMiddleware()
547416
ctx = zerorpc.Context()
548417
ctx.register_middleware(middleware)
549418

@@ -556,7 +425,7 @@ def echo(self, msg):
556425
client.connect(endpoint)
557426

558427
try:
559-
client.echo('This is a test which should call the InspectErrorMiddleware')
428+
client.echo('This is a test which should call the InspectExceptionMiddleware')
560429
except zerorpc.exceptions.RemoteError as ex:
561430
assert ex.name == 'RuntimeError'
562431

@@ -565,28 +434,11 @@ def echo(self, msg):
565434

566435
assert middleware.called is True
567436

568-
def test_inspect_error_middleware_puller():
569-
570-
class InspectErrorMiddleware(Tracer):
571-
def __init__(self, barrier):
572-
self.called = False
573-
self._barrier = barrier
574-
Tracer.__init__(self, identity='[server]')
575-
576-
def inspect_error(self, task_context, exc_info):
577-
assert 'trace_id' in task_context
578-
exc_type, exc_value, exc_traceback = exc_info
579-
self.called = True
580-
self._barrier.set()
581-
582-
class Srv(object):
583-
def echo(self, msg):
584-
raise RuntimeError(msg)
585-
437+
def test_server_inspect_exception_middleware_puller():
586438
endpoint = random_ipc_endpoint()
587439

588440
barrier = gevent.event.Event()
589-
middleware = InspectErrorMiddleware(barrier)
441+
middleware = InspectExceptionMiddleware(barrier)
590442
ctx = zerorpc.Context()
591443
ctx.register_middleware(middleware)
592444

@@ -599,8 +451,33 @@ def echo(self, msg):
599451
client.connect(endpoint)
600452

601453
barrier.clear()
602-
client.echo('This is a test which should call the InspectErrorMiddleware')
603-
barrier.wait()
454+
client.echo('This is a test which should call the InspectExceptionMiddleware')
455+
barrier.wait(timeout=2)
456+
457+
client.close()
458+
server.close()
459+
460+
assert middleware.called is True
461+
462+
def test_server_inspect_exception_middleware_stream():
463+
endpoint = random_ipc_endpoint()
464+
465+
middleware = InspectExceptionMiddleware()
466+
ctx = zerorpc.Context()
467+
ctx.register_middleware(middleware)
468+
469+
module = Srv()
470+
server = zerorpc.Server(module, context=ctx)
471+
server.bind(endpoint)
472+
gevent.spawn(server.run)
473+
474+
client = zerorpc.Client()
475+
client.connect(endpoint)
476+
477+
try:
478+
client.echo('This is a test which should call the InspectExceptionMiddleware')
479+
except zerorpc.exceptions.RemoteError as ex:
480+
assert ex.name == 'RuntimeError'
604481

605482
client.close()
606483
server.close()

0 commit comments

Comments
 (0)