"""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()