github.com/apache/beam/sdks/v2@v2.48.2/python/apache_beam/testing/pipeline_verifiers_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  """Unit tests for the test pipeline verifiers"""
    19  
    20  # pytype: skip-file
    21  
    22  import logging
    23  import os
    24  import tempfile
    25  import unittest
    26  
    27  from hamcrest import assert_that as hc_assert_that
    28  from mock import Mock
    29  from mock import patch
    30  
    31  from apache_beam.io.localfilesystem import LocalFileSystem
    32  from apache_beam.runners.runner import PipelineResult
    33  from apache_beam.runners.runner import PipelineState
    34  from apache_beam.testing import pipeline_verifiers as verifiers
    35  from apache_beam.testing.test_utils import patch_retry
    36  
    37  try:
    38    # pylint: disable=wrong-import-order, wrong-import-position
    39    # pylint: disable=ungrouped-imports
    40    from apitools.base.py.exceptions import HttpError
    41    from apache_beam.io.gcp.gcsfilesystem import GCSFileSystem
    42  except ImportError:
    43    HttpError = None
    44    GCSFileSystem = None  # type: ignore
    45  
    46  
    47  class PipelineVerifiersTest(unittest.TestCase):
    48    def setUp(self):
    49      self._mock_result = Mock()
    50      patch_retry(self, verifiers)
    51  
    52    def test_pipeline_state_matcher_success(self):
    53      """Test PipelineStateMatcher successes when using default expected state
    54      and job actually finished in DONE
    55      """
    56      pipeline_result = PipelineResult(PipelineState.DONE)
    57      hc_assert_that(pipeline_result, verifiers.PipelineStateMatcher())
    58  
    59    def test_pipeline_state_matcher_given_state(self):
    60      """Test PipelineStateMatcher successes when matches given state"""
    61      pipeline_result = PipelineResult(PipelineState.FAILED)
    62      hc_assert_that(
    63          pipeline_result, verifiers.PipelineStateMatcher(PipelineState.FAILED))
    64  
    65    def test_pipeline_state_matcher_fails(self):
    66      """Test PipelineStateMatcher fails when using default expected state
    67      and job actually finished in CANCELLED/DRAINED/FAILED/UNKNOWN
    68      """
    69      failed_state = [
    70          PipelineState.CANCELLED,
    71          PipelineState.DRAINED,
    72          PipelineState.FAILED,
    73          PipelineState.UNKNOWN
    74      ]
    75  
    76      for state in failed_state:
    77        pipeline_result = PipelineResult(state)
    78        with self.assertRaises(AssertionError):
    79          hc_assert_that(pipeline_result, verifiers.PipelineStateMatcher())
    80  
    81    test_cases = [
    82        {
    83            'content': 'Test FileChecksumMatcher with single file',
    84            'num_files': 1,
    85            'expected_checksum': 'ebe16840cc1d0b4fe1cf71743e9d772fa31683b8'
    86        },
    87        {
    88            'content': 'Test FileChecksumMatcher with multiple files',
    89            'num_files': 3,
    90            'expected_checksum': '58b3d3636de3891ac61afb8ace3b5025c3c37d44'
    91        },
    92        {
    93            'content': '',
    94            'num_files': 1,
    95            'expected_checksum': 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
    96        },
    97    ]
    98  
    99    def create_temp_file(self, content, directory=None):
   100      with tempfile.NamedTemporaryFile(delete=False, dir=directory) as f:
   101        f.write(content.encode('utf-8'))
   102        return f.name
   103  
   104    def test_file_checksum_matcher_success(self):
   105      for case in self.test_cases:
   106        temp_dir = tempfile.mkdtemp()
   107        for _ in range(case['num_files']):
   108          self.create_temp_file(case['content'], temp_dir)
   109        matcher = verifiers.FileChecksumMatcher(
   110            os.path.join(temp_dir, '*'), case['expected_checksum'])
   111        hc_assert_that(self._mock_result, matcher)
   112  
   113    @patch.object(LocalFileSystem, 'match')
   114    def test_file_checksum_matcher_read_failed(self, mock_match):
   115      mock_match.side_effect = IOError('No file found.')
   116      matcher = verifiers.FileChecksumMatcher(
   117          os.path.join('dummy', 'path'), Mock())
   118      with self.assertRaises(IOError):
   119        hc_assert_that(self._mock_result, matcher)
   120      self.assertTrue(mock_match.called)
   121      self.assertEqual(verifiers.MAX_RETRIES + 1, mock_match.call_count)
   122  
   123    @patch.object(GCSFileSystem, 'match')
   124    @unittest.skipIf(HttpError is None, 'google-apitools is not installed')
   125    def test_file_checksum_matcher_service_error(self, mock_match):
   126      mock_match.side_effect = HttpError(
   127          response={'status': '404'},
   128          url='',
   129          content='Not Found',
   130      )
   131      matcher = verifiers.FileChecksumMatcher('gs://dummy/path', Mock())
   132      with self.assertRaises(HttpError):
   133        hc_assert_that(self._mock_result, matcher)
   134      self.assertTrue(mock_match.called)
   135      self.assertEqual(verifiers.MAX_RETRIES + 1, mock_match.call_count)
   136  
   137    def test_file_checksum_matchcer_invalid_sleep_time(self):
   138      with self.assertRaises(ValueError) as cm:
   139        verifiers.FileChecksumMatcher(
   140            'file_path', 'expected_checksum', 'invalid_sleep_time')
   141      self.assertEqual(
   142          cm.exception.args[0],
   143          'Sleep seconds, if received, must be int. '
   144          'But received: \'invalid_sleep_time\', '
   145          '{}'.format(str))
   146  
   147    @patch('time.sleep', return_value=None)
   148    def test_file_checksum_matcher_sleep_before_verify(self, mocked_sleep):
   149      temp_dir = tempfile.mkdtemp()
   150      case = self.test_cases[0]
   151      self.create_temp_file(case['content'], temp_dir)
   152      matcher = verifiers.FileChecksumMatcher(
   153          os.path.join(temp_dir, '*'), case['expected_checksum'], 10)
   154      hc_assert_that(self._mock_result, matcher)
   155      self.assertTrue(mocked_sleep.called)
   156  
   157  
   158  if __name__ == '__main__':
   159    logging.getLogger().setLevel(logging.INFO)
   160    unittest.main()