github.com/apache/beam/sdks/v2@v2.48.2/python/apache_beam/testing/test_stream_service_test.py (about)

     1  #
     2  # Licensed to the Apache Software Foundation (ASF) under one or more
     3  # contributor license agreements.  See the NOTICE file distributed with
     4  # this work for additional information regarding copyright ownership.
     5  # The ASF licenses this file to You under the Apache License, Version 2.0
     6  # (the "License"); you may not use this file except in compliance with
     7  # the License.  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.
    16  #
    17  
    18  # pytype: skip-file
    19  
    20  import unittest
    21  from unittest.mock import patch
    22  
    23  import grpc
    24  
    25  from apache_beam.portability.api import beam_interactive_api_pb2
    26  from apache_beam.portability.api import beam_runner_api_pb2
    27  from apache_beam.portability.api import beam_runner_api_pb2_grpc
    28  from apache_beam.testing.test_stream_service import TestStreamServiceController
    29  
    30  # Nose automatically detects tests if they match a regex. Here, it mistakens
    31  # these protos as tests. For more info see the Nose docs at:
    32  # https://nose.readthedocs.io/en/latest/writing_tests.html
    33  beam_runner_api_pb2.TestStreamPayload.__test__ = False  # type: ignore[attr-defined]
    34  beam_interactive_api_pb2.TestStreamFileHeader.__test__ = False  # type: ignore[attr-defined]
    35  beam_interactive_api_pb2.TestStreamFileRecord.__test__ = False  # type: ignore[attr-defined]
    36  
    37  
    38  class EventsReader:
    39    def __init__(self, expected_key):
    40      self._expected_key = expected_key
    41  
    42    def read_multiple(self, keys):
    43      if keys != self._expected_key:
    44        raise ValueError(
    45            'Expected key ({}) is not argument({})'.format(
    46                self._expected_key, keys))
    47  
    48      for i in range(10):
    49        e = beam_runner_api_pb2.TestStreamPayload.Event()
    50        e.element_event.elements.append(
    51            beam_runner_api_pb2.TestStreamPayload.TimestampedElement(timestamp=i))
    52        yield e
    53  
    54  
    55  EXPECTED_KEY = 'key'
    56  EXPECTED_KEYS = [EXPECTED_KEY]
    57  
    58  
    59  class TestStreamServiceTest(unittest.TestCase):
    60    def setUp(self):
    61      self.controller = TestStreamServiceController(
    62          EventsReader(expected_key=[('full', EXPECTED_KEY)]))
    63      self.controller.start()
    64  
    65      channel = grpc.insecure_channel(self.controller.endpoint)
    66      self.stub = beam_runner_api_pb2_grpc.TestStreamServiceStub(channel)
    67  
    68    def tearDown(self):
    69      self.controller.stop()
    70  
    71    def test_normal_run(self):
    72      r = self.stub.Events(
    73          beam_runner_api_pb2.EventsRequest(output_ids=EXPECTED_KEYS))
    74      events = [e for e in r]
    75      expected_events = [
    76          e for e in EventsReader(
    77              expected_key=[EXPECTED_KEYS]).read_multiple([EXPECTED_KEYS])
    78      ]
    79  
    80      self.assertEqual(events, expected_events)
    81  
    82    def test_multiple_sessions(self):
    83      resp_a = self.stub.Events(
    84          beam_runner_api_pb2.EventsRequest(output_ids=EXPECTED_KEYS))
    85      resp_b = self.stub.Events(
    86          beam_runner_api_pb2.EventsRequest(output_ids=EXPECTED_KEYS))
    87  
    88      events_a = []
    89      events_b = []
    90  
    91      done = False
    92      while not done:
    93        a_is_done = False
    94        b_is_done = False
    95        try:
    96          events_a.append(next(resp_a))
    97        except StopIteration:
    98          a_is_done = True
    99  
   100        try:
   101          events_b.append(next(resp_b))
   102        except StopIteration:
   103          b_is_done = True
   104  
   105        done = a_is_done and b_is_done
   106  
   107      expected_events = [
   108          e for e in EventsReader(
   109              expected_key=[EXPECTED_KEYS]).read_multiple([EXPECTED_KEYS])
   110      ]
   111  
   112      self.assertEqual(events_a, expected_events)
   113      self.assertEqual(events_b, expected_events)
   114  
   115  
   116  class TestStreamServiceStartStopTest(unittest.TestCase):
   117  
   118    # Weak internal use needs to be explicitly imported.
   119    from grpc import _server
   120  
   121    def setUp(self):
   122      self.controller = TestStreamServiceController(
   123          EventsReader(expected_key=[('full', EXPECTED_KEY)]))
   124      self.assertFalse(self.controller._server_started)
   125      self.assertFalse(self.controller._server_stopped)
   126  
   127    def tearDown(self):
   128      self.controller.stop()
   129  
   130    def test_start_when_never_started(self):
   131      with patch.object(self._server._Server,
   132                        'start',
   133                        wraps=self.controller._server.start) as mock_start:
   134        self.controller.start()
   135        mock_start.assert_called_once()
   136        self.assertTrue(self.controller._server_started)
   137        self.assertFalse(self.controller._server_stopped)
   138  
   139    def test_start_noop_when_already_started(self):
   140      with patch.object(self._server._Server,
   141                        'start',
   142                        wraps=self.controller._server.start) as mock_start:
   143        self.controller.start()
   144        mock_start.assert_called_once()
   145        self.controller.start()
   146        mock_start.assert_called_once()
   147  
   148    def test_start_noop_when_already_stopped(self):
   149      with patch.object(self._server._Server,
   150                        'start',
   151                        wraps=self.controller._server.start) as mock_start:
   152        self.controller.start()
   153        self.controller.stop()
   154        mock_start.assert_called_once()
   155        self.controller.start()
   156        mock_start.assert_called_once()
   157  
   158    def test_stop_noop_when_not_started(self):
   159      with patch.object(self._server._Server,
   160                        'stop',
   161                        wraps=self.controller._server.stop) as mock_stop:
   162        self.controller.stop()
   163        mock_stop.assert_not_called()
   164  
   165    def test_stop_when_already_started(self):
   166      with patch.object(self._server._Server,
   167                        'stop',
   168                        wraps=self.controller._server.stop) as mock_stop:
   169        self.controller.start()
   170        mock_stop.assert_not_called()
   171        self.controller.stop()
   172        mock_stop.assert_called_once()
   173        self.assertFalse(self.controller._server_started)
   174        self.assertTrue(self.controller._server_stopped)
   175  
   176    def test_stop_noop_when_already_stopped(self):
   177      with patch.object(self._server._Server,
   178                        'stop',
   179                        wraps=self.controller._server.stop) as mock_stop:
   180        self.controller.start()
   181        self.controller.stop()
   182        mock_stop.assert_called_once()
   183        self.controller.stop()
   184        mock_stop.assert_called_once()
   185  
   186  
   187  if __name__ == '__main__':
   188    unittest.main()