Update docs with information about how to use thread-unsafe code in
[salmon.git] / tests / test_routing.py
blob53d6d93d8d7bf13a92cf8d923cba3785dde8aba9
1 from unittest.mock import MagicMock, Mock, patch
3 from salmon import routing
4 from salmon.mail import MailRequest
5 from salmon.routing import (MemoryStorage, Router, ShelveStorage, StateStorage, has_salmon_settings, locking, nolocking,
6 route, route_like, salmon_setting)
8 from .handlers import simple_fsm_mod
9 from .setup_env import SalmonTestCase, setup_router
12 class RoutingTestCase(SalmonTestCase):
13 def setUp(self):
14 super().setUp()
15 setup_router(['tests.handlers.simple_fsm_mod'])
17 def test_MemoryStorage(self):
18 store = MemoryStorage()
19 store.set(self.__module__, "tester@localhost", "TESTED")
21 self.assertEqual(store.get(self.__module__, "tester@localhost"), "TESTED")
23 self.assertEqual(store.get(self.__module__, "tester2@localhost"), "START")
25 store.clear()
27 self.assertEqual(store.get(self.__module__, "tester@localhost"), "START")
29 def test_ShelveStorage(self):
30 store = ShelveStorage("run/states.db")
32 store.set(self.__module__, "tester@localhost", "TESTED")
33 self.assertEqual(store.get(self.__module__, "tester@localhost"), "TESTED")
35 self.assertEqual(store.get(self.__module__, "tester2@localhost"), "START")
37 store.clear()
38 self.assertEqual(store.get(self.__module__, "tester@localhost"), "START")
40 def test_RoutingBase(self):
41 Router.clear_routes()
42 Router.clear_states()
43 Router.HANDLERS.clear()
45 # check that Router is in a pristine state
46 self.assertEqual(len(Router.ORDER), 0)
47 self.assertEqual(len(Router.REGISTERED), 0)
49 setup_router(['tests.handlers.simple_fsm_mod'])
51 self.assertEqual(len(Router.ORDER), 4)
52 self.assertEqual(len(Router.REGISTERED), 4)
54 message = MailRequest('fakepeer', 'zedshaw@localhost', 'users-subscribe@localhost', "")
55 Router.deliver(message)
56 assert Router.in_state(simple_fsm_mod.CONFIRM, message)
58 confirm = MailRequest('fakepeer', '"Zed Shaw" <zedshaw@localhost>', 'users-confirm-1@localhost', "")
59 Router.deliver(confirm)
60 assert Router.in_state(simple_fsm_mod.POSTING, message)
62 Router.deliver(message)
63 assert Router.in_state(simple_fsm_mod.NEXT, message)
65 Router.deliver(message)
66 assert Router.in_state(simple_fsm_mod.END, message)
68 Router.deliver(message)
69 assert Router.in_state(simple_fsm_mod.START, message)
71 Router.clear_states()
72 Router.LOG_EXCEPTIONS = True
73 explosion = MailRequest('fakepeer', '<hacker@localhost>', 'start-explode@localhost', "")
74 Router.deliver(explosion)
76 assert Router.in_error(simple_fsm_mod.END, explosion)
78 Router.clear_states()
79 Router.LOG_EXCEPTIONS = False
80 explosion = MailRequest('fakepeer', 'hacker@localhost', 'start-explode@localhost', "")
81 with self.assertRaises(RuntimeError):
82 Router.deliver(explosion)
84 Router.reload()
85 assert 'tests.handlers.simple_fsm_mod' in Router.HANDLERS
86 self.assertEqual(len(Router.ORDER), 4)
87 self.assertEqual(len(Router.REGISTERED), 4)
89 def test_Router_undeliverable_queue(self):
90 Router.clear_routes()
91 Router.clear_states()
93 Router.UNDELIVERABLE_QUEUE = Mock()
94 msg = MailRequest('fakepeer', 'from@localhost', 'to@localhost', "Nothing")
96 Router.deliver(msg)
97 self.assertEqual(Router.UNDELIVERABLE_QUEUE.push.call_count, 1)
99 def test_StateStorage_get_raises(self):
100 s = StateStorage()
101 with self.assertRaises(NotImplementedError):
102 s.get("raises", "raises")
104 def test_StateStorage_set_raises(self):
105 s = StateStorage()
106 with self.assertRaises(NotImplementedError):
107 s.set("raises", "raises", "raises")
109 def test_StateStorage_clear_raises(self):
110 s = StateStorage()
111 with self.assertRaises(NotImplementedError):
112 s.clear()
114 def test_route___get___raises(self):
115 class BadRoute:
117 @route("test")
118 def wont_work(message, **kw):
119 pass
121 br = BadRoute()
122 with self.assertRaises(TypeError):
123 br.wont_work("raises")
125 @patch('salmon.routing.reload', new=Mock(side_effect=ImportError))
126 @patch('salmon.routing.LOG', new=Mock())
127 def test_reload_raises(self):
128 Router.LOG_EXCEPTIONS = True
129 Router.reload()
130 self.assertEqual(routing.LOG.exception.call_count, 1)
132 Router.LOG_EXCEPTIONS = False
133 routing.LOG.exception.reset_mock()
134 with self.assertRaises(ImportError):
135 Router.reload()
136 self.assertEqual(routing.LOG.exception.call_count, 0)
138 routing.LOG.exception.reset_mock()
139 Router.LOG_EXCEPTIONS = True
140 Router.load(['fake.handler'])
141 self.assertEqual(routing.LOG.exception.call_count, 1)
143 Router.LOG_EXCEPTIONS = False
144 routing.LOG.exception.reset_mock()
145 with self.assertRaises(ImportError):
146 Router.load(['fake.handler'])
147 self.assertEqual(routing.LOG.exception.call_count, 0)
149 def test_route_like_typeerror(self):
150 def func():
151 pass
153 with self.assertRaises(TypeError):
154 route_like(func)
156 def test_locking_decorator(self):
157 def func():
158 pass
160 new_func = locking(func)
161 self.assertTrue(has_salmon_settings(new_func))
162 self.assertTrue(salmon_setting(new_func, "locking"))
164 def test_nolocking_decorator(self):
165 def func():
166 pass
168 with self.assertWarns(DeprecationWarning):
169 new_func = nolocking(func)
170 self.assertFalse(has_salmon_settings(new_func))
171 self.assertIsNone(salmon_setting(new_func, "locking"))
173 def test_locking_locks_router(self):
174 Router.clear_routes()
175 Router.clear_states()
176 Router.HANDLERS.clear()
178 @route(".*")
179 @locking
180 def START(message):
181 pass
183 message = MailRequest('peer', 'me@localhost', 'you@localhost', "")
184 with patch.object(Router, "call_lock", new=MagicMock()) as lock_mock:
185 Router.deliver(message)
186 self.assertEqual(lock_mock.__enter__.call_count, 1)
188 def test_no_locks_router(self):
189 Router.clear_routes()
190 Router.clear_states()
191 Router.HANDLERS.clear()
193 @route(".*")
194 def START(message):
195 pass
197 message = MailRequest('peer', 'me@localhost', 'you@localhost', "")
198 with patch.object(Router, "call_lock", new=MagicMock()) as lock_mock:
199 Router.deliver(message)
200 self.assertEqual(lock_mock.__enter__.call_count, 0)