1 # Copyright 2015 OpenStack Foundation
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
17 from neutron.callbacks import events
18 from neutron.callbacks import exceptions
19 from neutron.callbacks import manager
20 from neutron.callbacks import resources
21 from neutron.tests import base
24 def callback_1(*args, **kwargs):
25 callback_1.counter += 1
26 callback_id_1 = manager._get_id(callback_1)
29 def callback_2(*args, **kwargs):
30 callback_2.counter += 1
31 callback_id_2 = manager._get_id(callback_2)
34 def callback_raise(*args, **kwargs):
38 class CallBacksManagerTestCase(base.BaseTestCase):
41 super(CallBacksManagerTestCase, self).setUp()
42 self.manager = manager.CallbacksManager()
43 callback_1.counter = 0
44 callback_2.counter = 0
46 def test_subscribe(self):
47 self.manager.subscribe(
48 callback_1, resources.PORT, events.BEFORE_CREATE)
50 self.manager._callbacks[resources.PORT][events.BEFORE_CREATE])
51 self.assertIn(callback_id_1, self.manager._index)
53 def test_subscribe_unknown(self):
54 self.manager.subscribe(
55 callback_1, 'my_resource', 'my-event')
57 self.manager._callbacks['my_resource']['my-event'])
58 self.assertIn(callback_id_1, self.manager._index)
60 def test_subscribe_is_idempotent(self):
61 self.manager.subscribe(
62 callback_1, resources.PORT, events.BEFORE_CREATE)
63 self.manager.subscribe(
64 callback_1, resources.PORT, events.BEFORE_CREATE)
67 len(self.manager._callbacks[resources.PORT][events.BEFORE_CREATE]))
68 callbacks = self.manager._index[callback_id_1][resources.PORT]
69 self.assertEqual(1, len(callbacks))
71 def test_subscribe_multiple_callbacks(self):
72 self.manager.subscribe(
73 callback_1, resources.PORT, events.BEFORE_CREATE)
74 self.manager.subscribe(
75 callback_2, resources.PORT, events.BEFORE_CREATE)
76 self.assertEqual(2, len(self.manager._index))
79 len(self.manager._callbacks[resources.PORT][events.BEFORE_CREATE]))
81 def test_unsubscribe(self):
82 self.manager.subscribe(
83 callback_1, resources.PORT, events.BEFORE_CREATE)
84 self.manager.unsubscribe(
85 callback_1, resources.PORT, events.BEFORE_CREATE)
88 self.manager._callbacks[resources.PORT][events.BEFORE_CREATE])
89 self.assertNotIn(callback_id_1, self.manager._index)
91 def test_unsubscribe_unknown_callback(self):
92 self.manager.subscribe(
93 callback_2, resources.PORT, events.BEFORE_CREATE)
94 self.manager.unsubscribe(callback_1, mock.ANY, mock.ANY)
95 self.assertEqual(1, len(self.manager._index))
97 def test_unsubscribe_is_idempotent(self):
98 self.manager.subscribe(
99 callback_1, resources.PORT, events.BEFORE_CREATE)
100 self.manager.unsubscribe(
101 callback_1, resources.PORT, events.BEFORE_CREATE)
102 self.manager.unsubscribe(
103 callback_1, resources.PORT, events.BEFORE_CREATE)
104 self.assertNotIn(callback_id_1, self.manager._index)
105 self.assertNotIn(callback_id_1,
106 self.manager._callbacks[resources.PORT][events.BEFORE_CREATE])
108 def test_unsubscribe_by_resource(self):
109 self.manager.subscribe(
110 callback_1, resources.PORT, events.BEFORE_CREATE)
111 self.manager.subscribe(
112 callback_1, resources.PORT, events.BEFORE_DELETE)
113 self.manager.subscribe(
114 callback_2, resources.PORT, events.BEFORE_DELETE)
115 self.manager.unsubscribe_by_resource(callback_1, resources.PORT)
118 self.manager._callbacks[resources.PORT][events.BEFORE_CREATE])
121 self.manager._callbacks[resources.PORT][events.BEFORE_DELETE])
122 self.assertNotIn(callback_id_1, self.manager._index)
124 def test_unsubscribe_all(self):
125 self.manager.subscribe(
126 callback_1, resources.PORT, events.BEFORE_CREATE)
127 self.manager.subscribe(
128 callback_1, resources.PORT, events.BEFORE_DELETE)
129 self.manager.subscribe(
130 callback_1, resources.ROUTER, events.BEFORE_CREATE)
131 self.manager.unsubscribe_all(callback_1)
134 self.manager._callbacks[resources.PORT][events.BEFORE_CREATE])
135 self.assertNotIn(callback_id_1, self.manager._index)
137 def test_notify_none(self):
138 self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
139 self.assertEqual(0, callback_1.counter)
140 self.assertEqual(0, callback_2.counter)
142 def test_feebly_referenced_callback(self):
143 self.manager.subscribe(lambda *x, **y: None, resources.PORT,
144 events.BEFORE_CREATE)
145 self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
147 def test_notify_with_exception(self):
148 with mock.patch.object(self.manager, '_notify_loop') as n:
149 n.return_value = ['error']
150 self.assertRaises(exceptions.CallbackFailure,
152 mock.ANY, events.BEFORE_CREATE,
153 'trigger', params={'a': 1})
155 mock.call(mock.ANY, 'before_create',
156 'trigger', params={'a': 1}),
157 mock.call(mock.ANY, 'abort_create',
158 'trigger', params={'a': 1})
160 n.assert_has_calls(expected_calls)
162 def test_notify_handle_exception(self):
163 self.manager.subscribe(
164 callback_raise, resources.PORT, events.BEFORE_CREATE)
165 e = self.assertRaises(exceptions.CallbackFailure, self.manager.notify,
166 resources.PORT, events.BEFORE_CREATE, self)
167 self.assertIsInstance(e.errors[0], exceptions.NotificationError)
169 def test_notify_called_once_with_no_failures(self):
170 with mock.patch.object(self.manager, '_notify_loop') as n:
171 n.return_value = False
172 self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
173 n.assert_called_once_with(
174 resources.PORT, events.BEFORE_CREATE, mock.ANY)
176 def test__notify_loop_single_event(self):
177 self.manager.subscribe(
178 callback_1, resources.PORT, events.BEFORE_CREATE)
179 self.manager.subscribe(
180 callback_2, resources.PORT, events.BEFORE_CREATE)
181 self.manager._notify_loop(
182 resources.PORT, events.BEFORE_CREATE, mock.ANY)
183 self.assertEqual(1, callback_1.counter)
184 self.assertEqual(1, callback_2.counter)
186 def test__notify_loop_multiple_events(self):
187 self.manager.subscribe(
188 callback_1, resources.PORT, events.BEFORE_CREATE)
189 self.manager.subscribe(
190 callback_1, resources.ROUTER, events.BEFORE_DELETE)
191 self.manager.subscribe(
192 callback_2, resources.PORT, events.BEFORE_CREATE)
193 self.manager._notify_loop(
194 resources.PORT, events.BEFORE_CREATE, mock.ANY)
195 self.manager._notify_loop(
196 resources.ROUTER, events.BEFORE_DELETE, mock.ANY)
197 self.assertEqual(2, callback_1.counter)
198 self.assertEqual(1, callback_2.counter)