"""Tests for validation module.""" import json from typing import Any from unittest import mock import pytest from flask import Request, Response from werkzeug.datastructures import ImmutableMultiDict from assets.constants import error, field_const from assets.validation import json_schema from assets.validation.schema import query @pytest.fixture def required_params() -> list[str]: """Function that returns list of required arguments for tested schema. Returns: list: required arguments for tested schema """ return ["string_value", "number_value"] @pytest.fixture def tested_schema(required_params: list[str]) -> dict[str, Any]: """Function that returns json-schema for test validation. Returns: dict: schema dict. """ return { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Schema for query validation testing", "type": "object", "properties": { required_params[0]: {"type": "string"}, required_params[1]: {"type": "number"}, }, "required": ["string_value", "number_value"], "additionalProperties": False, } def fixture_function(request: Request, schema: dict[str, Any]) -> Response: """Function to mock real endpoint handler.""" @json_schema.validate_query(request, schema) def function() -> Response: return Response("test_result") return function() @pytest.fixture def generate_query_params(required_params: list[str]) -> ImmutableMultiDict[str, Any]: """Function that returns valid query params. Returns: ImmutableMultiDict: dictionary of query key-values """ query_params = {required_params[0]: "string", required_params[1]: 10} return ImmutableMultiDict(query_params) def test_validate_query_success( generate_query_params: ImmutableMultiDict[str, Any], tested_schema: dict[str, Any] ) -> None: """Assert that validate_query succeeds when query is valid.""" request = mock.Mock() request.args = generate_query_params assert "test_result" == fixture_function(request, tested_schema).data.decode() @pytest.mark.parametrize("missing_param", ["string_value", "number_value"]) def test_post_validate_query_missing_params_fail( missing_param: str, generate_query_params: ImmutableMultiDict[str, Any], tested_schema: dict[str, Any], ) -> None: """Assert that validate_query fails when params is missing.""" request = mock.Mock() current_args = generate_query_params.to_dict() del current_args[missing_param] request.args = ImmutableMultiDict(current_args) response = fixture_function(request, tested_schema) assert response.status_code == 400 response_json = json.loads(response.data.decode()) assert response_json["code"] == error.ERROR_CODE_QUERY_VALIDATION def test_validate_extra_params_fail( tested_schema: dict[str, Any], generate_query_params: ImmutableMultiDict[str, Any] ) -> None: """Assert that validate_query fails unknown field.""" request = mock.Mock() current_args = generate_query_params.to_dict() current_args["extra_field"] = "some_string" request.args = ImmutableMultiDict(current_args) response = fixture_function(request, tested_schema) assert response.status_code == 400 response_json = json.loads(response.data.decode()) assert response_json["code"] == error.ERROR_CODE_QUERY_VALIDATION @pytest.mark.parametrize( "args", [ {"string_value": 1, "number_value": 2}, {"string_value": "str", "number_value": "FF"}, ], ) def test_validate_query_invalid_types_field_fail( args: dict[str, Any], tested_schema: dict[str, Any] ) -> None: """Assert that validate_query fails when params types don't match.""" request = mock.Mock() request.args = ImmutableMultiDict(args) response = fixture_function(request, tested_schema) assert response.status_code == 400 response_json = json.loads(response.data.decode()) assert response_json["code"] == error.ERROR_CODE_QUERY_VALIDATION @pytest.mark.parametrize( "args", [ {field_const.FILENAME: "test_file.mp3"}, {field_const.FILENAMES: "test_file1.mp3,test_file2.mp3"}, ], ) def test_get_assets_status_validate_query_success(args: dict[str, str]) -> None: """Assert that validate_query succeeds when query is valid.""" request = mock.Mock() request.args = ImmutableMultiDict(args) assert ( "test_result" == fixture_function(request, query.get_assets_status_schema).data.decode() ) def test_get_assets_status_validate_query_fail() -> None: """Assert that validate_query fails when query is invalid.""" request = mock.Mock() request.args = ImmutableMultiDict({"invalid_key": "test_file.mp3"}) response = fixture_function(request, query.get_assets_status_schema) assert response.status_code == 400 response_json = json.loads(response.data.decode()) assert response_json["code"] == error.ERROR_CODE_QUERY_VALIDATION @pytest.fixture def fixture_correct_get_asset_info_query() -> dict[str, str]: """Return args for correct get_asset_info query.""" return { field_const.FILENAME: "unique_filename.ext", field_const.STATE: field_const.ASSET_STATE_RAW, } def test_get_asset_info_validate_query_success( fixture_correct_get_asset_info_query: dict[str, str], ) -> None: """Assert that validate_query succeeds when query is valid.""" request = mock.Mock() request.args = ImmutableMultiDict(fixture_correct_get_asset_info_query) assert ( "test_result" == fixture_function(request, query.get_asset_info_schema).data.decode() ) @pytest.mark.parametrize("missing_field", [field_const.FILENAME, field_const.STATE]) def test_get_asset_info_validate_query_missing_field_failure( fixture_correct_get_asset_info_query: dict[str, str], missing_field: str ) -> None: """Assert that validate_query fails when arg is missing.""" request = mock.Mock() del fixture_correct_get_asset_info_query[missing_field] request.args = ImmutableMultiDict(fixture_correct_get_asset_info_query) response = fixture_function(request, query.get_asset_info_schema) assert response.status_code == 400 response_json = json.loads(response.data.decode()) assert response_json["code"] == error.ERROR_CODE_QUERY_VALIDATION def test_get_asset_info_validate_query_wrong_state( fixture_correct_get_asset_info_query: dict[str, str], ) -> None: """Assert that validate_query fails when state is wrong.""" request = mock.Mock() fixture_correct_get_asset_info_query[field_const.STATE] = "wrong" request.args = ImmutableMultiDict(fixture_correct_get_asset_info_query) response = fixture_function(request, query.get_asset_info_schema) assert response.status_code == 400 response_json = json.loads(response.data.decode()) assert response_json["code"] == error.ERROR_CODE_QUERY_VALIDATION