"""Tests for track participation Neo4j queries.""" from unittest.mock import MagicMock, patch import pytest from contributor.queries.neo4j.tracks import ( get_by_label_participant_uuid, get_by_track_id, get_by_track_ids, get_track_artist_participations_by_track_ids, get_track_writer_participations_by_track_ids, ) @pytest.fixture def label_participant_uuid(): return "550e8400-e29b-41d4-a716-446655440000" @pytest.fixture def participations_record(label_participant_uuid): record = MagicMock() record.__getitem__ = lambda self, key: { "contributor": {"uuid": label_participant_uuid}, "participations": [ { "contributor": {"uuid": label_participant_uuid}, "participated_as": "performer", "track_id": 101, "track_artist_id": 1001, }, { "contributor": {"uuid": label_participant_uuid}, "participated_as": "featuring", "track_id": 202, "track_artist_id": 2002, }, ], }[key] record.get = lambda key, default=None: { "contributor": {"uuid": label_participant_uuid}, "participations": [ { "contributor": {"uuid": label_participant_uuid}, "participated_as": "performer", "track_id": 101, "track_artist_id": 1001, }, { "contributor": {"uuid": label_participant_uuid}, "participated_as": "featuring", "track_id": 202, "track_artist_id": 2002, }, ], }.get(key, default) return record @pytest.fixture def session(participations_record): session = MagicMock() result = MagicMock() result.single.return_value = participations_record session.run.return_value = result return session @pytest.fixture def empty_session(): session = MagicMock() result = MagicMock() result.single.return_value = None session.run.return_value = result return session @pytest.fixture def no_participations_record(label_participant_uuid): """LP exists but has no PARTICIPATED_IN relationships (OPTIONAL MATCH returns nulls).""" record = MagicMock() record.__getitem__ = lambda self, key: { "contributor": {"uuid": label_participant_uuid}, "participations": [ { "contributor": {"uuid": label_participant_uuid}, "participated_as": None, "track_id": None, "track_artist_id": None, } ], }[key] record.get = lambda key, default=None: { "contributor": {"uuid": label_participant_uuid}, "participations": [ { "contributor": {"uuid": label_participant_uuid}, "participated_as": None, "track_id": None, "track_artist_id": None, } ], }.get(key, default) return record def _make_record(track_dict): record = MagicMock() record.__getitem__ = lambda self, key: track_dict[key] return record def _make_session(artist_records, writer_records): """Mock Session that returns different results per query call. First session.run() call → TrackArtist branch (artist_records). Second session.run() call → TrackWriter branch (writer_records). """ session = MagicMock() artist_result = MagicMock() artist_result.__iter__ = lambda self: iter(artist_records) writer_result = MagicMock() writer_result.__iter__ = lambda self: iter(writer_records) session.run.side_effect = [artist_result, writer_result] return session class TestGetByLabelParticipantUuid: def test_returns_participations(self, session, label_participant_uuid) -> None: result = get_by_label_participant_uuid( session, uuid=label_participant_uuid, profile_ids=[7123], ) assert result == { "contributor": {"uuid": label_participant_uuid}, "participations": [ { "contributor": {"uuid": label_participant_uuid}, "participated_as": "performer", "track": {"tuid": 101}, "track_artist_id": 1001, }, { "contributor": {"uuid": label_participant_uuid}, "participated_as": "featuring", "track": {"tuid": 202}, "track_artist_id": 2002, }, ], } def test_returns_participations_as_admin( self, session, label_participant_uuid ) -> None: result = get_by_label_participant_uuid( session, uuid=label_participant_uuid, profile_ids=[], is_admin=True, ) assert result is not None assert len(result["participations"]) == 2 def test_returns_none_when_not_found(self, empty_session) -> None: assert ( get_by_label_participant_uuid( empty_session, uuid="no-match", profile_ids=[7123] ) is None ) def test_filters_null_participations_from_optional_match( self, no_participations_record, label_participant_uuid ) -> None: session = MagicMock() result = MagicMock() result.single.return_value = no_participations_record session.run.return_value = result tp = get_by_label_participant_uuid( session, uuid=label_participant_uuid, profile_ids=[7123], ) assert tp is not None assert tp["participations"] == [] class TestGetByTrackId: def test_returns_track_participations(self) -> None: track_result = { "track": {"tuid": 12345}, "participations": [ { "contributor": {"uuid": "550e8400-e29b-41d4-a716-446655440000"}, "participated_as": "performer", "track": {"tuid": 12345}, "track_artist_id": 1001, } ], } with patch( "contributor.queries.neo4j.track_participations.get_by_track_ids", return_value=[track_result], ): session = MagicMock() result = get_by_track_id(session, track_id=12345, profile_ids=[7123]) assert result == track_result def test_returns_none_when_track_not_found(self) -> None: with patch( "contributor.queries.neo4j.track_participations.get_by_track_ids", return_value=[], ): session = MagicMock() result = get_by_track_id(session, track_id=0, profile_ids=[7123]) assert result is None class TestGetByTrackIds: def test_unions_track_artist_and_track_writer_branches(self) -> None: artist_record = _make_record( { "track": {"tuid": 101}, "participations": [ { "contributor": {"uuid": "550e8400-e29b-41d4-a716-446655440000"}, "participated_as": "performer", "tuid": 101, "track_artist_id": 1001, } ], } ) writer_record = _make_record( { "track": {"tuid": 101}, "participations": [ { "contributor": {"uuid": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff"}, "participated_as": "track_writer", "tuid": 101, "track_artist_id": None, } ], } ) session = _make_session([artist_record], [writer_record]) tracks = get_by_track_ids(session, track_ids=[101], profile_ids=[7123]) assert tracks == [ { "track": {"tuid": 101}, "participations": [ { "contributor": {"uuid": "550e8400-e29b-41d4-a716-446655440000"}, "participated_as": "performer", "track": {"tuid": 101}, "track_artist_id": 1001, }, { "contributor": {"uuid": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff"}, "participated_as": "track_writer", "track": {"tuid": 101}, "track_artist_id": None, }, ], } ] def test_includes_writer_only_track(self) -> None: empty_artist_record = _make_record( {"track": {"tuid": 202}, "participations": []} ) writer_record = _make_record( { "track": {"tuid": 202}, "participations": [ { "contributor": {"uuid": "cccccccc-dddd-4eee-8fff-aaaaaaaaaaaa"}, "participated_as": "track_writer", "tuid": 202, "track_artist_id": None, } ], } ) session = _make_session([empty_artist_record], [writer_record]) tracks = get_by_track_ids(session, track_ids=[202], profile_ids=[7123]) assert len(tracks) == 1 assert tracks[0]["track"] == {"tuid": 202} assert tracks[0]["participations"] == [ { "contributor": {"uuid": "cccccccc-dddd-4eee-8fff-aaaaaaaaaaaa"}, "participated_as": "track_writer", "track": {"tuid": 202}, "track_artist_id": None, } ] def test_preserves_input_track_id_order(self) -> None: record_a = _make_record( { "track": {"tuid": 101}, "participations": [ { "contributor": {"uuid": "550e8400-e29b-41d4-a716-446655440000"}, "participated_as": "performer", "tuid": 101, "track_artist_id": 1001, } ], } ) record_b = _make_record( { "track": {"tuid": 202}, "participations": [ { "contributor": {"uuid": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"}, "participated_as": "featuring", "tuid": 202, "track_artist_id": 2002, } ], } ) empty_writer_records = [ _make_record({"track": {"tuid": 101}, "participations": []}), _make_record({"track": {"tuid": 202}, "participations": []}), ] # Artist branch returns 202 before 101 — output should still follow request order session = _make_session([record_b, record_a], empty_writer_records) tracks = get_by_track_ids(session, track_ids=[101, 202], profile_ids=[7123]) assert [t["track"]["tuid"] for t in tracks] == [101, 202] def test_returns_empty_list_when_none_found(self) -> None: session = _make_session([], []) tracks = get_by_track_ids(session, track_ids=[999], profile_ids=[7123]) assert tracks == [] def test_runs_artist_then_writer_query(self) -> None: session = _make_session([], []) get_by_track_ids(session, track_ids=[101], profile_ids=[7123]) first_query = session.run.call_args_list[0].kwargs["query"] second_query = session.run.call_args_list[1].kwargs["query"] assert first_query == get_track_artist_participations_by_track_ids assert second_query == get_track_writer_participations_by_track_ids