"""Functional tests for POST get_tracks_ids_by_product_ids handler.""" import json from typing import Any, Dict, List, Optional from tests.testutils import db DATABASE_PRODUCT_IDS = [1, 5] ENDPOINT = '/products/trackids' class TrackMock: """Mock for Track class.""" def __init__( self, product_id: int, tuid: int, volume_number: int, track_number: int, p_info: str, ) -> None: """Initialize TrackMock attributes.""" self.product_id = product_id self.tuid = tuid self.volume_number = volume_number self.track_number = track_number self.p_info = p_info def columns_values_to_dict(self, fields: List[str]) -> Dict[str, Any]: """Copy original Track.columns_values_to_dict behaviour.""" return {field: getattr(self, field) for field in fields} class TracksMock: """Mock for batch of TrackMock objects.""" def __init__(self, tracks: List[TrackMock]) -> None: """Create object for given tracks batch. Args: tracks: tracks for the object control. """ self.tracks = tracks def get_tracks_for_product_ids( self, product_ids: List[int], ) -> List[TrackMock]: """Get all tracks for given product IDs. Args: product_ids: list of product IDs Returns: list of filtered TrackMock objects. """ products = set(product_ids) return list( filter( lambda t: t.product_id in products, self.tracks, ), ) @staticmethod def selected_columns_to_dict( tracks: List[TrackMock], selected_columns: List[str], ) -> List[Dict[str, Any]]: """Convert given tracks objects to dicts with given columns. Args: tracks: list of TrackMock objects to convert. selected_columns: list of needed columns. Returns: list of dicts created from input TrackMock objects, saving sorting orders in tracks and selected_columns. """ return list( map( lambda tr: tr.columns_values_to_dict( fields=selected_columns, ), tracks, ), ) @classmethod def prepare_endpoint_response( cls, tracks: List[TrackMock], target_columns: List[str], order_by_columns: List[str], selected_product_ids: List[int], ) -> List[Optional[Dict[str, List[Dict[str, Any]]]]]: """Prepare the endpoint expected response. Args: tracks: tracks to be returned. target_columns: list of returned tracks columns. order_by_columns: list of columns for results sorting. selected_product_ids: product IDs for the result tracks. Returns: List of response-formatted tracks, saving ordering given in: target_columns, order_by_columns, selected_product_ids. """ resp: List[Dict[str, List[Dict[str, Any]]]] = [] for product_id in selected_product_ids: product_tracks: List[TrackMock] = list( filter(lambda t: t.product_id == product_id, tracks) ) sorted_product_tracks: List[TrackMock] = sorted( product_tracks, key=lambda tr: tuple( map( lambda order_column: getattr(tr, order_column), order_by_columns, ) ), ) resp.append( { 'tracks': cls.selected_columns_to_dict( tracks=sorted_product_tracks, selected_columns=target_columns, ) } ) return resp def get_prepared_tracks() -> TracksMock: """Get TracksMock object for used TrackMock ones. Returns: TracksMock object with TrackMock ones for all test cases. """ return TracksMock( tracks=[ TrackMock( product_id=1, tuid=274, volume_number=1, track_number=6, p_info='F', ), TrackMock( product_id=1, tuid=311, volume_number=2, track_number=5, p_info='E', ), TrackMock( product_id=1, tuid=294, volume_number=3, track_number=4, p_info='D', ), TrackMock( product_id=5, tuid=234, volume_number=4, track_number=3, p_info='C', ), TrackMock( product_id=5, tuid=254, volume_number=5, track_number=2, p_info='B', ), TrackMock( product_id=7, tuid=789, volume_number=6, track_number=1, p_info='A', ), ] ) def prepare_database(track_factory) -> None: """Save all mock objects to database. Args: track_factory: track factory (fixture). """ database_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=DATABASE_PRODUCT_IDS, ) db_tracks = [ track_factory(**tr) for tr in TracksMock.selected_columns_to_dict( tracks=database_tracks, selected_columns=[ 'product_id', 'tuid', 'volume_number', 'track_number', 'p_info', ], ) ] db.merge_model_objects(db_tracks) def prepare_database_for_sortering_order_tests(track_factory) -> None: """Prepare three seeds with track_number asc and volume_number mix. Args: track_factory: track factory (fixture). """ tracks = [ track_factory( **{ 'product_id': 1, 'tuid': 1, 'volume_number': 3, 'track_number': 1, } ), track_factory( **{ 'product_id': 1, 'tuid': 2, 'volume_number': 2, 'track_number': 2, } ), track_factory( **{ 'product_id': 1, 'tuid': 3, 'volume_number': 1, 'track_number': 1, } ), ] db.merge_model_objects(tracks) @db.test_schema_no_seed def test_get_all_tracks_by_product_ids(client, track_factory): """Test get all tracks in the database.""" prepare_database(track_factory) selected_product_ids = [1, 5] selected_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=selected_product_ids, ) actual_response = client.post( ENDPOINT, json={'product_ids': selected_product_ids}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=selected_tracks, target_columns=['tuid', 'product_id'], order_by_columns=['volume_number', 'track_number'], selected_product_ids=selected_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_for_single_product(client, track_factory): """Test get all tracks only for one product present in the database.""" prepare_database(track_factory) test_case_product_ids = [1] test_case_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=test_case_product_ids, ) actual_response = client.post( ENDPOINT, json={'product_ids': test_case_product_ids}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=test_case_tracks, target_columns=['tuid', 'product_id'], order_by_columns=['volume_number', 'track_number'], selected_product_ids=test_case_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_empty_product_list_in_request(client, track_factory): """Test endpoint when the request product_ids parameter is empty.""" prepare_database(track_factory) actual_response = client.post(ENDPOINT, json={'product_ids': []}) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == [] @db.test_schema_no_seed def test_no_product_ids_in_request_body(client, track_factory): """Test endpoint when the request product_ids is absent.""" prepare_database(track_factory) actual_response = client.post(ENDPOINT, json={}) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == [] @db.test_schema_no_seed def test_get_all_tracks_for_products_first_present(client, track_factory): """Test endpoint when only the first product tracks are present in DB.""" prepare_database(track_factory) test_case_product_ids = [1, 2] test_case_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=test_case_product_ids, ) actual_response = client.post( ENDPOINT, json={'product_ids': test_case_product_ids}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=test_case_tracks, target_columns=['tuid', 'product_id'], order_by_columns=['volume_number', 'track_number'], selected_product_ids=test_case_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_for_products_last_present(client, track_factory): """Test endpoint when only the last product tracks are present in DB.""" prepare_database(track_factory) test_case_product_ids = [2, 1] test_case_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=test_case_product_ids, ) actual_response = client.post( ENDPOINT, json={'product_ids': test_case_product_ids}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=test_case_tracks, target_columns=['tuid', 'product_id'], order_by_columns=['volume_number', 'track_number'], selected_product_ids=test_case_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_for_products_middle_present(client, track_factory): """Test endpoint when only middle product tracks are present in DB.""" prepare_database(track_factory) test_case_product_ids = [2, 1, 3] test_case_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=test_case_product_ids, ) actual_response = client.post( ENDPOINT, json={'product_ids': test_case_product_ids}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=test_case_tracks, target_columns=['tuid', 'product_id'], order_by_columns=['volume_number', 'track_number'], selected_product_ids=test_case_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_for_products_none_present(client, track_factory): """Test endpoint when only no a product tracks are present in DB.""" prepare_database(track_factory) test_case_product_ids = [2, 3] test_case_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=test_case_product_ids, ) actual_response = client.post( ENDPOINT, json={'product_ids': test_case_product_ids}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=test_case_tracks, target_columns=['tuid', 'product_id'], order_by_columns=['volume_number', 'track_number'], selected_product_ids=test_case_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_by_product_ids_track_number_order_first( client, track_factory, ): """Test endpoint ordering is the next: track_number, volume_number.""" prepare_database(track_factory) selected_product_ids = [1, 5] selected_sorting_columns = ['track_number', 'volume_number'] selected_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=selected_product_ids, ) actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_sorting_columns, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=selected_tracks, target_columns=['tuid', 'product_id'], order_by_columns=selected_sorting_columns, selected_product_ids=selected_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_by_product_ids_track_number_order_only( client, track_factory, ): """Test endpoint when ordering is only by track_number.""" prepare_database(track_factory) selected_product_ids = [1, 5] selected_sorting_columns = ['track_number'] selected_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=selected_product_ids, ) actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_sorting_columns, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=selected_tracks, target_columns=['tuid', 'product_id'], order_by_columns=selected_sorting_columns, selected_product_ids=selected_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_by_product_ids_volume_number_order_only( client, track_factory, ): """Test endpoint when ordering is only by volume_number.""" prepare_database(track_factory) selected_product_ids = [1, 5] selected_sorting_columns = ['volume_number'] selected_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=selected_product_ids, ) actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_sorting_columns, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=selected_tracks, target_columns=['tuid', 'product_id'], order_by_columns=selected_sorting_columns, selected_product_ids=selected_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_by_product_ids_p_info_order_only( client, track_factory, ): """Test endpoint when ordering is only by p_info.""" prepare_database(track_factory) selected_product_ids = [1, 5] selected_sorting_columns = ['p_info'] selected_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=selected_product_ids, ) actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_sorting_columns, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=selected_tracks, target_columns=['tuid', 'product_id'], order_by_columns=selected_sorting_columns, selected_product_ids=selected_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_get_all_tracks_by_product_ids_order_by_p_info_tn_vn( client, track_factory, ): """Test endpoint with ordering: p_info, track_number, volume_number.""" prepare_database(track_factory) selected_product_ids = [1, 5] selected_sorting_columns = ['p_info', 'track_number', 'volume_number'] selected_tracks = get_prepared_tracks().get_tracks_for_product_ids( product_ids=selected_product_ids, ) actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_sorting_columns, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) expected_response = TracksMock.prepare_endpoint_response( tracks=selected_tracks, target_columns=['tuid', 'product_id'], order_by_columns=selected_sorting_columns, selected_product_ids=selected_product_ids, ) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_desc_first_name_second( client, track_factory, ): """Test reverse sorting in first field only name in second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 2, 'product_id': 1}, {'tuid': 3, 'product_id': 1}, {'tuid': 1, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ {'column_name': 'track_number', 'order': 'desc'}, 'volume_number', ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_asc_first_name_second( client, track_factory, ): """Test asc sorting in first field only name in second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 3, 'product_id': 1}, {'tuid': 1, 'product_id': 1}, {'tuid': 2, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ {'column_name': 'track_number', 'order': 'asc'}, 'volume_number', ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_name_first_asc_second( client, track_factory, ): """Test name in first field and asc sorting in the second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 3, 'product_id': 1}, {'tuid': 1, 'product_id': 1}, {'tuid': 2, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ 'track_number', {'column_name': 'volume_number', 'order': 'asc'}, ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_name_first_desc_second( client, track_factory, ): """Test name in first field and desc sorting in the second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 1, 'product_id': 1}, {'tuid': 3, 'product_id': 1}, {'tuid': 2, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ 'track_number', {'column_name': 'volume_number', 'order': 'desc'}, ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_asc_first_asc_second( client, track_factory, ): """Test asc soring in first field and asc sorting in the second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 3, 'product_id': 1}, {'tuid': 1, 'product_id': 1}, {'tuid': 2, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ {'column_name': 'track_number', 'order': 'asc'}, {'column_name': 'volume_number', 'order': 'asc'}, ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_asc_first_desc_second( client, track_factory, ): """Test asc soring in first field and desc sorting in the second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 1, 'product_id': 1}, {'tuid': 3, 'product_id': 1}, {'tuid': 2, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ {'column_name': 'track_number', 'order': 'asc'}, {'column_name': 'volume_number', 'order': 'desc'}, ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_desc_first_asc_second( client, track_factory, ): """Test desc soring in first field and asc sorting in the second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 2, 'product_id': 1}, {'tuid': 3, 'product_id': 1}, {'tuid': 1, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ {'column_name': 'track_number', 'order': 'desc'}, {'column_name': 'volume_number', 'order': 'asc'}, ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_sorting_desc_first_desc_second( client, track_factory, ): """Test desc soring in first field and desc sorting in the second.""" prepare_database_for_sortering_order_tests(track_factory) expected_response = [ { 'tracks': [ {'tuid': 2, 'product_id': 1}, {'tuid': 1, 'product_id': 1}, {'tuid': 3, 'product_id': 1}, ], }, ] selected_product_ids = [1] selected_fields = [ {'column_name': 'track_number', 'order': 'desc'}, {'column_name': 'volume_number', 'order': 'desc'}, ] actual_response = client.post( ENDPOINT, json={ 'product_ids': selected_product_ids, 'order_by_fields': selected_fields, }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json == expected_response @db.test_schema_no_seed def test_none_product_ids_in_request_body(client, track_factory): """Test endpoint when the request product_ids is null.""" prepare_database(track_factory) actual_response = client.post(ENDPOINT, json={'product_ids': None}) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json['code'] == 'internal_error' @db.test_schema_no_seed def test_incorrect_product_ids_in_request_body(client, track_factory): """Test endpoint when the request product_ids is incorrect.""" prepare_database(track_factory) actual_response = client.post(ENDPOINT, json={'product_ids': 'INCORRECT'}) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json['code'] == 'internal_error' @db.test_schema_no_seed def test_incorrect_order_by_fields_in_request_body(client, track_factory): """Test endpoint when the request product_ids iis incorrect.""" prepare_database(track_factory) actual_response = client.post( ENDPOINT, json={'product_ids': [1, 5], 'order_by_fields': 'INCORRECT'}, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json['code'] == 'internal_error' @db.test_schema_no_seed def test_illegal_column_name_request_body(client, track_factory): """Test endpoint when the not accepted column name is present.""" prepare_database(track_factory) actual_response = client.post( ENDPOINT, json={ 'product_ids': [1, 5], 'order_by_fields': [{'column_name': '__dict__'}], }, ) assert actual_response response_json = json.loads(actual_response.data.decode()) assert response_json['code'] == 'internal_error'