| import pytest |
| from unittest.mock import MagicMock, patch |
| import os |
| from fastapi import UploadFile, HTTPException |
|
|
| from app.services.video_service import VideoService |
| from app.db.repositories.video import VideoRepository |
| from app.db.repositories.results import ResultsRepository |
| from app.models.video import VideoMetadata |
| from app.core.exceptions import VideoNotFoundError |
|
|
| class TestVideoService: |
| """Tests for the VideoService class.""" |
| |
| @pytest.fixture |
| def mock_video_repo(self): |
| """Create a mock video repository.""" |
| return MagicMock(spec=VideoRepository) |
| |
| @pytest.fixture |
| def mock_results_repo(self): |
| """Create a mock results repository.""" |
| return MagicMock(spec=ResultsRepository) |
| |
| @pytest.fixture |
| def video_service(self, mock_video_repo, mock_results_repo, db_session): |
| """Create a video service with mock repositories.""" |
| service = VideoService(db_session) |
| service.video_repo = mock_video_repo |
| service.results_repo = mock_results_repo |
| return service |
| |
| @patch('app.services.video_service.save_upload_file') |
| @patch('app.services.video_service.get_video_duration') |
| @patch('os.path.getsize') |
| async def test_upload_video(self, mock_getsize, mock_get_duration, mock_save_upload, video_service, mock_video_repo): |
| """Test uploading a video.""" |
| |
| mock_file = MagicMock(spec=UploadFile) |
| mock_file.filename = "test_video.mp4" |
| |
| mock_save_upload.return_value = ("test-video-id", "test_video.mp4") |
| mock_getsize.return_value = 1000 |
| mock_get_duration.return_value = 10.0 |
| |
| mock_video = MagicMock() |
| mock_video.id = "test-video-id" |
| mock_video.original_filename = "test_video.mp4" |
| mock_video.upload_date = "2023-01-01T00:00:00" |
| mock_video.size = 1000 |
| mock_video.duration = 10.0 |
| mock_video.status = "uploaded" |
| |
| mock_video_repo.create.return_value = mock_video |
| |
| |
| result = await video_service.upload_video(mock_file) |
| |
| |
| assert isinstance(result, VideoMetadata) |
| assert result.video_id == "test-video-id" |
| assert result.original_filename == "test_video.mp4" |
| assert result.size == 1000 |
| assert result.duration == 10.0 |
| assert result.status == "uploaded" |
| |
| mock_save_upload.assert_called_once_with(mock_file) |
| mock_getsize.assert_called_once() |
| mock_get_duration.assert_called_once() |
| mock_video_repo.create.assert_called_once() |
| |
| async def test_upload_video_no_filename(self, video_service): |
| """Test uploading a video with no filename.""" |
| |
| mock_file = MagicMock(spec=UploadFile) |
| mock_file.filename = None |
| |
| |
| with pytest.raises(HTTPException) as excinfo: |
| await video_service.upload_video(mock_file) |
| |
| assert excinfo.value.status_code == 400 |
| assert "No file provided" in str(excinfo.value.detail) |
| |
| def test_get_video_metadata(self, video_service, mock_video_repo): |
| """Test getting video metadata.""" |
| |
| video_id = "test-video-id" |
| |
| mock_video = MagicMock() |
| mock_video.id = video_id |
| mock_video.original_filename = "test_video.mp4" |
| mock_video.upload_date = "2023-01-01T00:00:00" |
| mock_video.size = 1000 |
| mock_video.duration = 10.0 |
| mock_video.status = "uploaded" |
| |
| mock_video_repo.get_by_id.return_value = mock_video |
| |
| |
| result = video_service.get_video_metadata(video_id) |
| |
| |
| assert isinstance(result, VideoMetadata) |
| assert result.video_id == video_id |
| assert result.original_filename == "test_video.mp4" |
| assert result.size == 1000 |
| assert result.duration == 10.0 |
| assert result.status == "uploaded" |
| |
| mock_video_repo.get_by_id.assert_called_once_with(video_id) |
| |
| def test_get_video_metadata_not_found(self, video_service, mock_video_repo): |
| """Test getting video metadata for a video that doesn't exist.""" |
| |
| video_id = "non-existent-id" |
| mock_video_repo.get_by_id.return_value = None |
| |
| |
| with pytest.raises(HTTPException) as excinfo: |
| video_service.get_video_metadata(video_id) |
| |
| assert excinfo.value.status_code == 404 |
| assert "Video not found" in str(excinfo.value.detail) |
| |
| mock_video_repo.get_by_id.assert_called_once_with(video_id) |
| |
| def test_list_videos(self, video_service, mock_video_repo): |
| """Test listing videos.""" |
| |
| mock_video1 = MagicMock() |
| mock_video1.id = "test-video-id-1" |
| mock_video1.original_filename = "test_video1.mp4" |
| mock_video1.upload_date = "2023-01-01T00:00:00" |
| mock_video1.size = 1000 |
| mock_video1.duration = 10.0 |
| mock_video1.status = "uploaded" |
| |
| mock_video2 = MagicMock() |
| mock_video2.id = "test-video-id-2" |
| mock_video2.original_filename = "test_video2.mp4" |
| mock_video2.upload_date = "2023-01-02T00:00:00" |
| mock_video2.size = 2000 |
| mock_video2.duration = 20.0 |
| mock_video2.status = "completed" |
| |
| mock_video_repo.get_all.return_value = [mock_video1, mock_video2] |
| |
| |
| result = video_service.list_videos() |
| |
| |
| assert isinstance(result, list) |
| assert len(result) == 2 |
| assert all(isinstance(item, VideoMetadata) for item in result) |
| assert result[0].video_id == "test-video-id-1" |
| assert result[1].video_id == "test-video-id-2" |
| |
| mock_video_repo.get_all.assert_called_once() |
| |
| def test_delete_video_with_results(self, video_service, mock_video_repo, mock_results_repo): |
| """Test deleting a video with associated processing results.""" |
| |
| video_id = "test-video-id" |
| file_path = "/path/to/test_video.mp4" |
| |
| mock_video = MagicMock() |
| mock_video.id = video_id |
| mock_video.file_path = file_path |
| |
| mock_video_repo.get_by_id.return_value = mock_video |
| mock_video_repo.delete.return_value = True |
| |
| |
| with patch('os.path.exists', return_value=True), \ |
| patch('os.remove') as mock_remove: |
| |
| |
| result = video_service.delete_video(video_id) |
| |
| |
| assert result is True |
| mock_video_repo.get_by_id.assert_called_once_with(video_id) |
| mock_results_repo.delete_by_video_id.assert_called_once_with(video_id) |
| mock_video_repo.delete.assert_called_once_with(video_id) |
| mock_remove.assert_called_once_with(file_path) |
| |
| def test_delete_video_not_found(self, video_service, mock_video_repo): |
| """Test deleting a video that doesn't exist.""" |
| |
| video_id = "non-existent-id" |
| mock_video_repo.get_by_id.return_value = None |
| |
| |
| with pytest.raises(VideoNotFoundError): |
| video_service.delete_video(video_id) |
| |
| mock_video_repo.get_by_id.assert_called_once_with(video_id) |
| mock_video_repo.delete.assert_not_called() |