import contextlib import dataclasses import typing as t from contextlib import contextmanager import pytest from slz_apple_music_charts_scrapper.entities import ( APIResponseMixin, Config, Track, TrackArtistAttributes, TrackArtwork, TrackEditorialNotes, TrackPlayParams, TrackPreview, ) from tests.entities import ConfigData @pytest.mark.parametrize( 'test_input, expected', [ ( ConfigData('auth_client_id', 'auth_client_secret', None), ConfigData('**************', '******************', None), ), ( ConfigData('auth_client_id', 'auth_client_secret', 'sentry_secret_key'), ConfigData('**************', '******************', '*****************'), ), ( ConfigData('123', '1234', '12345'), ConfigData('***', '****', '*****'), ), ] ) def test_config_as_safe_dict(test_input: ConfigData, expected: ConfigData): config = Config( auth_client_id=test_input.auth_client_id, auth_client_secret=test_input.auth_client_secret, auth_audience='auth_audience', auth_token_url='auth_token_url', vendor_api_host='vendor_api_host', config_bucket='config_bucket', decompressed_bucket='decompressed_bucket', quarantine_bucket='quarantine_bucket', corrupted_bucket='corrupted_bucket', rds_secret_key='rds_secret_key', sentry_secret_key=test_input.sentry_secret_key, aws_region='aws_region', aws_sfn_task_token='aws_sfn_task_token', aws_batch_job_id='aws_batch_job_id', ) config_safe_dict = config.as_safe_dict() assert config_safe_dict['auth_client_id'] == expected.auth_client_id assert config_safe_dict['auth_client_secret'] == expected.auth_client_secret if expected.sentry_secret_key is not None: assert config_safe_dict['sentry_secret_key'] == expected.sentry_secret_key else: assert config_safe_dict['sentry_secret_key'] is expected.sentry_secret_key @pytest.mark.parametrize( 'entity,expected', [ ( TrackArtistAttributes(), { 'genre_names': ['NA'], 'name': 'NA', 'url': 'NA', 'editorial_notes': { 'name': 'NA', 'short': 'NA', 'standard': 'NA', 'tagline': 'NA' }, }, ), ( TrackArtistAttributes(genre_names=['Rock'], editorial_notes={'name': 'some'}), { 'genre_names': ['Rock'], 'name': 'NA', 'url': 'NA', 'editorial_notes': { 'name': 'some', 'short': 'NA', 'standard': 'NA', 'tagline': 'NA' }, }, ), ] ) def test_track_arttist_attributes_missing_values_fallback(entity, expected): assert entity.as_dict() == expected @pytest.mark.parametrize( 'entity,expected', [ ( TrackArtwork(), { 'bg_color': 'NA', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, ), ( TrackArtwork(bg_color='#FFF'), { 'bg_color': '#FFF', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, ), ] ) def test_track_artwork_missing_values_fallback(entity, expected): assert entity.as_dict() == expected @pytest.mark.parametrize( 'entity,expected', [ ( TrackPreview(), { 'artwork': { 'bg_color': 'NA', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'hls_url': 'NA', 'url': 'NA', }, ), ( TrackPreview(hls_url='https://apple.com/something/'), { 'artwork': { 'bg_color': 'NA', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'hls_url': 'https://apple.com/something/', 'url': 'NA', }, ), ( TrackPreview(artwork={'bg_color': '#FFFFFF'}), { 'artwork': { 'bg_color': '#FFFFFF', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'hls_url': 'NA', 'url': 'NA', }, ), ] ) def test_track_preview_missing_values_fallback(entity, expected): assert entity.as_dict() == expected @pytest.mark.parametrize( 'entity, expected', [( TrackPlayParams(), { 'id': 'NA', 'kind': 'NA' }, ), ( TrackPlayParams(id='some_id'), { 'id': 'some_id', 'kind': 'NA' }, )] ) def test_track_play_params_missing_values_fallback( entity: TrackPlayParams, expected: t.Dict[str, t.Any] ): assert entity.as_dict() == expected @pytest.mark.parametrize( 'entity, expected', [ ( TrackEditorialNotes(), { 'short': 'NA', 'standard': 'NA', 'name': 'NA', 'tagline': 'NA' }, ), ( TrackEditorialNotes(short='blah'), { 'short': 'blah', 'standard': 'NA', 'name': 'NA', 'tagline': 'NA' }, ), ] ) def test_track_editorial_notes_missing_values_fallback( entity: TrackEditorialNotes, expected: t.Dict[str, t.Any] ): assert entity.as_dict() == expected @pytest.mark.parametrize( 'entity, expected', [ ( Track( id='pl.606afcbb70264d2eb2b51d8dbcfa6a12', position=1, report_date='2021-12-24', timestamp='timestamp', country='de', ), { 'album_name': 'NA', 'artist_name': 'NA', 'artist_url': 'NA', 'artwork': { 'bg_color': 'NA', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'composer_name': 'NA', 'content_rating': 'NA', 'country': 'de', 'disc_number': 'NA', 'duration_in_millis': 'NA', 'genre_names': ['NA'], 'has_lyrics': 'NA', 'id': 'pl.606afcbb70264d2eb2b51d8dbcfa6a12', 'isrc': 'NA', 'movement_count': None, 'movement_name': None, 'movement_number': None, 'name': 'NA', 'play_params': { 'id': 'NA', 'kind': 'NA', }, 'position': 1, 'previews': [], 'release_date': 'NA', 'report_date': '2021-12-24', 'timestamp': 'timestamp', 'track_number': 'NA', 'url': 'NA', 'work_name': 'NA', 'editorial_notes': { 'short': 'NA', 'standard': 'NA', 'name': 'NA', 'tagline': 'NA', }, 'attribution': 'NA', }, ), ( Track( id='pl.606afcbb70264d2eb2b51d8dbcfa6a12', position=1, report_date='2021-12-24', timestamp='timestamp', country='de', previews=[ { 'artwork': { 'height': 123, } }, { 'artwork': { 'width': 321, } }, ], play_params={'kind': 'awesome'}, artwork={'bg_color': 'bloody'}, editorial_notes={'short': 'blah'}, ), { 'album_name': 'NA', 'artist_name': 'NA', 'artist_url': 'NA', 'artwork': { 'bg_color': 'bloody', 'height': 'NA', 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'composer_name': 'NA', 'content_rating': 'NA', 'country': 'de', 'disc_number': 'NA', 'duration_in_millis': 'NA', 'genre_names': ['NA'], 'has_lyrics': 'NA', 'id': 'pl.606afcbb70264d2eb2b51d8dbcfa6a12', 'isrc': 'NA', 'movement_count': None, 'movement_name': None, 'movement_number': None, 'name': 'NA', 'play_params': { 'id': 'NA', 'kind': 'awesome' }, 'position': 1, 'previews': [{ 'artwork': { 'bg_color': 'NA', 'height': 123, 'url': 'NA', 'width': 'NA', 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'hls_url': 'NA', 'url': 'NA', }, { 'artwork': { 'bg_color': 'NA', 'height': 'NA', 'url': 'NA', 'width': 321, 'text_color1': 'NA', 'text_color2': 'NA', 'text_color3': 'NA', 'text_color4': 'NA', }, 'hls_url': 'NA', 'url': 'NA', }], 'release_date': 'NA', 'report_date': '2021-12-24', 'timestamp': 'timestamp', 'track_number': 'NA', 'url': 'NA', 'work_name': 'NA', 'editorial_notes': { 'short': 'blah', 'standard': 'NA', 'name': 'NA', 'tagline': 'NA', }, 'attribution': 'NA', }, ), ] ) def test_track_missing_values_fallback(entity: Track, expected: t.Dict[str, t.Any]): assert entity.as_dict() == expected @dataclasses.dataclass class TestEntity(APIResponseMixin): field1: str field2: int def test_api_response_fields(): item = TestEntity(field1='hello', field2=2) assert item.fields() == set(['field1', 'field2']) @pytest.mark.parametrize( 'args,ignore_unknown,expected', [( { 'field1': 'hello', 'field2': 2, 'field3': 'world', }, False, pytest.raises(TypeError), ), ( { 'field1': 'hello', 'field2': 2, 'field3': 'world', }, True, contextlib.nullcontext(), )] ) def test_api_response_from_dict( args: t.Dict[str, t.Any], ignore_unknown: bool, expected: contextmanager ): with expected: TestEntity.from_dict(args, ignore_unknown=ignore_unknown)