github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/tests/test_events/tests.py (about) 1 # Copyright 2017 Intel Corporation 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ------------------------------------------------------------------------------ 15 16 # pylint: disable=protected-access 17 18 import unittest 19 from unittest.mock import Mock 20 from uuid import uuid4 21 22 from sawtooth_validator.database.dict_database import DictDatabase 23 from sawtooth_validator.journal.block_store import BlockStore 24 from sawtooth_validator.journal.block_wrapper import BlockWrapper 25 from sawtooth_validator.journal.event_extractors \ 26 import BlockEventExtractor 27 from sawtooth_validator.journal.receipt_store import TransactionReceiptStore 28 from sawtooth_validator.networking.dispatch import HandlerStatus 29 30 from sawtooth_validator.server.events.broadcaster import EventBroadcaster 31 from sawtooth_validator.server.events.handlers \ 32 import ClientEventsGetRequestHandler 33 from sawtooth_validator.server.events.handlers \ 34 import ClientEventsSubscribeValidationHandler 35 from sawtooth_validator.server.events.handlers \ 36 import ClientEventsSubscribeHandler 37 from sawtooth_validator.server.events.handlers \ 38 import ClientEventsUnsubscribeHandler 39 40 from sawtooth_validator.server.events.subscription import EventSubscription 41 from sawtooth_validator.server.events.subscription import EventFilterFactory 42 43 from sawtooth_validator.execution.tp_state_handlers import TpEventAddHandler 44 45 from sawtooth_validator.protobuf import events_pb2 46 from sawtooth_validator.protobuf import client_event_pb2 47 from sawtooth_validator.protobuf import block_pb2 48 from sawtooth_validator.protobuf import state_context_pb2 49 from sawtooth_validator.protobuf import transaction_receipt_pb2 50 from sawtooth_validator.protobuf import validator_pb2 51 52 from sawtooth_signing import create_context 53 from sawtooth_signing import CryptoFactory 54 55 from test_scheduler.yaml_scheduler_tester import create_batch 56 from test_scheduler.yaml_scheduler_tester import create_transaction 57 58 59 def create_block(block_num=85, 60 previous_block_id="0000000000000000", 61 block_id="abcdef1234567890", 62 batches=None): 63 if batches is None: 64 batches = [] 65 block_header = block_pb2.BlockHeader( 66 block_num=block_num, 67 state_root_hash="0987654321fedcba", 68 previous_block_id=previous_block_id) 69 block = BlockWrapper( 70 block_pb2.Block( 71 header_signature=block_id, 72 header=block_header.SerializeToString(), 73 batches=batches)) 74 return block 75 76 77 def create_chain(num=10): 78 context = create_context('secp256k1') 79 private_key = context.new_random_private_key() 80 crypto_factory = CryptoFactory(context) 81 signer = crypto_factory.new_signer(private_key) 82 83 counter = 1 84 previous_block_id = "0000000000000000" 85 blocks = [] 86 while counter <= num: 87 current_block_id = uuid4().hex 88 txns = [ 89 t[0] 90 for t in [ 91 create_transaction( 92 payload=uuid4().hex.encode(), signer=signer) 93 for _ in range(20) 94 ] 95 ] 96 97 txn_ids = [t.header_signature for t in txns] 98 batch = create_batch( 99 transactions=txns, 100 signer=signer) 101 102 blk_w = create_block( 103 counter, 104 previous_block_id, 105 current_block_id, 106 batches=[batch]) 107 blocks.append((current_block_id, blk_w, txn_ids)) 108 109 counter += 1 110 previous_block_id = current_block_id 111 112 return blocks 113 114 115 def create_receipt(txn_id, key_values): 116 events = [] 117 for key, value in key_values: 118 event = events_pb2.Event() 119 event.event_type = "sawtooth/block-commit" 120 attribute = event.attributes.add() 121 attribute.key = key 122 attribute.value = value 123 events.append(event) 124 125 receipt = transaction_receipt_pb2.TransactionReceipt(transaction_id=txn_id) 126 receipt.events.extend(events) 127 return receipt 128 129 130 def create_block_commit_subscription(): 131 return EventSubscription(event_type="sawtooth/block-commit") 132 133 134 FILTER_FACTORY = EventFilterFactory() 135 136 137 class EventSubscriptionTest(unittest.TestCase): 138 def test_filter(self): 139 """Test that a regex filter matches properly against an event.""" 140 self.assertIn( 141 events_pb2.Event(attributes=[ 142 events_pb2.Event.Attribute( 143 key="address", value="000000" + "f" * 64)]), 144 FILTER_FACTORY.create( 145 key="address", match_string="000000.*", 146 filter_type=events_pb2.EventFilter.REGEX_ANY)) 147 148 self.assertIn( 149 events_pb2.Event(attributes=[ 150 events_pb2.Event.Attribute(key="abc", value="123")]), 151 FILTER_FACTORY.create(key="abc", match_string="123")) 152 153 def test_subscription(self): 154 """Test that an event correctly matches against a subscription.""" 155 self.assertIn( 156 events_pb2.Event( 157 event_type="test", attributes=[ 158 events_pb2.Event.Attribute( 159 key="test", value="test")]), 160 EventSubscription( 161 event_type="test", filters=[ 162 FILTER_FACTORY.create( 163 key="test", match_string="test")])) 164 165 166 class ClientEventsSubscribeValidationHandlerTest(unittest.TestCase): 167 def test_subscribe(self): 168 """Test that a subscriber is successfully validated and added to the 169 event broadcaster. 170 """ 171 172 mock_event_broadcaster = Mock() 173 mock_event_broadcaster.get_latest_known_block_id.return_value = \ 174 "0" * 128 175 handler = \ 176 ClientEventsSubscribeValidationHandler(mock_event_broadcaster) 177 request = client_event_pb2.ClientEventsSubscribeRequest( 178 subscriptions=[ 179 events_pb2.EventSubscription( 180 event_type="test_event", 181 filters=[ 182 events_pb2.EventFilter( 183 key="test", 184 match_string="test", 185 filter_type=events_pb2.EventFilter.SIMPLE_ANY) 186 ], 187 ) 188 ], 189 last_known_block_ids=["0" * 128]).SerializeToString() 190 191 response = handler.handle("test_conn_id", request) 192 193 mock_event_broadcaster.add_subscriber.assert_called_with( 194 "test_conn_id", 195 [EventSubscription( 196 event_type="test_event", 197 filters=[ 198 FILTER_FACTORY.create(key="test", match_string="test")])], 199 "0" * 128) 200 self.assertEqual(HandlerStatus.RETURN_AND_PASS, response.status) 201 self.assertEqual(client_event_pb2.ClientEventsSubscribeResponse.OK, 202 response.message_out.status) 203 204 def test_subscribe_bad_filter(self): 205 """Tests that the handler will respond with an INVALID_FILTER 206 when a subscriber provides an invalid filter. 207 """ 208 mock_event_broadcaster = Mock() 209 handler = \ 210 ClientEventsSubscribeValidationHandler(mock_event_broadcaster) 211 request = client_event_pb2.ClientEventsSubscribeRequest( 212 subscriptions=[ 213 events_pb2.EventSubscription( 214 event_type="test_event", 215 filters=[ 216 events_pb2.EventFilter( 217 key="test", 218 match_string="???", 219 filter_type=events_pb2.EventFilter.REGEX_ANY) 220 ], 221 ) 222 ], 223 last_known_block_ids=["0" * 128]).SerializeToString() 224 225 response = handler.handle("test_conn_id", request) 226 227 mock_event_broadcaster.add_subscriber.assert_not_called() 228 self.assertEqual(HandlerStatus.RETURN, response.status) 229 self.assertEqual( 230 client_event_pb2.ClientEventsSubscribeResponse.INVALID_FILTER, 231 response.message_out.status) 232 233 234 class ClientEventsSubscribeHandlersTest(unittest.TestCase): 235 def test_subscribe(self): 236 """Tests that the handler turns on the subscriber.""" 237 mock_event_broadcaster = Mock() 238 handler = ClientEventsSubscribeHandler(mock_event_broadcaster) 239 request = client_event_pb2.ClientEventsSubscribeRequest() 240 241 response = handler.handle("test_conn_id", request) 242 243 mock_event_broadcaster.enable_subscriber.assert_called_with( 244 "test_conn_id") 245 self.assertEqual(HandlerStatus.PASS, response.status) 246 247 248 class ClientEventsUnsubscribeHandlerTest(unittest.TestCase): 249 def test_unsubscribe(self): 250 """Test that a handler will unregister a subscriber via a requestor's 251 connection id. 252 """ 253 mock_event_broadcaster = Mock() 254 handler = ClientEventsUnsubscribeHandler(mock_event_broadcaster) 255 256 request = ( 257 client_event_pb2.ClientEventsUnsubscribeRequest() 258 .SerializeToString() 259 ) 260 261 response = handler.handle('test_conn_id', request) 262 263 mock_event_broadcaster.disable_subscriber.assert_called_with( 264 'test_conn_id') 265 mock_event_broadcaster.remove_subscriber.assert_called_with( 266 'test_conn_id') 267 268 self.assertEqual(HandlerStatus.RETURN, response.status) 269 self.assertEqual(client_event_pb2.ClientEventsUnsubscribeResponse.OK, 270 response.message_out.status) 271 272 273 class ClientEventsGetRequestHandlerTest(unittest.TestCase): 274 def setUp(self): 275 self.block_store = BlockStore(DictDatabase()) 276 self.receipt_store = TransactionReceiptStore(DictDatabase()) 277 self._txn_ids_by_block_id = {} 278 for block_id, blk_w, txn_ids in create_chain(): 279 self.block_store[block_id] = blk_w 280 self._txn_ids_by_block_id[block_id] = txn_ids 281 for txn_id in txn_ids: 282 receipt = create_receipt(txn_id=txn_id, 283 key_values=[("address", block_id)]) 284 self.receipt_store.put( 285 txn_id=txn_id, 286 txn_receipt=receipt) 287 288 def test_get_events_by_block_id(self): 289 """Tests that the correct events are returned by the 290 ClientEventsGetRequest handler for each block id. 291 292 """ 293 294 event_broadcaster = EventBroadcaster( 295 Mock(), 296 block_store=self.block_store, 297 receipt_store=self.receipt_store) 298 for block_id, _ in self._txn_ids_by_block_id.items(): 299 request = client_event_pb2.ClientEventsGetRequest() 300 request.block_ids.extend([block_id]) 301 subscription = request.subscriptions.add() 302 subscription.event_type = "sawtooth/block-commit" 303 event_filter = subscription.filters.add() 304 event_filter.key = "address" 305 event_filter.match_string = block_id 306 event_filter.filter_type = event_filter.SIMPLE_ALL 307 308 event_filter2 = subscription.filters.add() 309 event_filter2.key = "block_id" 310 event_filter2.match_string = block_id 311 event_filter2.filter_type = event_filter2.SIMPLE_ALL 312 313 handler = ClientEventsGetRequestHandler(event_broadcaster) 314 handler_output = handler.handle( 315 "dummy_conn_id", 316 request.SerializeToString()) 317 318 self.assertEqual(handler_output.message_type, 319 validator_pb2.Message.CLIENT_EVENTS_GET_RESPONSE) 320 321 self.assertEqual(handler_output.status, HandlerStatus.RETURN) 322 self.assertTrue( 323 all(any(a.value == block_id 324 for a in e.attributes) 325 for e in handler_output.message_out.events), 326 "Each Event has at least one attribute value that is the" 327 " block id for the block.") 328 self.assertEqual(handler_output.message_out.status, 329 client_event_pb2.ClientEventsGetResponse.OK) 330 self.assertTrue(len(handler_output.message_out.events) > 0) 331 332 333 class EventBroadcasterTest(unittest.TestCase): 334 def test_add_remove_subscriber(self): 335 """Test adding and removing a subscriber.""" 336 mock_service = Mock() 337 mock_block_store = Mock() 338 mock_receipt_store = Mock() 339 event_broadcaster = EventBroadcaster(mock_service, 340 mock_block_store, 341 mock_receipt_store) 342 subscriptions = [ 343 EventSubscription( 344 event_type="test_event", 345 filters=[ 346 FILTER_FACTORY.create(key="test", match_string="test") 347 ], 348 ) 349 ] 350 event_broadcaster.add_subscriber("test_conn_id", subscriptions, []) 351 352 self.assertTrue( 353 "test_conn_id" in event_broadcaster._subscribers.keys()) 354 self.assertEqual( 355 event_broadcaster._subscribers["test_conn_id"].subscriptions, 356 subscriptions) 357 358 event_broadcaster.remove_subscriber("test_conn_id") 359 360 self.assertTrue( 361 "test_conn_id" not in event_broadcaster._subscribers.keys()) 362 363 def test_broadcast_events(self): 364 """Test that broadcast_events works with a single subscriber to the 365 sawtooth/block-commit event type and that the subscriber does 366 not receive events until it is enabled. 367 368 """ 369 mock_service = Mock() 370 mock_block_store = Mock() 371 mock_receipt_store = Mock() 372 event_broadcaster = EventBroadcaster(mock_service, 373 mock_block_store, 374 mock_receipt_store) 375 block = create_block() 376 377 event_broadcaster.chain_update(block, []) 378 mock_service.send.assert_not_called() 379 380 event_broadcaster.add_subscriber( 381 "test_conn_id", [create_block_commit_subscription()], []) 382 383 event_broadcaster.chain_update(block, []) 384 mock_service.send.assert_not_called() 385 386 event_broadcaster.enable_subscriber("test_conn_id") 387 event_broadcaster.chain_update(block, []) 388 389 event_list = events_pb2.EventList( 390 events=BlockEventExtractor(block).extract( 391 [create_block_commit_subscription()])).SerializeToString() 392 mock_service.send.assert_called_with( 393 validator_pb2.Message.CLIENT_EVENTS, 394 event_list, connection_id="test_conn_id", one_way=True) 395 396 397 class TpEventAddHandlerTest(unittest.TestCase): 398 def test_add_event(self): 399 event = events_pb2.Event(event_type="add_event") 400 mock_context_manager = Mock() 401 handler = TpEventAddHandler(mock_context_manager) 402 request = state_context_pb2.TpEventAddRequest( 403 event=event).SerializeToString() 404 405 response = handler.handle("test_conn_id", request) 406 407 self.assertEqual(HandlerStatus.RETURN, response.status)