1#!/usr/bin/env python3 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16import threading 17import unittest 18from unittest import TestCase 19 20from mock import Mock 21from mock import patch 22 23from acts.event import event_bus 24from acts.event.event import Event 25from acts.event.event_subscription import EventSubscription 26 27 28class EventBusTest(TestCase): 29 """Tests the event_bus functions.""" 30 31 def setUp(self): 32 """Clears all state from the event_bus between test cases.""" 33 event_bus._event_bus = event_bus._EventBus() 34 35 def get_subscription_argument(self, register_subscription_call): 36 """Gets the subscription argument from a register_subscription call.""" 37 return register_subscription_call[0][0] 38 39 @patch('acts.event.event_bus._event_bus.register_subscription') 40 def test_register_registers_a_subscription(self, register_subscription): 41 """Tests that register creates and registers a subscription.""" 42 mock_event = Mock() 43 mock_func = Mock() 44 order = 43 45 event_bus.register(mock_event, mock_func, order=order) 46 47 args, _ = register_subscription.call_args 48 subscription = args[0] 49 50 # Instead of writing an equality operator for only testing, 51 # check the internals to make sure they are expected values. 52 self.assertEqual(subscription._event_type, mock_event) 53 self.assertEqual(subscription._func, mock_func) 54 self.assertEqual(subscription.order, order) 55 56 @patch('acts.event.event_bus._event_bus.register_subscription') 57 def test_register_subscriptions_for_list(self, register_subscription): 58 """Tests that register_subscription is called for each subscription.""" 59 mocks = [Mock(), Mock(), Mock()] 60 subscriptions = [ 61 EventSubscription(mocks[0], lambda _: None), 62 EventSubscription(mocks[1], lambda _: None), 63 EventSubscription(mocks[2], lambda _: None), 64 ] 65 66 event_bus.register_subscriptions(subscriptions) 67 received_subscriptions = set() 68 for index, call in enumerate(register_subscription.call_args_list): 69 received_subscriptions.add(self.get_subscription_argument(call)) 70 71 self.assertEqual(register_subscription.call_count, len(subscriptions)) 72 self.assertSetEqual(received_subscriptions, set(subscriptions)) 73 74 def test_register_subscription_new_event_type(self): 75 """Tests that the event_bus can register a new event type.""" 76 mock_type = Mock() 77 bus = event_bus._event_bus 78 subscription = EventSubscription(mock_type, lambda _: None) 79 80 reg_id = event_bus.register_subscription(subscription) 81 82 self.assertTrue(mock_type in bus._subscriptions.keys()) 83 self.assertTrue(subscription in bus._subscriptions[mock_type]) 84 self.assertTrue(reg_id in bus._registration_id_map.keys()) 85 86 def test_register_subscription_existing_type(self): 87 """Tests that the event_bus can register an existing event type.""" 88 mock_type = Mock() 89 bus = event_bus._event_bus 90 bus._subscriptions[mock_type] = [ 91 EventSubscription(mock_type, lambda _: None)] 92 new_subscription = EventSubscription(mock_type, lambda _: True) 93 94 reg_id = event_bus.register_subscription(new_subscription) 95 96 self.assertTrue(new_subscription in bus._subscriptions[mock_type]) 97 self.assertTrue(reg_id in bus._registration_id_map.keys()) 98 99 def test_post_to_unregistered_event_does_not_call_other_funcs(self): 100 """Tests posting an unregistered event will not call other funcs.""" 101 mock_subscription = Mock() 102 bus = event_bus._event_bus 103 mock_type = Mock() 104 mock_subscription.event_type = mock_type 105 bus._subscriptions[mock_type] = [mock_subscription] 106 107 event_bus.post(Mock()) 108 109 self.assertEqual(mock_subscription.deliver.call_count, 0) 110 111 def test_post_to_registered_event_calls_all_registered_funcs(self): 112 """Tests posting to a registered event calls all registered funcs.""" 113 mock_subscriptions = [Mock(), Mock(), Mock()] 114 bus = event_bus._event_bus 115 for subscription in mock_subscriptions: 116 subscription.order = 0 117 mock_event = Mock() 118 bus._subscriptions[type(mock_event)] = mock_subscriptions 119 120 event_bus.post(mock_event) 121 122 for subscription in mock_subscriptions: 123 subscription.deliver.assert_called_once_with(mock_event) 124 125 def test_post_with_ignore_errors_calls_all_registered_funcs(self): 126 """Tests posting with ignore_errors=True calls all registered funcs, 127 even if they raise errors. 128 """ 129 def _raise(_): 130 raise Exception 131 mock_event = Mock() 132 mock_subscriptions = [Mock(), Mock(), Mock()] 133 mock_subscriptions[0].deliver.side_effect = _raise 134 bus = event_bus._event_bus 135 for i, subscription in enumerate(mock_subscriptions): 136 subscription.order = i 137 bus._subscriptions[type(mock_event)] = mock_subscriptions 138 139 event_bus.post(mock_event, ignore_errors=True) 140 141 for subscription in mock_subscriptions: 142 subscription.deliver.assert_called_once_with(mock_event) 143 144 @patch('acts.event.event_bus._event_bus.unregister') 145 def test_unregister_all_from_list(self, unregister): 146 """Tests unregistering from a list unregisters the specified list.""" 147 unregister_list = [Mock(), Mock()] 148 149 event_bus.unregister_all(from_list=unregister_list) 150 151 self.assertEqual(unregister.call_count, len(unregister_list)) 152 for args, _ in unregister.call_args_list: 153 subscription = args[0] 154 self.assertTrue(subscription in unregister_list) 155 156 @patch('acts.event.event_bus._event_bus.unregister') 157 def test_unregister_all_from_event(self, unregister): 158 """Tests that all subscriptions under the event are unregistered.""" 159 mock_event = Mock() 160 mock_event_2 = Mock() 161 bus = event_bus._event_bus 162 unregister_list = [Mock(), Mock()] 163 bus._subscriptions[type(mock_event_2)] = [Mock(), Mock(), Mock()] 164 bus._subscriptions[type(mock_event)] = unregister_list 165 for sub_type in bus._subscriptions.keys(): 166 for subscription in bus._subscriptions[sub_type]: 167 subscription.event_type = sub_type 168 bus._registration_id_map[id(subscription)] = subscription 169 170 event_bus.unregister_all(from_event=type(mock_event)) 171 172 self.assertEqual(unregister.call_count, len(unregister_list)) 173 for args, _ in unregister.call_args_list: 174 subscription = args[0] 175 self.assertTrue(subscription in unregister_list) 176 177 @patch('acts.event.event_bus._event_bus.unregister') 178 def test_unregister_all_no_args_unregisters_everything(self, unregister): 179 """Tests unregister_all without arguments will unregister everything.""" 180 mock_event_1 = Mock() 181 mock_event_2 = Mock() 182 bus = event_bus._event_bus 183 unregister_list_1 = [Mock(), Mock()] 184 unregister_list_2 = [Mock(), Mock(), Mock()] 185 bus._subscriptions[type(mock_event_1)] = unregister_list_1 186 bus._subscriptions[type(mock_event_2)] = unregister_list_2 187 for sub_type in bus._subscriptions.keys(): 188 for subscription in bus._subscriptions[sub_type]: 189 subscription.event_type = sub_type 190 bus._registration_id_map[id(subscription)] = subscription 191 192 event_bus.unregister_all() 193 194 self.assertEqual(unregister.call_count, 195 len(unregister_list_1) + len(unregister_list_2)) 196 for args, _ in unregister.call_args_list: 197 subscription = args[0] 198 self.assertTrue(subscription in unregister_list_1 or 199 subscription in unregister_list_2) 200 201 def test_unregister_given_an_event_subscription(self): 202 """Tests that unregister can unregister a given EventSubscription.""" 203 mock_event = Mock() 204 bus = event_bus._event_bus 205 subscription = EventSubscription(type(mock_event), lambda _: None) 206 bus._registration_id_map[id(subscription)] = subscription 207 bus._subscriptions[type(mock_event)] = [subscription] 208 209 val = event_bus.unregister(subscription) 210 211 self.assertTrue(val) 212 self.assertTrue(subscription not in bus._registration_id_map) 213 self.assertTrue( 214 subscription not in bus._subscriptions[type(mock_event)]) 215 216 def test_unregister_given_a_registration_id(self): 217 """Tests that unregister can unregister a given EventSubscription.""" 218 mock_event = Mock() 219 bus = event_bus._event_bus 220 subscription = EventSubscription(type(mock_event), lambda _: None) 221 registration_id = id(subscription) 222 bus._registration_id_map[id(subscription)] = subscription 223 bus._subscriptions[type(mock_event)] = [subscription] 224 225 val = event_bus.unregister(registration_id) 226 227 self.assertTrue(val) 228 self.assertTrue(subscription not in bus._registration_id_map) 229 self.assertTrue( 230 subscription not in bus._subscriptions[type(mock_event)]) 231 232 def test_unregister_given_object_that_is_not_a_subscription(self): 233 """Asserts that a ValueError is raised upon invalid arguments.""" 234 with self.assertRaises(ValueError): 235 event_bus.unregister(Mock()) 236 237 def test_unregister_given_invalid_registration_id(self): 238 """Asserts that a false is returned upon invalid registration_id.""" 239 val = event_bus.unregister(9) 240 self.assertFalse(val) 241 242 def test_listen_for_registers_listener(self): 243 """Tests listen_for registers the listener within the with statement.""" 244 bus = event_bus._event_bus 245 246 def event_listener(_): 247 pass 248 249 with event_bus.listen_for(Event, event_listener): 250 self.assertEqual(len(bus._registration_id_map), 1) 251 252 def test_listen_for_unregisters_listener(self): 253 """Tests listen_for unregisters the listener after the with statement. 254 """ 255 bus = event_bus._event_bus 256 257 def event_listener(_): 258 pass 259 260 with event_bus.listen_for(Event, event_listener): 261 pass 262 263 self.assertEqual(len(bus._registration_id_map), 0) 264 265 266if __name__ == '__main__': 267 unittest.main() 268