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)