[feature] reactor-based authenticator
[leap_pycommon.git] / src / leap / common / tests / test_events.py
1 # -*- coding: utf-8 -*-
2 # test_events.py
3 # Copyright (C) 2013 LEAP
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18
19 import os
20 import logging
21 import time
22
23 from twisted.internet.reactor import callFromThread
24 from twisted.trial import unittest
25 from twisted.internet import defer
26
27 from leap.common.events import server
28 from leap.common.events import client
29 from leap.common.events import flags
30 from leap.common.events import txclient
31 from leap.common.events import catalog
32 from leap.common.events.errors import CallbackAlreadyRegisteredError
33
34
35 if 'DEBUG' in os.environ:
36     logging.basicConfig(level=logging.DEBUG)
37
38
39 class EventsGenericClientTestCase(object):
40
41     def setUp(self):
42         flags.set_events_enabled(True)
43         self._server = server.ensure_server(
44             emit_addr="tcp://127.0.0.1:0",
45             reg_addr="tcp://127.0.0.1:0")
46         self._client.configure_client(
47             emit_addr="tcp://127.0.0.1:%d" % self._server.pull_port,
48             reg_addr="tcp://127.0.0.1:%d" % self._server.pub_port)
49
50     def tearDown(self):
51         self._client.shutdown()
52         self._server.shutdown()
53         flags.set_events_enabled(False)
54         # wait a bit for sockets to close properly
55         time.sleep(0.1)
56
57     def test_client_register(self):
58         """
59         Ensure clients can register callbacks.
60         """
61         callbacks = self._client.instance().callbacks
62         self.assertTrue(len(callbacks) == 0,
63                         'There should be no callback for this event.')
64         # register one event
65         event1 = catalog.CLIENT_UID
66
67         def cbk1(event, _):
68             return True
69
70         uid1 = self._client.register(event1, cbk1)
71         # assert for correct registration
72         self.assertTrue(len(callbacks) == 1)
73         self.assertTrue(callbacks[event1][uid1] == cbk1,
74                         'Could not register event in local client.')
75         # register another event
76         event2 = catalog.CLIENT_SESSION_ID
77
78         def cbk2(event, _):
79             return True
80
81         uid2 = self._client.register(event2, cbk2)
82         # assert for correct registration
83         self.assertTrue(len(callbacks) == 2)
84         self.assertTrue(callbacks[event2][uid2] == cbk2,
85                         'Could not register event in local client.')
86
87     def test_register_signal_replace(self):
88         """
89         Make sure clients can replace already registered callbacks.
90         """
91         event = catalog.CLIENT_UID
92         d = defer.Deferred()
93
94         def cbk_fail(event, _):
95             return callFromThread(d.errback, event)
96
97         def cbk_succeed(event, _):
98             return callFromThread(d.callback, event)
99
100         self._client.register(event, cbk_fail, uid=1)
101         self._client.register(event, cbk_succeed, uid=1, replace=True)
102         self._client.emit(event, None)
103         return d
104
105     def test_register_signal_replace_fails_when_replace_is_false(self):
106         """
107         Make sure clients trying to replace already registered callbacks fail
108         when replace=False
109         """
110         event = catalog.CLIENT_UID
111         self._client.register(event, lambda event, _: None, uid=1)
112         self.assertRaises(
113             CallbackAlreadyRegisteredError,
114             self._client.register,
115             event, lambda event, _: None, uid=1, replace=False)
116
117     def test_register_more_than_one_callback_works(self):
118         """
119         Make sure clients can replace already registered callbacks.
120         """
121         event = catalog.CLIENT_UID
122         d1 = defer.Deferred()
123
124         def cbk1(event, _):
125             return callFromThread(d1.callback, event)
126
127         d2 = defer.Deferred()
128
129         def cbk2(event, _):
130             return d2.callback(event)
131
132         self._client.register(event, cbk1)
133         self._client.register(event, cbk2)
134         self._client.emit(event, None)
135         d = defer.gatherResults([d1, d2])
136         return d
137
138     def test_client_receives_signal(self):
139         """
140         Ensure clients can receive signals.
141         """
142         event = catalog.CLIENT_UID
143         d = defer.Deferred()
144
145         def cbk(events, _):
146             callFromThread(d.callback, event)
147
148         self._client.register(event, cbk)
149         self._client.emit(event, None)
150         return d
151
152     def test_client_unregister_all(self):
153         """
154         Test that the client can unregister all events for one signal.
155         """
156         event1 = catalog.CLIENT_UID
157         d = defer.Deferred()
158         # register more than one callback for the same event
159         self._client.register(
160             event1, lambda ev, _: callFromThread(d.errback, None))
161         self._client.register(
162             event1, lambda ev, _: callFromThread(d.errback, None))
163         # unregister and emit the event
164         self._client.unregister(event1)
165         self._client.emit(event1, None)
166         # register and emit another event so the deferred can succeed
167         event2 = catalog.CLIENT_SESSION_ID
168         self._client.register(
169             event2, lambda ev, _: callFromThread(d.callback, None))
170         self._client.emit(event2, None)
171         return d
172
173     def test_client_unregister_by_uid(self):
174         """
175         Test that the client can unregister an event by uid.
176         """
177         event = catalog.CLIENT_UID
178         d = defer.Deferred()
179         # register one callback that would fail
180         uid = self._client.register(
181             event, lambda ev, _: callFromThread(d.errback, None))
182         # register one callback that will succeed
183         self._client.register(
184             event, lambda ev, _: callFromThread(d.callback, None))
185         # unregister by uid and emit the event
186         self._client.unregister(event, uid=uid)
187         self._client.emit(event, None)
188         return d
189
190
191 class EventsTxClientTestCase(EventsGenericClientTestCase, unittest.TestCase):
192
193     _client = txclient
194
195
196 class EventsClientTestCase(EventsGenericClientTestCase, unittest.TestCase):
197
198     _client = client