class TestCreateUDFs(unittest.TestCase):
    """
    This class uses the parameterized python package
    (https://pypi.org/project/parameterized/) to programmatically
    create multiple python test function definitions
    (based off `test_create_udf`). It will effectively create a python test
    function for each UDF that it encounters as it walks
    through the udfs/ directory.
    """
    @classmethod
    def setUpClass(cls):
        cls._client = bigquery.Client(project=os.getenv('BQ_PROJECT_ID'))

    @parameterized.expand(utils.get_all_udf_paths())
    def test_create_udf(self, udf_path):
        try:
            with open(udf_path) as udf_file:
                udf_sql = udf_file.read()
            # Only replace UDF datasets with a test dataset if the
            # build was triggered by a pull request or a non-main branch
            if (os.getenv('_PR_NUMBER') is not None
                    or os.getenv('BRANCH_NAME') != 'master'):
                udf_sql = utils.replace_with_test_datasets(
                    self._client.project, udf_sql)
                if udf_sql is None:
                    self.fail(
                        f'Unable to replace SQL DDL with testing dataset '
                        f'for UDF: {udf_path}')
            udf_creation_result = self._client.query(udf_sql).result()

            self.assertIsInstance(udf_creation_result, _EmptyRowIterator)
        except GoogleAPICallError as error:
            self.fail(error.message)
class CreateUDFSignatures(unittest.TestCase):
    """
    This class uses the parameterized python package
    (https://pypi.org/project/parameterized/) to programmatically
    create multiple python test function definitions
    (based off `test_create_udf_signature`). It will effectively create a python
    test function for each UDF that it encounters as it walks through
    the udfs/ directory.

    This class creates all UDFs with NULL bodies in order to prevent errors when
    subsequently creating all UDFs concurrently in the TestCreateUDFs class.
    Some UDFs may invoke other UDFs within their body and therefore have a
    dependency on them which could lead to errors upon creation:
    (e.g. one UDF might not have been created yet but is needed by another UDF
     currently being created)
    """
    @classmethod
    def setUpClass(cls):
        cls._client = bigquery.Client(project=os.getenv('BQ_PROJECT_ID'))

    @parameterized.expand(utils.get_all_udf_paths())
    def test_create_udf_signature(self, udf_path):
        client = self._client
        udf_signature = utils.replace_with_null_body(udf_path)
        udf_signature = utils.replace_with_test_datasets(
            client.project, udf_signature)
        try:
            udf_creation_result = client.query(udf_signature).result()
            self.assertIsInstance(udf_creation_result, _EmptyRowIterator)
        except GoogleAPICallError as error:
            self.fail(error.message)
class TestCreateUDFs(unittest.TestCase):
    """
    This class uses the parameterized python package (https://pypi.org/project/parameterized/) to programmatically
    create multiple python test function definitions (based off `test_create_udf`). It will effectively create a
    python test function for each UDF that it encounters as it walks through the udfs/ directory.
    """
    @classmethod
    def setUpClass(cls):
        cls._client = bigquery.Client()

    @parameterized.expand(utils.get_all_udf_paths())
    def test_create_udf(self, udf_path):
        client = self._client
        bq_test_dataset = utils.get_target_bq_dataset(udf_path)

        job_config = QueryJobConfig()
        job_config.default_dataset = (f'{client.project}.{bq_test_dataset}')
        try:
            udf_sql = utils.replace_with_test_datasets(udf_path,
                                                       client.project)
            udf_creation_result = client.query(udf_sql,
                                               job_config=job_config).result()
            self.assertIsInstance(udf_creation_result, _EmptyRowIterator)
        except GoogleAPICallError as e:
            self.fail(e.message)
Ejemplo n.º 4
0
class TestRunUDFs(unittest.TestCase):
    """
    This class uses the parameterized python package
    (https://pypi.org/project/parameterized/) to programmatically
    create multiple python test function definitions
    (based off `test_run_udf_and_verify_expected_result`).
    It will effectively create a python test function for each UDF that it
    encounters as it walks through the udfs/ directory. This class tests
    each UDF by running it in BigQuery with the inputs given in the
    test_cases.yaml file, and then asserting that the results equal the expected
    outputs given in the test_cases.yaml file.
    """
    @classmethod
    def setUpClass(cls):
        cls._client = bigquery.Client(project=os.getenv('BQ_PROJECT_ID'))

    @parameterized.expand(utils.get_all_udf_paths())
    def test_run_udf_and_verify_expected_result(self, udf_path):
        bq_test_dataset = utils.get_test_bq_dataset(udf_path)
        if bq_test_dataset is None:
            self.fail(f'Unable to retrieve test dataset name for UDF:'
                      f' {udf_path}')
        file_name = Path(udf_path).stem
        udf_name = utils.extract_udf_name(udf_path)
        self.assertEqual(
            udf_name,
            file_name,
            msg=(f'\nFile name: {udf_path}'
                 f'\nshould match the function name defined inside: {udf_name}'
                 ))
        test_cases = utils.load_test_cases(udf_path, udf_name)
        if test_cases is None:
            self.skipTest(
                f'Test inputs and outputs are not provided for : {udf_path}')
        for case in test_cases:
            try:
                actual_result_rows = self._client.query(
                    f'SELECT `{bq_test_dataset}.{udf_name}`('
                    f' {case["input"]} ) AS actual_result_rows').result()

                expected_result_rows = self._client.query(
                    f'SELECT ( {case["expected_output"]} ) '
                    f'AS expected_result_rows').result()

                for expected_result_row, actual_result_row in zip(
                        expected_result_rows, actual_result_rows):
                    self.assertSequenceEqual(
                        expected_result_row.values(),
                        actual_result_row.values(),
                        msg=
                        (f'\nTest failed for: '
                         f'{self._client.project}.{bq_test_dataset}.{udf_name}'
                         f'( {case["input"]} )'
                         f'\nExpected output: {expected_result_row.values()}'
                         f'\nActual output: {actual_result_row.values()}'))

            except GoogleAPICallError as error:
                self.fail(error.message)
class CreateUDFSignatures(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._client = bigquery.Client()

    @parameterized.expand(utils.get_all_udf_paths())
    def test_create_udf_signature(self, udf_path):
        client = self._client
        bq_test_dataset = utils.get_target_bq_dataset(udf_path)

        job_config = QueryJobConfig()
        job_config.default_dataset = (f'{client.project}.{bq_test_dataset}')
        udf_signature = utils.extract_udf_signature(udf_path)
        udf_sql = utils.replace_with_test_datasets(
            project_id=client.project,
            udf_sql=f'CREATE OR REPLACE FUNCTION {udf_signature} AS (NULL)')
        try:
            udf_creation_result = client.query(udf_sql,
                                               job_config=job_config).result()
            self.assertIsInstance(udf_creation_result, _EmptyRowIterator)
        except GoogleAPICallError as e:
            self.fail(e.message)