Reconcile verified account IDs and make language repairs observable
Magent CI/CD / verify (push) Successful in 1m50s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-11 19:56:32 +12:00
parent 38169b881e
commit de25255ea8
25 changed files with 593 additions and 160 deletions
+53 -1
View File
@@ -4,7 +4,7 @@ from types import SimpleNamespace
from unittest.mock import AsyncMock, patch
from fastapi import HTTPException
from backend.app.services.request_language import language_info, original_profile, is_original_profile
from backend.app.services.request_language import language_info, original_profile, is_original_profile, apply_original_to_movie, movie_search_outcome
from backend.app.routers import requests
@@ -54,6 +54,7 @@ class RequestLanguageTests(unittest.IsolatedAsyncioTestCase):
with patch.object(requests, 'get_runtime_settings', return_value=runtime), \
patch.object(requests, 'JellyseerrClient', return_value=seerr), \
patch.object(requests, '_resolve_request_destination', new=AsyncMock(return_value={'server_id': 1, 'profile_id': 6, 'root_folder': '/media'})), \
patch.object(requests, 'apply_original_to_movie', new=AsyncMock(return_value=None)), \
patch.object(requests, 'original_profile', new=AsyncMock(return_value=20)) as clone:
payload = {'mediaType': media_type, 'tmdbId': 1417, 'acceptOriginalLanguage': consent, 'seasons': [1]}
if expected is None:
@@ -65,3 +66,54 @@ class RequestLanguageTests(unittest.IsolatedAsyncioTestCase):
await requests.create_request(payload, {'username': 'viewer'})
self.assertEqual(seerr.create_request.await_args.kwargs['profile_id'], expected)
self.assertEqual(clone.await_count, int(expected == 20))
async def test_existing_radarr_movie_is_updated_and_read_back(self):
movie = {'id': 6940, 'tmdbId': 613, 'qualityProfileId': 9, 'monitored': True}
client = SimpleNamespace(get_movie_by_tmdb_id=AsyncMock(return_value=[movie]),
update_movie=AsyncMock(), get_movie=AsyncMock(return_value={**movie, 'qualityProfileId': 20}))
with patch('backend.app.services.request_language.original_profile', new=AsyncMock(return_value=20)):
self.assertEqual(await apply_original_to_movie(client, 613), 20)
self.assertEqual(client.update_movie.await_args.args[0]['qualityProfileId'], 20)
self.assertTrue(client.update_movie.await_args.args[0]['monitored'])
async def test_failed_profile_verification_does_not_claim_success(self):
client = SimpleNamespace(get_movie_by_tmdb_id=AsyncMock(return_value=[{'id': 6940, 'tmdbId': 613, 'qualityProfileId': 9}]),
update_movie=AsyncMock(), get_movie=AsyncMock(return_value={'qualityProfileId': 9}))
with patch('backend.app.services.request_language.original_profile', new=AsyncMock(return_value=20)):
with self.assertRaises(HTTPException):
await apply_original_to_movie(client, 613)
async def test_search_reports_real_outcomes(self):
for command_status, queue, expected in [('completed', [], 'attention'), ('failed', [], 'attention'),
('started', [], 'searching'), ('completed', [{'movieId': 6940}], 'downloading')]:
client = SimpleNamespace(get=AsyncMock(return_value={'status': command_status}),
get_queue=AsyncMock(return_value={'records': queue}), get_movie=AsyncMock(return_value={'hasFile': False}))
result = await movie_search_outcome(client, 6940, {'id': 1}, attempts=1, delay=0)
self.assertEqual(result['status'], expected)
async def test_language_endpoint_checks_consent_identity_and_access(self):
for payload in ({}, {'acceptOriginalLanguage': 'true'}, {'acceptOriginalLanguage': True, 'languageCode': 'es'}):
with patch.object(requests, '_request_language_context', new=AsyncMock(return_value=(SimpleNamespace(), 613, {'code': 'de'}))), \
patch.object(requests, 'apply_original_to_movie', new=AsyncMock()) as apply:
with self.assertRaises(HTTPException):
await requests.accept_request_language('3976', payload, {'role': 'admin'})
apply.assert_not_awaited()
with self.assertRaises(HTTPException):
await requests.accept_request_language('3976', {'acceptOriginalLanguage': True}, {'role': 'user', 'auto_search_enabled': False})
async def test_radarr_queue_filters_before_pagination(self):
from backend.app.clients.radarr import RadarrClient
client = RadarrClient('http://radarr.test', 'test')
with patch.object(client, 'get', new=AsyncMock(return_value={'records': []})) as get:
await client.get_queue(6940)
get.assert_awaited_once_with('/api/v3/queue', params={'movieIds': 6940, 'pageSize': 1000})
async def test_tv_search_distinguishes_no_download_and_queue(self):
from backend.app.services.request_language import series_search_outcome
client = SimpleNamespace(get=AsyncMock(return_value={'status': 'completed'}), get_queue=AsyncMock(return_value={'records': []}))
self.assertEqual((await series_search_outcome(client, 50, [{'id': 1}], attempts=1))['status'], 'attention')
client.get_queue.return_value = {'records': [{'seriesId': 50}]}
self.assertEqual((await series_search_outcome(client, 50, [{'id': 1}], attempts=1))['status'], 'downloading')