"""Unit tests for Episode model."""
import datetime
from dateutil.tz import tzutc
from oto import status
import pytest
from sqlalchemy.exc import IntegrityError
from podcast.connectors import mysql
from podcast.constants import api as api_const
from podcast.models import episode
from podcast.utils import exc
from tests.utils import db_operations
def test_get_episodes():
"""Test episode model returns paginated data when seeded."""
limit = 0
offset = 0
podcast_id = 1
result_episodes = episode.get_episodes(podcast_id, limit, offset)
assert len(result_episodes['items']) == 3
result_episode = result_episodes['items'][2]
assert result_episode['id'] == db_operations.podcast_data[0]['id']
assert result_episode['title'] == db_operations.podcast_data[0]['title']
def test_get_episodes_draft(output_cdn_fixture):
"""Test episode model returns drafts."""
limit = 0
offset = 0
filter_by_state = 'DRAFT'
podcast_id = 1
result_episodes = episode.get_episodes(podcast_id, limit, offset, filter_by_state)
assert len(result_episodes['items']) == 2
def test_get_episodes_published():
"""Test episode model returns drafts."""
limit = 0
offset = 0
filter_by_state = 'DONE'
podcast_id = 1
result_episodes = episode.get_episodes(podcast_id, limit, offset, filter_by_state)
assert len(result_episodes['items']) == 1
def test_get_episodes_start_date():
"""Test episode model returns after start date."""
limit = 0
offset = 0
podcast_id = 1
result_episodes = episode.get_episodes(podcast_id, limit, offset, 'ALL',
order_by='published_date', sort_order='asc', start_date='2018-02-02')
assert len(result_episodes['items']) == 1
def test_get_episodes_end_date():
"""Test episode model returns before end date."""
limit = 0
offset = 0
podcast_id = 1
result_episodes = episode.get_episodes(podcast_id, limit, offset, 'ALL',
order_by='published_date', sort_order='asc', start_date='2019-02-02')
assert len(result_episodes['items']) == 1
def test_get_episodes_sorting_by_title():
"""Test that episode model sorts episodes."""
podcast_id = 1
result_episodes = episode.get_episodes(
podcast_id=podcast_id,
order_by='title',
sort_order='desc'
)
assert len(result_episodes['items']) == 3
assert result_episodes['items'][0]['title'] == 'title2'
assert result_episodes['items'][1]['title'] == 'title four'
assert result_episodes['items'][2]['title'] == 'title'
result_episodes = episode.get_episodes(
podcast_id=podcast_id,
order_by='title',
sort_order='asc'
)
assert result_episodes['items'][0]['title'] == 'title'
assert result_episodes['items'][1]['title'] == 'title four'
assert result_episodes['items'][2]['title'] == 'title2'
def test_get_episodes_by_mp_ids():
"""Test can get many episodes by mp ids."""
results = episode.get_episodes_by_megaphone_ids([
'6bf5bea4-a1d4-11e6-8dea-b334e2aa4880',
])
assert len(results['items']) == 1
def test_get_episode_by_id():
"""Test episode model return data by episode_id."""
episode_id = 1
result = episode.get_episode_by_id(episode_id)
assert result['id'] == episode_id
def test_get_episode_by_id_not_found():
"""Test episode model raises if episode_id doesn't exist."""
episode_id = 999
with pytest.raises(exc.OwsError) as err:
episode.get_episode_by_id(episode_id)
assert err.value.status == 404
def test_get_episodes_empty():
"""Test not found response when there is no episodes data."""
podcast_id = 100
result = episode.get_episodes(podcast_id)
assert len(result['items']) == 0
def test_get_episodes_with_insertion_points():
"""Test that get_episodes produces insertion_points."""
podcast_id = 1
result = episode.get_episodes(podcast_id)
assert len(result['items']) > 0
assert all(
isinstance(item['insertion_points'], list)
for item in result['items'])
def test_get_episode_by_id_with_insertion_points():
"""Test that get_episode_by_id produces insertion_points."""
episode_id = 1
result = episode.get_episode_by_id(episode_id)
assert len(result['insertion_points']) == 3
def test_get_episode_computed_status(mock_current_admin_user):
"""Test that computed_status property works correctly."""
podcast_id = 1
date_before_now = (datetime.datetime.now() - datetime.timedelta(hours=1)).isoformat()
episode_data = dict(
id=555,
podcast_id=podcast_id,
title='title',
description='description',
published_date=date_before_now,
draft=False
)
episode.create_episode(episode_data)
result = episode.get_episode_by_id(555)
assert result['status'] == api_const.EPISODE_STATUS_PUBLISHED
def test_search_episodes():
"""Test search on episodes."""
result = episode.search_episodes('title', [1, 2])
assert len(result) == 1
result_episode = result[0]
assert result_episode['id'] == db_operations.episode_data[0]['id']
assert result_episode['title'] == db_operations.episode_data[0]['title']
def test_create_episode(mock_current_admin_user, episode_fixture):
"""Test that a episode can be created."""
del episode_fixture['id']
created_episode = episode.create_episode(episode_fixture)
assert created_episode['id'] == 5
assert created_episode['external_id'] is None
assert created_episode['is_reviewed'] is True
def test_create_episode_with_external_id(mock_current_admin_user, episode_fixture):
"""Test that a episode can be created with external_id."""
episode_fixture['external_id'] = 'test_external_id'
del episode_fixture['id']
created_episode = episode.create_episode(episode_fixture)
assert created_episode['id'] == 5
assert created_episode['external_id'] == episode_fixture['external_id']
def test_create_episode_empty_body():
"""Test that a episode requires fields to be created."""
data = {}
with pytest.raises(exc.OwsError) as err:
episode.create_episode(data)
assert err.value.status == 400
def test_create_episode_with_insertion_points(mock_current_admin_user, episode_fixture):
"""Test that created episode involves insertion points' empty list."""
del episode_fixture['id']
created_episode = episode.create_episode(episode_fixture)
assert isinstance(created_episode['insertion_points'], list)
assert not created_episode['insertion_points']
def test_create_html_cleaned(monkeypatch, mock_current_admin_user):
"""Test create episode html stripped."""
episode_data = dict(
id=33,
podcast_id=1,
title='Episode Title',
description=''
)
result = episode.create_episode(episode_data)
assert result['description'] == '<script>alert("hi")</script>'
def test_update_html_cleaned(monkeypatch, mock_current_admin_user):
"""Test update episode html stripped."""
podcast_id = 1
episode_id = 1
episode_data = dict(
id=episode_id,
podcast_id=podcast_id,
title='Episode Title',
description='',
megaphone_id='f64b0f8e-ea77-11e9-9831-df1b1d22b24a'
)
result = episode.update_episode(episode_id, episode_data)
assert result['description'] == '<script>alert("hi")</script>'
def test_clean_episode_input_data():
"""Test that timestamp is converting correctly."""
data = {'published_date': '2019-12-26T16:52:01.000Z'}
validated = episode._clean_episode_input_data(data)
assert validated['published_date'] == datetime.datetime(2019, 12, 26, 16, 52, 1, tzinfo=tzutc())
def test_create_episode_published_date(mock_current_admin_user, episode_fixture):
"""Test that published date is correctly inserted."""
episode_fixture['published_date'] = '2019-12-26T16:52:01.000Z'
del episode_fixture['id']
created_episode = episode.create_episode(episode_fixture)
assert isinstance(created_episode['published_date'], datetime.datetime)
def test_update_episode(mock_current_admin_user):
"""Test that a episode can be updated."""
episode_id = 1
data = dict(
title='title 2',
description='description 2')
updated_episode = episode.update_episode(episode_id, data)
assert updated_episode['title'] == data['title']
assert updated_episode['description'] == data['description']
def test_update_episode_for_external_id(mock_current_admin_user):
"""Test that a episode can be updated for external_id."""
episode_id = 1
data = dict(
title='title 2',
description='description 2',
external_id='test_external_id')
updated_episode = episode.update_episode(episode_id, data)
assert updated_episode['external_id'] == data['external_id']
data['external_id'] = None
updated_episode = episode.update_episode(episode_id, data)
assert updated_episode['external_id'] is None
def test_update_episode_for_is_reviewed(mock_current_admin_user):
"""Test that a episode can be updated for is_reviewed."""
episode_id = 2
data = dict(
title='title 2',
description='description 2',
is_reviewed=True)
updated_episode = episode.update_episode(episode_id, data)
assert updated_episode['is_reviewed'] is True
def test_update_episode_empty_body():
"""Test that a podcast requires fields to be updated."""
episode_id = 2
data = {}
with pytest.raises(exc.OwsError) as err:
episode.update_episode(episode_id, data)
assert err.value.status == 400
def test_update_episode_null_podcast_id(mock_current_admin_user):
"""Test that episode update will fail with new podcast_id is None."""
episode_id = 1
data = {
'podcast_id': None
}
with pytest.raises(IntegrityError) as err:
episode.update_episode(episode_id, data)
assert err.type == IntegrityError
def test_update_episode_with_insertion_points(mock_current_admin_user):
"""Test that updated episode involves insetion points."""
episode_id = 1
data = dict(
title='title 2',
description='description 2')
result = episode.update_episode(episode_id, data)
assert result['insertion_points']
def test_update_episode_published_date(mock_current_admin_user):
"""Test that published date is correctly updated."""
episode_id = 1
data = dict(
published_date='2019-12-26T16:52:01.000Z')
result = episode.update_episode(episode_id, data)
assert isinstance(result['published_date'], datetime.datetime)
def test_delete_episode(mock_current_admin_user, output_cdn_fixture):
"""Test delete episode."""
episode_id = 1
podcast_id = 1
result_episode = episode.get_episodes(podcast_id)
starting_count = len(result_episode['items'])
with mysql.pod_db_session() as session:
result = episode.delete_episode(podcast_id, episode_id, session)
assert result['id'] == podcast_id
result_episode = episode.get_episodes(podcast_id)
assert len(result_episode['items']) == starting_count - 1
def test_delete_episode_not_found():
"""Test delete episode with not found response."""
episode_id = 10
podcast_id = 10
with mysql.pod_db_session() as session:
with pytest.raises(exc.OwsError) as err:
episode.delete_episode(podcast_id, episode_id, session)
assert err.value.status == 404
def test_delete_episode_with_insertion_points(mock_current_admin_user):
"""Test delete episode returns insertion points as well."""
episode_id = 1
podcast_id = 1
with mysql.pod_db_session() as session:
result = episode.delete_episode(podcast_id, episode_id, session)
assert result['insertion_points']
def test_soft_delete_doesnt_fetch_rows(mock_current_admin_user, output_cdn_fixture):
"""Test with is_deleted=True rows are not fetched."""
podcast_id = 1
episode_id = 1
result = episode.get_episode_by_id(episode_id)
assert result['id'] == episode_id
result = episode.get_episodes(podcast_id)
starting_count = len(result['items'])
episode.update_episode(episode_id, {'is_deleted': True})
with pytest.raises(exc.OwsError) as err:
episode.get_episode_by_id(episode_id)
assert err.value.status == 404
result = episode.get_episodes(podcast_id)
assert len(result['items']) == starting_count - 1
def test_create_planned_inventory(mock_current_admin_user, planned_inventory_fixture):
"""Test create planned inventory inserts."""
podcast_id = 1
planned_inventory_fixture['dates'].append('2019-11-22T16:52:01.000Z')
starting_num_episodes = len(episode.get_episodes(podcast_id)['items'])
episode.create_planned_inventory(1, planned_inventory_fixture)
episodes = episode.get_episodes(podcast_id)['items']
finished_num_episodes = len(episodes)
assert finished_num_episodes == starting_num_episodes + 2
assert episodes[3]['title'] == 'Draft Episode for 11/22/2019'
assert episodes[3]['planned_mid_roll_count'] == 0
assert episodes[3]['planned_post_roll_count'] == 2
assert episodes[3]['planned_pre_roll_count'] == 1
assert episodes[4]['title'] == 'Draft Episode for 11/26/2019'
def test_create_planned_inventory_no_podcast(mock_current_admin_user, planned_inventory_fixture):
"""Test create planned inventory has no podcast."""
with pytest.raises(exc.OwsError) as err:
episode.create_planned_inventory(None, planned_inventory_fixture)
assert err.value.status == status.BAD_REQUEST
def test_create_planned_inventory_no_data(mock_current_admin_user):
"""Test create planned inventory has no data."""
podcast_id = 1
with pytest.raises(exc.OwsError) as err:
episode.create_planned_inventory(podcast_id, None)
assert err.value.status == status.BAD_REQUEST
def test_get_episodes_by_ids():
"""Test can get many episodes by ids."""
results = episode.get_episodes_by_ids([1, 2])
assert len(results['items']) == 2
def test_get_num_episodes_for_podcast_ids():
"""Test get number of episodes for podcast ids."""
results = episode.get_num_episodes_for_podcast_ids([1, 2])
assert results == {1: 1}
def test_episodes_gone_live_within_hour(mock_current_admin_user):
"""Test episodes gone live within an hour."""
now = datetime.datetime.utcnow()
half_hour_ago = (now - datetime.timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
assert len(episode.episodes_gone_live_within_hour()) == 0
episode.update_episode(1, {
'published_date': half_hour_ago,
'draft': False
})
assert len(episode.episodes_gone_live_within_hour()) == 1
hour_ago = (now - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
episode.update_episode(1, {
'published_date': hour_ago,
'draft': False
})
assert len(episode.episodes_gone_live_within_hour()) == 0
episode.update_episode(1, {
'published_date': now.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
'draft': False
})
assert len(episode.episodes_gone_live_within_hour()) == 1
in_one_min = (now + datetime.timedelta(minutes=1)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
episode.update_episode(1, {
'published_date': in_one_min,
'draft': False
})
assert len(episode.episodes_gone_live_within_hour()) == 0
def test_episodes_going_live_tomorrow(mock_current_admin_user):
"""Test episodes going live tomorrow."""
episode.update_episode(1, {'draft': False})
now = datetime.datetime.utcnow()
episode.update_episode(1, {'published_date': now.strftime('%Y-%m-%dT%H:%M:%S.000Z')})
assert len(episode.episodes_going_live_tomorrow()) == 0
in_24_hours = (now + datetime.timedelta(hours=24)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
episode.update_episode(1, {'published_date': in_24_hours})
assert len(episode.episodes_going_live_tomorrow()) == 1
in_23_hours = (now + datetime.timedelta(hours=23)).strftime('%Y-%m-%dT%H:%M:%S.000Z')
episode.update_episode(1, {'published_date': in_23_hours})
assert len(episode.episodes_going_live_tomorrow()) == 0