wrolpi/modules/videos/video/test/test_api.py
Roland ae9d188391
Adding FileGroup.published_date/author/etc. Creating script which converts a Singlefile to an Archive FileGroup files.
Parsing SingleFile datetime using dates.strpdate.

Adding timezone when no timezone info is available.

Installing python-dateutil to assist in handling diverse datetime strings.

Reworking refresh progress to use idempotency to display more accurate progress.  Only logging that files have been invalidated if they used to be indexed.

Clearing archives to force re-index.

Ignoring 'Unknown' author from PDF metadata. Using file_title when pdf metadata title is empty.
2023-10-23 18:09:08 -06:00

192 lines
8.1 KiB
Python

import json
from datetime import timedelta
from http import HTTPStatus
from json import dumps
import pytest
from modules.videos.models import Video
from wrolpi.dates import now
def test_get_video_prev_next(test_session, channel_factory, video_factory):
"""
Test that the previous and next videos will be retrieved when fetching a video.
"""
channel1, channel2, channel3, channel4 = channel_factory(), channel_factory(), channel_factory(), channel_factory()
now_ = now()
second = timedelta(seconds=1)
# The upload_date decides the order of the prev/next videos.
video_factory(title='vid1', channel_id=channel1.id, upload_date=now_)
video_factory(title='vid2', channel_id=channel1.id, upload_date=now_ + second)
video_factory(title='vid3', channel_id=channel2.id, upload_date=now_ + (second * 4))
video_factory(title='vid4', channel_id=channel1.id, upload_date=now_ + (second * 3))
video_factory(title='vid5', channel_id=channel2.id, upload_date=now_ + (second * 2))
video_factory(title='vid6', channel_id=channel2.id, upload_date=now_ + (second * 5))
video_factory(title='vid7', channel_id=channel1.id)
video_factory(title='vid8', channel_id=channel2.id, upload_date=now_ + (second * 7))
video_factory(title='vid9', channel_id=channel3.id, upload_date=now_ + (second * 8))
# Videos without an upload date can't be placed.
video_factory(title='vid10', channel_id=channel4.id)
video_factory(title='vid11', channel_id=channel4.id)
test_session.commit()
tests = [
# Channel 1's videos were inserted in upload_date order.
(1, (None, 'vid2')),
(2, ('vid1', 'vid4')),
(4, ('vid2', None)), # 7 has no upload_date, so it doesn't come after 4.
(7, ('vid4', None)), # 7 has no upload_date, so we get the video next to it's file.
# Channel 3 has only one video.
(9, (None, None)),
# Channel 2 was inserted out of order.
(5, (None, 'vid3')),
(3, ('vid5', 'vid6')),
(8, ('vid6', None)),
# Channel 4's videos have no upload date, so we don't know what is previous/next.
(10, (None, 'vid11')),
(11, ('vid10', None)),
]
for id_, (prev_title, next_title) in tests:
video = test_session.query(Video).filter_by(id=id_).one()
prev_video, next_video = video.get_surrounding_videos()
try:
if prev_title is None:
assert prev_video is None
else:
assert prev_video and prev_video.file_group.title == prev_title
if next_title is None:
assert next_video is None
else:
assert next_video and next_video.file_group.title == next_title
except AssertionError as e:
raise AssertionError(f'Assert failed for {id_=} {prev_title=} {next_title=}') from e
def test_get_video_prev_next_no_upload_date(test_session, video_factory, channel_factory):
"""
Previous and Next Videos should be those next to a Video file when videos do not have upload dates.
"""
channel1, channel2 = channel_factory(), channel_factory()
vid0, vid1, vid2, vid3, vid4, vid5 = video_factory(channel2.id, title='vid0'), \
video_factory(channel1.id, title='vid1'), \
video_factory(channel1.id, title='vid2'), \
video_factory(channel1.id, title='vid3'), \
video_factory(title='vid4'), \
video_factory(title='vid5')
test_session.commit()
# Channel 2 has only 1 video.
prev, next_ = vid0.get_surrounding_videos()
assert prev is None
assert next_ is None
# Channel 1 has 3 videos, finally getting surrounding videos.
prev, next_ = vid1.get_surrounding_videos()
assert prev is None
assert next_ == vid2
prev, next_ = vid2.get_surrounding_videos()
assert prev == vid1
assert next_ == vid3
prev, next_ = vid3.get_surrounding_videos()
assert prev == vid2
assert next_ is None
# Videos without a channel
prev, next_ = vid4.get_surrounding_videos()
assert prev is None
assert next_ is vid5
prev, next_ = vid5.get_surrounding_videos()
assert prev == vid4
assert next_ is None
@pytest.mark.asyncio
async def test_video_delete(test_async_client, test_session, channel_factory, video_factory, test_download_manager):
"""Video.delete() removes the video's files, but leave the DB record."""
channel1, channel2 = channel_factory(), channel_factory()
vid1 = video_factory(channel_id=channel1.id, with_video_file=True, with_caption_file=True,
with_info_json={'url': '1'})
vid2 = video_factory(channel_id=channel2.id, with_video_file=True, with_info_json={'url': '2'})
test_session.commit()
assert test_session.query(Video).count() == 2
vid1_video_path, vid1_caption_path = vid1.video_path, vid1.caption_paths[0]
vid2_video_path, vid2_info_json_path = vid2.video_path, vid2.info_json_path
# No videos have been deleted yet.
assert vid1_video_path.is_file() and vid1_caption_path.is_file()
assert vid2_video_path.is_file() and vid2_info_json_path.is_file()
request, response = await test_async_client.delete(f'/api/videos/video/{vid1.id}')
assert response.status_code == HTTPStatus.NO_CONTENT
# Video was added to skip list.
assert test_download_manager.is_skipped(vid1.url)
# Video was deleted.
assert test_session.query(Video).count() == 1
assert vid1_video_path.is_file() is False and vid1_caption_path.is_file() is False
assert vid2_video_path.is_file() and vid2_info_json_path.is_file()
request, response = await test_async_client.delete(f'/api/videos/video/{vid2.id}')
assert response.status_code == HTTPStatus.NO_CONTENT
assert test_download_manager.is_skipped(vid1.url, vid2.url)
assert test_session.query(Video).count() == 0
assert vid1_video_path.is_file() is False and vid1_caption_path.is_file() is False
assert vid2_video_path.is_file() is False and vid2_info_json_path.is_file() is False
# 3 does not exist.
request, response = await test_async_client.delete(f'/api/videos/video/3')
assert response.status_code == HTTPStatus.NOT_FOUND
@pytest.mark.asyncio
async def test_wrol_mode(test_async_client, simple_channel, simple_video, wrol_mode_fixture,
test_download_manager, tag_factory):
"""Many methods are blocked when WROL Mode is enabled."""
channel = dumps(dict(name=simple_channel.name, directory=str(simple_channel.directory)))
tag = tag_factory()
wrol_mode_fixture(True)
# Can't create, update, or delete a channel.
_, resp = await test_async_client.post('/api/videos/channels', content=channel)
assert resp.status_code == HTTPStatus.FORBIDDEN
assert resp.json['code'] == 'WROL_MODE_ENABLED'
_, resp = await test_async_client.put(f'/api/videos/channels/{simple_channel.id}', content=channel)
assert resp.status_code == HTTPStatus.FORBIDDEN
assert resp.json['code'] == 'WROL_MODE_ENABLED'
_, resp = await test_async_client.delete(f'/api/videos/channels/{simple_channel.id}')
assert resp.status_code == HTTPStatus.FORBIDDEN
assert resp.json['code'] == 'WROL_MODE_ENABLED'
# Can't delete a video
_, resp = await test_async_client.delete(f'/api/videos/video/{simple_video.id}')
assert resp.status_code == HTTPStatus.FORBIDDEN
assert resp.json['code'] == 'WROL_MODE_ENABLED'
# Can't refresh or download
_, resp = await test_async_client.post('/api/files/refresh')
assert resp.status_code == HTTPStatus.FORBIDDEN
assert resp.json['code'] == 'WROL_MODE_ENABLED'
_, resp = await test_async_client.post(f'/api/videos/channels/download/{simple_channel.id}')
assert resp.status_code == HTTPStatus.FORBIDDEN
assert resp.json['code'] == 'WROL_MODE_ENABLED'
# THE REST OF THESE METHODS ARE ALLOWED
content = dict(file_group_id=simple_video.file_group_id, tag_name=tag.name)
_, resp = await test_async_client.post('/api/files/tag', content=json.dumps(content))
assert resp.status_code == HTTPStatus.CREATED
assert test_download_manager.stopped.is_set()
wrol_mode_fixture(False)
assert not test_download_manager.stopped.is_set()