"""Provides general test helper functions.""" import random import time from typing import Any, Callable import requests from tests.testutils.api_client.product_digital_api_client import ( ProductDigitalAPIClient, ) from tests.testutils.api_client.track_api_client import TrackAPIClient from tests.testutils.file_helper.file_helper import FileType from tests.testutils.mysql.query_helper import QueryHelper class TestHelper: """Provides general test helper functions.""" @staticmethod def _track_data(product_id: int) -> dict[str, Any]: """Return a dictionary of track data.""" return { "product_id": product_id, "track_name": "assets_test_track_{}".format(time.time()), } @staticmethod # TODO: remove once full migration to v2 is done and v1 is not needed anymore def post_asset_v1_dict( asset_type: str, product_id: int, upc: str, tuid: int | None, original_filename: str, token_filename: str, token: str, is_correction: bool = False, ) -> dict[str, Any]: """Build POST /asset (v1) dictionary.""" return { "asset_type": asset_type, "product_id": product_id, "upc": upc, "track_unique_id": 0 if tuid is None else tuid, "original_filename": original_filename, "filename": token_filename, "is_correction": is_correction, "token": token, } @staticmethod def create_track_if_audio( workstation_track_api_client: TrackAPIClient, file_type: FileType, product_id: int, ) -> int | None: """Create a new track is file type is audio.""" if file_type != FileType.AUDIO: return None count = 0 # retry because ows-track can be unresponsive at times. while True: track_response = workstation_track_api_client.create_track( TestHelper._track_data(product_id) ) try: assert track_response.status_code == 201, ( "Result of POST was {}, expected 201.".format( track_response.status_code ) ) return int(track_response.json()["tuid"]) except AssertionError: count += 1 if count > 4: raise AssertionError("Failed after 4 attempts.") from None time.sleep(random.uniform(0.1, 0.4)) @staticmethod def assets_query(filename: str, file_type: str) -> dict[str, Any]: """Build a dictionary for querying assets endpoint.""" return {"filename": filename, "state": file_type} @staticmethod def assert_with_timeout( call: Callable[..., Any], call_args: Any, assertions: Callable[..., Any], interval: int = 1, timeout: int = 300, additional_assert_args: Any | None = None, ) -> Any: """Continue to assert expectation until condition is met or timeout is met/exceeded.""" assertions_met = False timer = 0 assertion_error = None while not assertions_met: if timer >= timeout: raise AssertionError( "Exceeded timeout of {}, assertion failed was {}".format( timeout, assertion_error ) ) result_of_call = call(call_args) assertion_error = None try: if additional_assert_args: assertions(result_of_call, additional_assert_args) else: assertions(result_of_call) except AssertionError as ae: assertion_error = ae if not assertion_error: assertions_met = True else: timer += interval time.sleep(interval) return result_of_call @staticmethod def create_product( workstation_product_digital_api_client: ProductDigitalAPIClient, product_data: dict[str, Any], ) -> dict[str, Any]: """Create a new product and check response.""" count = 0 # retry until UPC deadlock issue in product-digital is fixed. while True: product_response = workstation_product_digital_api_client.create_product( product_data ) try: assert product_response.status_code == 201, ( "Result of POST was {}, expected 201.".format( product_response.status_code ) ) break except AssertionError: count += 1 if count > 4: raise AssertionError("Failed after 4 attempts.") from None time.sleep(random.uniform(0.1, 0.4)) # If our new product has ID references in ows_assets RDS database, clear out all associated records. product_json: dict[str, Any] = product_response.json() QueryHelper.delete_asset_records(product_id=product_json["product_id"]) return product_json @staticmethod def expect_completely_encoded_asset( response: requests.Response, filename: str ) -> None: """Assert that an asset has completed encoded.""" assert response.status_code == 200, ( "Result of GET was {}, expected 200.".format(response.status_code) ) response_content = response.json() assert response_content["asset_upload_id"], ( "Expected asset_upload_id to not be null." ) assert response_content["status_time"], "Expected status_time to not be null." assert response_content["status"] == "encoding_completed", ( 'Status was {}, expected "encoding_completed".'.format( response_content["status"] ) ) message_content = response_content["message"] assert filename in message_content["input"]["key"], ( "Expected response message to include filename of {}, got {}.".format( filename, message_content["input"]["key"] ) ) assert "completed" in message_content["status"].lower(), ( "Expected completed to be present in message status, got {}".format( message_content["status"].lower() ) ) try: assert message_content["result_assets"], ( "Expected result_assets to not be null." ) except KeyError: raise AssertionError( "Got a KeyError looking for result_assets in message." ) from None