"""Tests Meta DDEX header generation.""" from datetime import datetime, timezone from textwrap import dedent from unittest.mock import patch import pytest from freezegun import freeze_time from soundrecording_utils.ddex.v38 import deal from soundrecording_utils.ddex.v38.e import E from soundrecording_utils.metadata.types import FingerprintRule, OrchardSoundRecording, Product, Track, TrackConnection @freeze_time('2024-02-01') def test_generate_sound_recording_deals( mock_orchard_sound_recording: OrchardSoundRecording, mock_product: Product, mock_track: Track, mock_fingerprint_rule: FingerprintRule, helpers, ): """Test _generate_sound_recording_deals.""" mock_t1_rules = [ mock_fingerprint_rule._replace(territory='CA', service='tiktok'), mock_fingerprint_rule._replace(territory='US', service='tiktok'), ] mock_t2_rules = [ mock_fingerprint_rule._replace(territory='UK', service='tiktok'), mock_fingerprint_rule._replace(territory='US', service='tiktok'), ] mock_t3_rules = [ mock_fingerprint_rule._replace(territory='CA', service='tiktok'), mock_fingerprint_rule._replace(territory='MX', service='tiktok'), ] mock_t4_rules = [ mock_fingerprint_rule._replace( territory='FR', policy='block_access', service='tiktok', end_date=datetime(2025, 1, 1, 10, 1, 40, tzinfo=timezone.utc), ), ] mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection( tracks=[ mock_track._replace( tuid='1', rules=mock_t1_rules, ), mock_track._replace( tuid='2', rules=mock_t2_rules, ), mock_track._replace( tuid='3', rules=mock_t3_rules, ), mock_track._replace( tuid='4', rules=mock_t4_rules, ), ] ) ) result = deal._generate_sound_recording_deals(mock_orchard_sound_recording, 'tiktok') result = E( 'TestDealContainer', *result, ) # group deals by policy type+start date+end date # 'US' and 'CA' de-duplicated result = helpers.print_xml(result) expected = """ RightsClaimModel UserMakeAvailableUserProvided CA MX UK US 2024-01-01T10:01:40 Monetize RightsClaimModel UserMakeAvailableUserProvided FR 2024-01-01T10:01:40 2025-01-01T10:01:40 BlockAccess """ assert result == dedent(expected).strip() @freeze_time('2024-02-01') def test_generate_sound_recording_deals_with_sixtyseconds_policy( mock_orchard_sound_recording: OrchardSoundRecording, mock_product: Product, mock_track: Track, mock_fingerprint_rule: FingerprintRule, helpers, ): """Test that sixtyseconds policies emit conditional RightsClaimPolicy nodes.""" sixtysecond_rules = [ mock_fingerprint_rule._replace( policy='sixtyseconds', territory='US', service='tiktok', ), ] mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection( tracks=[ mock_track._replace( tuid='1', rules=sixtysecond_rules, ), ] ) ) result = deal._generate_sound_recording_deals( mock_orchard_sound_recording, 'tiktok' ) result = E( 'TestDealContainer', *result, ) result = helpers.print_xml(result) expected = """ RightsClaimModel UserMakeAvailableUserProvided US 2024-01-01T10:01:40 60 Seconds ConsumerResource LessThanOrEqualTo Audio Monetize 60 Seconds ConsumerResource MoreThanOrEqualTo Audio BlockAccess """ assert result == dedent(expected).strip() @freeze_time('2019-06-15') def test_generate_sound_recording_deals_takedown( mock_orchard_sound_recording: OrchardSoundRecording, mock_product: Product, mock_track: Track, mock_fingerprint_rule: FingerprintRule, helpers, ): """Test _generate_sound_recording_details w/o territories.""" mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection(tracks=[mock_track._replace(rules=[])]) ) result = deal._generate_sound_recording_deals(mock_orchard_sound_recording, 'tiktok') result = E( 'TestDealContainer', *result, ) result = helpers.print_xml(result) # no territories means 'Worldwide' and 2 days ago as EndDateTime expected = """ RightsClaimModel UserMakeAvailableUserProvided Worldwide 2019-06-13T00:00:00 Monetize """ assert result == dedent(expected).strip() @freeze_time('2024-02-01') def test_generate_sound_recording_deals_filters_by_service( mock_orchard_sound_recording: OrchardSoundRecording, mock_track: Track, mock_fingerprint_rule: FingerprintRule, ): """Test that _generate_sound_recording_deals only uses rules for the given service.""" youtube_rule = mock_fingerprint_rule._replace(territory='DE', service='youtube') tiktok_rule = mock_fingerprint_rule._replace(territory='US', service='tiktok') mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection( tracks=[ mock_track._replace(tuid='1', rules=[youtube_rule, tiktok_rule]), ] ) ) result = deal._generate_sound_recording_deals( mock_orchard_sound_recording, service='youtube' ) all_territories = [ t.text for d in result for t in d.find('DealTerms').findall('TerritoryCode') ] assert 'DE' in all_territories assert 'US' not in all_territories def test_generate_deal_value_error(): """Test exception on no date params.""" expected = 'Deal must include start and/or end date' with pytest.raises(ValueError, match=expected): deal._generate_sound_recording_deal(['US'], 'Monetize') @freeze_time('2024-02-01') def test_generate_sound_recording_deals_with_sixtyseconds_and_monetize( mock_orchard_sound_recording: OrchardSoundRecording, mock_product: Product, mock_track: Track, mock_fingerprint_rule: FingerprintRule, helpers, ): """Test sixtyseconds overrides monetize in consolidated policy.""" rules = [ mock_fingerprint_rule._replace( policy='monetize', territory='US', service='tiktok', ), mock_fingerprint_rule._replace( policy='sixtyseconds', territory='US', service='tiktok', ), mock_fingerprint_rule._replace( policy='monetize', territory='CA', service='tiktok', ), ] mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection( tracks=[ mock_track._replace( tuid='1', rules=rules, ), ] ) ) result = deal._generate_sound_recording_deals( mock_orchard_sound_recording, 'tiktok' ) result = E( 'TestDealContainer', *result, ) result = helpers.print_xml(result) expected = """ RightsClaimModel UserMakeAvailableUserProvided CA 2024-01-01T10:01:40 Monetize RightsClaimModel UserMakeAvailableUserProvided US 2024-01-01T10:01:40 60 Seconds ConsumerResource LessThanOrEqualTo Audio Monetize 60 Seconds ConsumerResource MoreThanOrEqualTo Audio BlockAccess """ assert result == dedent(expected).strip() @freeze_time('2024-02-01') def test_generate_sound_recording_deals_with_block_overrides_sixtyseconds( mock_orchard_sound_recording: OrchardSoundRecording, mock_product: Product, mock_track: Track, mock_fingerprint_rule: FingerprintRule, helpers, ): """Test block_access overrides sixtyseconds in consolidated policy.""" rules = [ mock_fingerprint_rule._replace( policy='sixtyseconds', territory='US', service='tiktok', ), mock_fingerprint_rule._replace( policy='block_access', territory='US', service='tiktok', ), mock_fingerprint_rule._replace( policy='sixtyseconds', territory='CA', service='tiktok', ), ] mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection( tracks=[ mock_track._replace( tuid='1', rules=rules, ), ] ) ) result = deal._generate_sound_recording_deals( mock_orchard_sound_recording, 'tiktok' ) result = E( 'TestDealContainer', *result, ) result = helpers.print_xml(result) expected = """ RightsClaimModel UserMakeAvailableUserProvided CA 2024-01-01T10:01:40 60 Seconds ConsumerResource LessThanOrEqualTo Audio Monetize 60 Seconds ConsumerResource MoreThanOrEqualTo Audio BlockAccess RightsClaimModel UserMakeAvailableUserProvided US 2024-01-01T10:01:40 BlockAccess """ assert result == dedent(expected).strip() @freeze_time('2024-02-01') def test_generate_sound_recording_deals_with_mixed_all_policies( mock_orchard_sound_recording: OrchardSoundRecording, mock_product: Product, mock_track: Track, mock_fingerprint_rule: FingerprintRule, helpers, ): """Test mixed monetize, sixtyseconds, and block_access policies in one deal.""" rules = [ mock_fingerprint_rule._replace( policy='monetize', territory='FR', service='tiktok', ), mock_fingerprint_rule._replace( policy='sixtyseconds', territory='DE', service='tiktok', ), mock_fingerprint_rule._replace( policy='block_access', territory='UK', service='tiktok', ), ] mock_orchard_sound_recording = mock_orchard_sound_recording._replace( track_connection=TrackConnection( tracks=[ mock_track._replace( tuid='1', rules=rules, ), ] ) ) result = deal._generate_sound_recording_deals( mock_orchard_sound_recording, 'tiktok' ) result = E( 'TestDealContainer', *result, ) result = helpers.print_xml(result) expected = """ RightsClaimModel UserMakeAvailableUserProvided FR 2024-01-01T10:01:40 Monetize RightsClaimModel UserMakeAvailableUserProvided DE 2024-01-01T10:01:40 60 Seconds ConsumerResource LessThanOrEqualTo Audio Monetize 60 Seconds ConsumerResource MoreThanOrEqualTo Audio BlockAccess RightsClaimModel UserMakeAvailableUserProvided UK 2024-01-01T10:01:40 BlockAccess """ assert result == dedent(expected).strip() @patch('soundrecording_utils.ddex.v38.deal._generate_sound_recording_deals') def test_generate_release_deal( mock_generate_sound_recording_deals, mock_orchard_sound_recording: OrchardSoundRecording, helpers, ): """Test generate_release_deal.""" mock_generate_sound_recording_deals.return_value = ( E('MockSoundRecordingDeal1'), E('MockSoundRecordingDeal2'), ) result = deal.generate_release_deal( 'R0', mock_orchard_sound_recording, 'tiktok', ) result = helpers.print_xml(result) expected = """ R0 """ assert result == dedent(expected).strip()