"""Unit tests for format_sql utility functions.""" from unittest.mock import patch import pytest from sound_recordings.utils import format_sql def _flatten_string(sql): return " ".join("".join(sql.splitlines()).split()) class TestFormatWithLPermissionFilter: """Tests for format_with_permissions_filter util function.""" @pytest.fixture() def product_filter_clause_mock(self): """Mock _compose_product_filter_clause helper function.""" with patch( "sound_recordings.utils.format_sql._compose_permissions_filter" ) as product_filter: product_filter.return_value = "product_dim_filter" yield product_filter def test_default(self, product_filter_clause_mock): """Test correct response for default.""" expected = """ {product_dim_filter} AND feed_id IN (:feed_ids) """.format( product_dim_filter=product_filter_clause_mock.return_value ) permissions_filter = {} filter_sql = format_sql.format_with_permissions_filter( "{filter_clause}", permissions_filter ) assert _flatten_string(filter_sql) == _flatten_string(expected) product_filter_clause_mock.assert_called_once_with(permissions_filter) def test_with_dates(self, product_filter_clause_mock): """Test correct response for passed dates.""" expected = """ {product_dim_filter} AND (download_activity_date BETWEEN :start_date AND :end_date) AND feed_id IN (:feed_ids) """.format( product_dim_filter=product_filter_clause_mock.return_value ) filter_sql = format_sql.format_with_permissions_filter( "{filter_clause}", {}, start_date="2021-01-01", end_date="2021-01-01" ) assert _flatten_string(filter_sql) == _flatten_string(expected) def test_old_feed_format(self, product_filter_clause_mock): """Test correct response for default.""" expected = """ {product_dim_filter} AND feedid IN (:feed_ids) """.format( product_dim_filter=product_filter_clause_mock.return_value ) filter_sql = format_sql.format_with_permissions_filter( "{filter_clause}", {}, use_old_format=True ) assert _flatten_string(filter_sql) == _flatten_string(expected) def test_allow_null_feed(self, product_filter_clause_mock): """Test correct response when allow_null_feed is True.""" expected = """ {product_dim_filter} AND (feed_id IS NULL OR feed_id IN (:feed_ids)) """.format( product_dim_filter=product_filter_clause_mock.return_value ) filter_sql = format_sql.format_with_permissions_filter( "{filter_clause}", {}, allow_null_feed=True ) assert _flatten_string(filter_sql) == _flatten_string(expected) class TestDimProductFilter: """Tests for _dim_release_filter helper function.""" @pytest.mark.parametrize( "permissions_filter, expected", [ [{"label_ids": None, "subaccount_ids": None, "artist_ids": None}, ""], [ {"label_ids": [1], "subaccount_ids": None, "artist_ids": None}, "labelid IN (:label_ids)", ], [ {"label_ids": None, "subaccount_ids": [2], "artist_ids": None}, "subaccountid IN (:subaccount_ids)", ], [ {"label_ids": None, "subaccount_ids": None, "artist_ids": [3]}, "artistid IN (:artist_ids)", ], [ {"label_ids": [1], "subaccount_ids": [2], "artist_ids": None}, "labelid IN (:label_ids) OR subaccountid IN (:subaccount_ids)", ], [ {"label_ids": [1], "subaccount_ids": None, "artist_ids": [3]}, "labelid IN (:label_ids) OR artistid IN (:artist_ids)", ], [ {"label_ids": None, "subaccount_ids": [2], "artist_ids": [3]}, "subaccountid IN (:subaccount_ids) OR " "artistid IN (:artist_ids)", ], [ {"label_ids": [1], "subaccount_ids": [2], "artist_ids": [3]}, "labelid IN (:label_ids) OR subaccountid IN (:subaccount_ids) " "OR artistid IN (:artist_ids)", ], ], ) def test_dim_release_filter(self, permissions_filter, expected): """Test _dim_release_filter helper function.""" filter_sql = format_sql._dim_release_filter(permissions_filter) assert filter_sql == expected class TestProductFilterClause: """Tests for _dim_release_filter helper function.""" @pytest.fixture() def compose_dim_filter_mock(self): """Mock _dim_release_filter helper function.""" with patch( "sound_recordings.utils.format_sql._dim_release_filter" ) as dim_filter: dim_filter.return_value = "dim_filter" yield dim_filter def test_full_access(self): """Test for full access case.""" permissions = { "label_ids": [], "subaccount_ids": [], "artist_ids": [], "label_participant_ids": [], } assert format_sql._compose_permissions_filter(permissions) == " true " def test_no_access(self): """Test for no access case.""" permissions = { "label_ids": None, "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, } assert format_sql._compose_permissions_filter(permissions) == " false " def test_dim_filter_only(self, compose_dim_filter_mock): """Test for dim_release filter only.""" expected = """ product_id IN ( SELECT product_id FROM dim_release WHERE {dim_release_filter} ) """.format( dim_release_filter=compose_dim_filter_mock.return_value ) permissions = { "label_ids": [6971], "subaccount_ids": None, "artist_ids": [777], "label_participant_ids": None, } filter_clause = format_sql._compose_permissions_filter(permissions) assert _flatten_string(expected) == _flatten_string(filter_clause) def test_label_participant_only(self): """Test for label participant ids filter only.""" expected = """ product_id IN ( SELECT product_id FROM label_participant_participated_in_orchard_product WHERE label_participant_id IN (:label_participant_ids) AND participated_as in ('performer', 'featuring', 'remixer') ) """ permissions = { "label_ids": None, "subaccount_ids": None, "artist_ids": None, "label_participant_ids": [1, 2], } filter_clause = format_sql._compose_permissions_filter(permissions) assert _flatten_string(expected) == _flatten_string(filter_clause) def test_dim_filter_and_participant(self, compose_dim_filter_mock): """Test for dim_release and label participant ids filter.""" expected = """ product_id IN ( SELECT product_id FROM dim_release WHERE {dim_release_filter} UNION SELECT product_id FROM label_participant_participated_in_orchard_product WHERE label_participant_id IN (:label_participant_ids) AND participated_as in ('performer', 'featuring', 'remixer') ) """.format( dim_release_filter=compose_dim_filter_mock.return_value ) permissions = { "label_ids": [6971], "subaccount_ids": None, "artist_ids": [777], "label_participant_ids": [10000], } filter_clause = format_sql._compose_permissions_filter(permissions) assert _flatten_string(expected) == _flatten_string(filter_clause) class TestHasFullAccess: """Test _has_full_access helper function.""" @pytest.mark.parametrize( "permissions, expected_result", [ [ { "label_ids": [], "subaccount_ids": [], "artist_ids": [], "label_participant_ids": [], }, True, ], [ { "label_ids": [], "subaccount_ids": [], "artist_ids": [], }, False, ], [ { "subaccount_ids": [], "artist_ids": [], "label_participant_ids": [], }, False, ], [ { "label_ids": [1], "subaccount_ids": [], "artist_ids": [], "label_participant_ids": [], }, False, ], [ { "label_ids": None, "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, }, False, ], ], ) def test_has_full_access(self, permissions, expected_result): """Test _has_full_access helper function.""" result = format_sql._has_full_access(permissions) assert result == expected_result class TestHasNoAccess: """Test _has_no_access helper function.""" @pytest.mark.parametrize( "permissions, expected_result", [ [ { "label_ids": None, "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, }, True, ], [ { "label_ids": [], "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, }, True, ], [ { "label_ids": None, "subaccount_ids": [], "artist_ids": None, "label_participant_ids": [], }, True, ], [ { "label_ids": [1], "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, }, False, ], [ { "label_ids": None, "subaccount_ids": None, "artist_ids": None, "label_participant_ids": [4], }, False, ], [ { "label_ids": [1], "subaccount_ids": [], "artist_ids": [], "label_participant_ids": [], }, False, ], ], ) def test_has_no_access(self, permissions, expected_result): """Test _has_no_access helper function.""" result = format_sql._has_no_access(permissions) assert result == expected_result @pytest.fixture def empty_permissions(): """Permissions template.""" return { "label_ids": None, "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, } @pytest.fixture def full_permissions(): """Permissions template.""" return { "label_ids": [], "subaccount_ids": [], "artist_ids": [], "label_participant_ids": [], } @pytest.fixture def partial_permissions(): """Permissions template.""" return { "label_ids": [1], "subaccount_ids": [2], "artist_ids": [3], "label_participant_ids": [4], }