"""Test acr cloud service.""" from unittest import mock import pytest import requests from requests.exceptions import ConnectionError from requests.exceptions import HTTPError from src.services.acr_cloud import ACRCloudClient from src.services.acr_cloud import TooLargeFingerprint from src.services.acr_cloud import TooSmallFingerprint from src.services.acr_cloud import UnableToFingerprint from src.services.acr_cloud import UnableToRegister from src.common.exceptions import exceptions @pytest.mark.parametrize( ('filename'), [ ('my_song_1.mp3'), ('my_song_2.mp3'), ('my_song_2.wav') ] ) def test_create_fingerprint(filename): """Test create fingerprint operation.""" # test files provided from ACRCloud # https://docs.acrcloud.com/tutorials/recognize-custom-content-offline fixture_dir = './tests/fixtures' file_bytes = open(f'{fixture_dir}/{filename}', 'rb').read() client = ACRCloudClient(None, None) fingerprint = client._create_fingerprint(file_bytes) fingerprint_bytes = open(f'{fixture_dir}/{filename}.txt', 'rb').read() # noqa:E501 assert fingerprint == fingerprint_bytes @pytest.mark.parametrize( ('fingerprint', 'max_size', 'expected_exception'), [ (b'123', -1, None), (b'123', 2, TooLargeFingerprint), (b'', -1, TooSmallFingerprint), (None, -1, UnableToFingerprint) ] ) @mock.patch('src.services.acr_cloud.create_fingerprint_by_filebuffer') def test_handle_create_fingerprint_errors( mock_generate, fingerprint, max_size, expected_exception): """Test exceptions based on generated fingerprint.""" music = b'music' mock_generate.return_value = fingerprint client = ACRCloudClient( 'acr-creds', 'test-url.theorchard.io', max_fingerprint_size=max_size) if expected_exception: with pytest.raises(expected_exception): client._create_fingerprint(music) else: result = client._create_fingerprint(music) assert result == fingerprint @mock.patch('requests.request') def test_upload_fingerprint_new(mock_request): """Test response when fingerprint does not exist.""" client = ACRCloudClient('acr-creds', 'test-url.theorchard.io') client._create_fingerprint = lambda x: b'fingerprint' mock_response = mock_request.return_value mock_response.json.return_value = { 'data': { 'acr_id': 'acr-id-123', 'bucket_id': '999', 'do_db': True, 'dup_files': [], 'file_id': '123' } } response = client.upload_fingerprint(999, '123', b'music') assert mock_request.called assert mock_request.call_args_list == [ mock.call( 'POST', 'test-url.theorchard.io/buckets/999/dedup-files', headers={ 'Accept': 'application/json', 'Authorization': 'Bearer acr-creds' }, params={}, data={ 'partner': 'orchard', 'id': '123', 'db_id_nodup': 1 }, files=[('file', b'fingerprint')] ) ] assert response == 'acr-id-123' @mock.patch('requests.request') def test_upload_fingerprint_existing(mock_request): """Test response when fingerprint exists.""" client = ACRCloudClient('acr-creds', 'test-url.theorchard.io') client._create_fingerprint = lambda x: b'fingerprint' mock_response = mock_request.return_value mock_response.json.return_value = { 'data': { 'acr_id': 'acr-id-123', 'bucket_id': '999', 'do_db': False, 'dup_files': ['123'], 'file_id': '456' } } response = client.upload_fingerprint(999, '123', b'music') assert mock_request.called assert response == 'acr-id-123' @pytest.mark.parametrize( ('http_code', 'expected_exception'), [ (500, exceptions.RetryableException), (502, exceptions.RetryableException), (504, exceptions.RetryableException), (429, exceptions.RetryableException), (503, requests.exceptions.HTTPError) ] ) @mock.patch('requests.request') def test_upload_fingerprint_http_exceptions(mock_request, http_code, expected_exception): # noqa:E501 """Test http exceptions on upload.""" client = ACRCloudClient('acr-creds', 'test-url.theorchard.io') client._create_fingerprint = lambda x: b'fingerprint' mock_response = mock.Mock() mock_response.status_code = http_code mock_response.raise_for_status.side_effect = HTTPError( response=mock_response) mock_request.return_value = mock_response with pytest.raises(expected_exception): client.upload_fingerprint(999, '123', b'music') assert mock_request.called @pytest.mark.parametrize( ('exception', 'expected_message'), [ (ConnectionError, 'Connection Error from ACRCloudClient') ] ) @mock.patch('requests.request') def test_upload_fingerprint_non_http_exceptions(mock_request, exception, expected_message): # noqa:E501 """Test non-http retryable exceptions.""" client = ACRCloudClient('acr-creds', 'test-url.theorchard.io') client._create_fingerprint = lambda x: b'fingerprint' mock_request.side_effect = exception with pytest.raises(exceptions.RetryableException) as e: client.upload_fingerprint(999, '123', b'music') assert mock_request.called assert str(e.value) == expected_message @mock.patch('requests.request') def test_upload_fingerprint_body_error(mock_request): """Test error in response body.""" client = ACRCloudClient('acr-creds', 'test-url.theorchard.io') client._create_fingerprint = lambda x: b'fingerprint' mock_response = mock_request.return_value mock_response.json.return_value = { 'data': { 'error': 'Invalid fingerprint' } } with pytest.raises(UnableToRegister) as e: client.upload_fingerprint(999, '123', b'music') assert str(e.value) == 'Invalid fingerprint'