"""Fixtures for lambda testing.""" import os import boto3 from botocore.exceptions import ClientError import textwrap from datetime import datetime import mysql.connector from py.xml import html import pytest from pytest_html.extras import url from utils.dockerized_lambda_api_client import DockerizedLambdaAPIClient from urllib.parse import urlparse QA_BASE_URL = os.environ.get( 'QA_BASE_URL', 'http://json-contract-file-import-lambda:8080' ) JIRA_PREFIX_URL = 'https://theorchard.atlassian.net/browse/' PYTEST_REPORT_PREFIX = 'json_contract_file_import lambda integration tests results' PYTEST_REPORT_SUMMARY = textwrap.dedent(""" Lambda for validating adjustment file content """).splitlines() def upload_file_to_s3(bucket_name, relative_file_path): """Upload a file to the root of an S3 bucket with a timestamp postfix.""" source_file_path = os.path.abspath(relative_file_path) if not os.path.exists(source_file_path): raise FileNotFoundError(f"Source file '{source_file_path}' not found.") timestamp = datetime.utcnow().strftime('%Y%m%d%H%M%S') file_name = os.path.basename(source_file_path) file_name_without_ext, file_extension = os.path.splitext(file_name) s3_key = f'{file_name_without_ext}_{timestamp}{file_extension}' s3_client = boto3.client('s3') try: print(f'Uploading file: {source_file_path} to s3://{bucket_name}/{s3_key}') s3_client.upload_file(source_file_path, bucket_name, s3_key) return s3_key except Exception as e: raise RuntimeError(f'Failed to upload file to S3: {str(e)}') def s3_url_exists(s3_url: str) -> bool: """Check if an S3 URL exists.""" parsed = urlparse(s3_url) bucket, key = parsed.netloc, parsed.path.lstrip('/') s3 = boto3.client('s3') try: s3.head_object(Bucket=bucket, Key=key) return True except ClientError as e: if e.response['Error']['Code'] in ('404', 'NoSuchKey'): return False raise def check_table_empty(table): """Check whether table is empty.""" cnx = mysql_connector() cursor = cnx.cursor() cursor.execute('SELECT * FROM {}'.format(table)) cursor.fetchall() rc = cursor.rowcount assert rc == 0 cursor.close() cnx.close() def check_table_not_empty(table): """Check whether table is empty.""" cnx = mysql_connector() cursor = cnx.cursor() cursor.execute('SELECT * FROM {}'.format(table)) cursor.fetchall() rc = cursor.rowcount assert rc > 0 cursor.close() cnx.close() def mysql_connector(): """Create docker_db connector.""" return mysql.connector.connect( host='json-contract-file-import-mysql', port='3306', database='royalty_accounting', user='db_user', password='db_pass' ) def get_db_field_value(table, column, condition): """Retrieve the value of the specified column from a table based on a condition.""" cnx = mysql_connector() cursor = cnx.cursor() query = 'SELECT {} FROM {} WHERE {}'.format(column, table, condition) cursor.execute(query) result = cursor.fetchone() if result is not None: value = result[0] else: value = None cursor.close() cnx.close() return value @pytest.fixture def clean_db(): """Clean tables between runs.""" tables = [ 'account', 'account_contract', 'account_payee', 'account_payment_term', 'account_tax_info', 'contract', 'contract_term', 'run_controller_contract' ] cnx = mysql_connector() cursor = cnx.cursor() try: cursor.execute('SET FOREIGN_KEY_CHECKS = 0;') for table in tables: cursor.execute(f'TRUNCATE TABLE `{table}`') cursor.execute('SET FOREIGN_KEY_CHECKS = 1;') cnx.commit() finally: cursor.close() cnx.close() def dockerized_lambda_api_client(headers): """Create json_contract_file_import dockerized lambda object.""" return DockerizedLambdaAPIClient(QA_BASE_URL, headers) @pytest.fixture(scope='session') def basic_headers(): """Return basic headers.""" return {'Content-Type': 'application/json'} @pytest.hookimpl(optionalhook=True) def pytest_html_results_summary(prefix, summary, postfix): """Populate report with info and summary.""" prefix.extend([html.p(PYTEST_REPORT_PREFIX)]) summary.extend([html.p(PYTEST_REPORT_SUMMARY)]) def pytest_html_results_table_header(cells): """Create results table header.""" cells.insert(1, html.th('Jira ID')) cells.insert(2, html.th('Description')) cells.pop() def pytest_html_results_table_row(report, cells): """Populate results table row.""" jira_ids = getattr(report, 'jira_ids', []) jira_links = [] for index, item in enumerate(jira_ids): link = url('{}{}'.format(JIRA_PREFIX_URL, item), item) if index == 0: jira_links.append(html.a(link['name'], href=link['content'])) else: jira_links.append(', ') jira_links.append(html.a(link['name'], href=link['content'])) jira_links_html = html.td(*jira_links) cells.insert(1, jira_links_html) cells.insert(2, html.td(report.description)) cells.pop() @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): """Populate results table.""" outcome = yield report = outcome.get_result() report.description = str(item.function.__doc__) if item.get_closest_marker('jira') is not None: to_populate = [] for item in item.get_closest_marker('jira').args: to_populate.append(item) report.jira_ids = to_populate else: report.jira_id = []