diff --git a/tests/test_phase1_websocket.py b/tests/test_phase1_websocket.py index e25eed5d..8d1f4658 100644 --- a/tests/test_phase1_websocket.py +++ b/tests/test_phase1_websocket.py @@ -35,34 +35,6 @@ class TestInfrastructure: assert client.is_connected() client.disconnect() - def test_http_status_still_works(self, flask_client): - """GET /status returns 200 with expected keys.""" - resp = flask_client.get('/status') - assert resp.status_code == 200 - data = resp.get_json() - assert 'spotify' in data - assert 'media_server' in data - assert 'soulseek' in data - assert 'active_media_server' in data - - def test_http_watchlist_count_still_works(self, flask_client): - """GET /api/watchlist/count returns 200 with expected keys.""" - resp = flask_client.get('/api/watchlist/count') - assert resp.status_code == 200 - data = resp.get_json() - assert data['success'] is True - assert 'count' in data - assert 'next_run_in_seconds' in data - - def test_http_download_batch_still_works(self, flask_client): - """GET /api/download_status/batch returns 200 with expected structure.""" - resp = flask_client.get('/api/download_status/batch') - assert resp.status_code == 200 - data = resp.get_json() - assert 'batches' in data - assert 'metadata' in data - - # ========================================================================= # Group B — Service Status Parity # ========================================================================= @@ -70,16 +42,6 @@ class TestInfrastructure: class TestServiceStatus: """status:update socket events match GET /status HTTP responses.""" - def test_status_update_received(self, test_app, shared_state): - """Client receives a status:update event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_status_payload'] - socketio.emit('status:update', build()) - received = client.get_received() - status_events = [e for e in received if e['name'] == 'status:update'] - assert len(status_events) >= 1 - def test_status_update_shape(self, test_app, shared_state): """status:update event data has the expected keys.""" app, socketio = test_app @@ -139,16 +101,6 @@ class TestServiceStatus: class TestWatchlistCount: """watchlist:count socket events match GET /api/watchlist/count.""" - def test_watchlist_count_received(self, test_app, shared_state): - """Client receives a watchlist:count event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_watchlist_count_payload'] - socketio.emit('watchlist:count', build()) - received = client.get_received() - wl_events = [e for e in received if e['name'] == 'watchlist:count'] - assert len(wl_events) >= 1 - def test_watchlist_count_shape(self, test_app, shared_state): """watchlist:count event data has expected keys.""" app, socketio = test_app @@ -222,12 +174,6 @@ class TestDownloadBatch: with lock: batches[batch_id] = defaults - def test_download_subscribe(self, test_app): - """Client can subscribe to a batch room.""" - app, socketio = test_app - client = socketio.test_client(app) - client.emit('downloads:subscribe', {'batch_ids': ['batch_abc']}) - def test_download_receives_updates(self, test_app, shared_state): """After subscribing, client receives batch_update for that batch.""" app, socketio = test_app @@ -338,47 +284,6 @@ class TestDownloadBatch: assert 'active_count' in data assert 'max_concurrent' in data - def test_download_http_batch_still_works(self, test_app, shared_state): - """HTTP batch endpoint works alongside WebSocket rooms.""" - app, socketio = test_app - flask_client = app.test_client() - - self._add_batch(shared_state, 'batch_http') - - resp = flask_client.get('/api/download_status/batch?batch_ids=batch_http') - assert resp.status_code == 200 - data = resp.get_json() - assert 'batch_http' in data['batches'] - assert data['batches']['batch_http']['phase'] == 'downloading' - - -# ========================================================================= -# Group E — Fallback Behavior -# ========================================================================= - -class TestFallback: - """HTTP endpoints work when no WebSocket is connected.""" - - def test_http_works_without_websocket(self, flask_client): - """All three HTTP endpoints work without any WebSocket connection.""" - # Status - resp = flask_client.get('/status') - assert resp.status_code == 200 - data = resp.get_json() - assert data['spotify']['connected'] is True - - # Watchlist - resp = flask_client.get('/api/watchlist/count') - assert resp.status_code == 200 - data = resp.get_json() - assert data['count'] == 7 - - # Download batch (empty — no active batches) - resp = flask_client.get('/api/download_status/batch') - assert resp.status_code == 200 - data = resp.get_json() - assert data['batches'] == {} - def test_multiple_clients_get_updates(self, test_app, shared_state): """Multiple WebSocket clients each receive broadcast events.""" app, socketio = test_app diff --git a/tests/test_phase2_dashboard.py b/tests/test_phase2_dashboard.py index dc5ae65f..ed028110 100644 --- a/tests/test_phase2_dashboard.py +++ b/tests/test_phase2_dashboard.py @@ -21,16 +21,6 @@ import time class TestSystemStats: """dashboard:stats socket events match GET /api/system/stats.""" - def test_stats_event_received(self, test_app, shared_state): - """Client receives a dashboard:stats event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_system_stats'] - socketio.emit('dashboard:stats', build()) - received = client.get_received() - stats_events = [e for e in received if e['name'] == 'dashboard:stats'] - assert len(stats_events) >= 1 - def test_stats_shape(self, test_app, shared_state): """dashboard:stats event data has expected keys.""" app, socketio = test_app @@ -70,16 +60,6 @@ class TestSystemStats: assert ws_data['uptime'] == http_data['uptime'] assert ws_data['memory_usage'] == http_data['memory_usage'] - def test_http_stats_still_works(self, flask_client): - """GET /api/system/stats returns 200 with expected keys.""" - resp = flask_client.get('/api/system/stats') - assert resp.status_code == 200 - data = resp.get_json() - assert 'active_downloads' in data - assert 'finished_downloads' in data - assert 'download_speed' in data - - # ========================================================================= # Group B — Activity Feed # ========================================================================= @@ -87,16 +67,6 @@ class TestSystemStats: class TestActivityFeed: """dashboard:activity socket events match GET /api/activity/feed.""" - def test_activity_event_received(self, test_app, shared_state): - """Client receives a dashboard:activity event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_activity_feed_payload'] - socketio.emit('dashboard:activity', build()) - received = client.get_received() - events = [e for e in received if e['name'] == 'dashboard:activity'] - assert len(events) >= 1 - def test_activity_shape(self, test_app, shared_state): """dashboard:activity event data has activities array.""" app, socketio = test_app @@ -136,14 +106,6 @@ class TestActivityFeed: if ws_data['activities']: assert ws_data['activities'][0]['title'] == http_data['activities'][0]['title'] - def test_http_activity_still_works(self, flask_client): - """GET /api/activity/feed returns 200 with expected structure.""" - resp = flask_client.get('/api/activity/feed') - assert resp.status_code == 200 - data = resp.get_json() - assert 'activities' in data - - # ========================================================================= # Group C — Toasts (instant push) # ========================================================================= @@ -201,18 +163,6 @@ class TestToasts: assert 'show_toast' in data assert data['show_toast'] is True - def test_http_toasts_still_works(self, flask_client, shared_state): - """GET /api/activity/toasts returns 200 with expected structure.""" - # Add a toast-worthy activity first - add_item = shared_state['add_activity_item'] - add_item('', 'Test', 'Sub', show_toast=True) - - resp = flask_client.get('/api/activity/toasts') - assert resp.status_code == 200 - data = resp.get_json() - assert 'toasts' in data - - # ========================================================================= # Group D — DB Stats # ========================================================================= @@ -220,16 +170,6 @@ class TestToasts: class TestDbStats: """dashboard:db_stats socket events match GET /api/database/stats.""" - def test_db_stats_event_received(self, test_app, shared_state): - """Client receives a dashboard:db_stats event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_db_stats'] - socketio.emit('dashboard:db_stats', build()) - received = client.get_received() - events = [e for e in received if e['name'] == 'dashboard:db_stats'] - assert len(events) >= 1 - def test_db_stats_shape(self, test_app, shared_state): """dashboard:db_stats event data has expected keys.""" app, socketio = test_app @@ -266,16 +206,6 @@ class TestDbStats: assert ws_data['database_size_mb'] == http_data['database_size_mb'] assert ws_data['server_source'] == http_data['server_source'] - def test_http_db_stats_still_works(self, flask_client): - """GET /api/database/stats returns 200 with expected keys.""" - resp = flask_client.get('/api/database/stats') - assert resp.status_code == 200 - data = resp.get_json() - assert 'artists' in data - assert 'albums' in data - assert 'tracks' in data - - # ========================================================================= # Group E — Wishlist Count # ========================================================================= @@ -283,16 +213,6 @@ class TestDbStats: class TestWishlistCount: """dashboard:wishlist_count socket events match GET /api/wishlist/count.""" - def test_wishlist_count_received(self, test_app, shared_state): - """Client receives a dashboard:wishlist_count event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_wishlist_count_payload_ws'] - socketio.emit('dashboard:wishlist_count', build()) - received = client.get_received() - events = [e for e in received if e['name'] == 'dashboard:wishlist_count'] - assert len(events) >= 1 - def test_wishlist_count_shape(self, test_app, shared_state): """dashboard:wishlist_count event data has count key.""" app, socketio = test_app @@ -322,54 +242,6 @@ class TestWishlistCount: assert ws_data['count'] == http_data['count'] - def test_http_wishlist_count_still_works(self, flask_client): - """GET /api/wishlist/count returns 200 with count.""" - resp = flask_client.get('/api/wishlist/count') - assert resp.status_code == 200 - data = resp.get_json() - assert 'count' in data - assert isinstance(data['count'], int) - - -# ========================================================================= -# Group F — Backward Compatibility -# ========================================================================= - -class TestBackwardCompat: - """HTTP endpoints work when no WebSocket is connected.""" - - def test_all_http_endpoints_work_without_socket(self, flask_client): - """All 5 Phase 2 HTTP endpoints work without any WebSocket connection.""" - # System stats - resp = flask_client.get('/api/system/stats') - assert resp.status_code == 200 - data = resp.get_json() - assert data['active_downloads'] == 2 - - # Activity feed - resp = flask_client.get('/api/activity/feed') - assert resp.status_code == 200 - data = resp.get_json() - assert 'activities' in data - - # Toasts - resp = flask_client.get('/api/activity/toasts') - assert resp.status_code == 200 - data = resp.get_json() - assert 'toasts' in data - - # DB stats - resp = flask_client.get('/api/database/stats') - assert resp.status_code == 200 - data = resp.get_json() - assert data['artists'] == 350 - - # Wishlist count - resp = flask_client.get('/api/wishlist/count') - assert resp.status_code == 200 - data = resp.get_json() - assert data['count'] == 5 - def test_multiple_clients_get_dashboard_updates(self, test_app, shared_state): """Multiple WebSocket clients each receive dashboard broadcast events.""" app, socketio = test_app diff --git a/tests/test_phase3_enrichment.py b/tests/test_phase3_enrichment.py index 321f47a7..73d77942 100644 --- a/tests/test_phase3_enrichment.py +++ b/tests/test_phase3_enrichment.py @@ -39,19 +39,6 @@ ENDPOINTS = { class TestEnrichmentEventDelivery: """enrichment: socket events are received by the client.""" - @pytest.mark.parametrize('worker', WORKERS) - def test_enrichment_event_received(self, test_app, shared_state, worker): - """Client receives an enrichment: event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_enrichment_status'] - - socketio.emit(f'enrichment:{worker}', build(worker)) - received = client.get_received() - events = [e for e in received if e['name'] == f'enrichment:{worker}'] - assert len(events) >= 1 - - # ========================================================================= # Group B — Data Shape (parameterized) # ========================================================================= @@ -160,38 +147,11 @@ class TestEnrichmentHttpParity: # ========================================================================= -# Group D — HTTP Still Works (parameterized) -# ========================================================================= - -class TestEnrichmentHttpStillWorks: - """HTTP endpoints return 200 with expected structure.""" - - @pytest.mark.parametrize('worker', WORKERS) - def test_http_enrichment_still_works(self, flask_client, worker): - """GET /api//status returns 200.""" - endpoint = ENDPOINTS[worker] - resp = flask_client.get(endpoint) - assert resp.status_code == 200 - data = resp.get_json() - assert 'running' in data - assert 'paused' in data - - -# ========================================================================= -# Group E — Backward Compatibility +# Group D — Backward Compatibility # ========================================================================= class TestEnrichmentBackwardCompat: - """HTTP endpoints work when no WebSocket is connected.""" - - def test_all_http_endpoints_work_without_socket(self, flask_client): - """All 7 enrichment HTTP endpoints work without any WebSocket connection.""" - for worker in WORKERS: - endpoint = ENDPOINTS[worker] - resp = flask_client.get(endpoint) - assert resp.status_code == 200 - data = resp.get_json() - assert data['running'] is True + """WebSocket clients still receive broadcast enrichment updates.""" def test_multiple_clients_get_enrichment_updates(self, test_app, shared_state): """Multiple WebSocket clients each receive enrichment events.""" diff --git a/tests/test_phase4_tools.py b/tests/test_phase4_tools.py index 7d0608fd..d23dc765 100644 --- a/tests/test_phase4_tools.py +++ b/tests/test_phase4_tools.py @@ -38,19 +38,6 @@ ENDPOINTS = { class TestToolEventDelivery: """tool: socket events are received by the client.""" - @pytest.mark.parametrize('tool', TOOLS) - def test_tool_event_received(self, test_app, shared_state, tool): - """Client receives a tool: event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_tool_status'] - - socketio.emit(f'tool:{tool}', build(tool)) - received = client.get_received() - events = [e for e in received if e['name'] == f'tool:{tool}'] - assert len(events) >= 1 - - # ========================================================================= # Group B — Data Shape (individual per tool) # ========================================================================= @@ -255,41 +242,11 @@ class TestToolHttpParity: # ========================================================================= -# Group D — HTTP Still Works (parameterized) -# ========================================================================= - -class TestToolHttpStillWorks: - """HTTP endpoints return 200 with expected structure.""" - - @pytest.mark.parametrize('tool', TOOLS) - def test_http_tool_still_works(self, flask_client, tool): - """GET /api//status returns 200.""" - endpoint = ENDPOINTS[tool] - resp = flask_client.get(endpoint) - assert resp.status_code == 200 - data = resp.get_json() - if tool == 'logs': - assert 'logs' in data - elif tool == 'metadata': - assert 'success' in data - assert 'status' in data - else: - assert 'status' in data - - -# ========================================================================= -# Group E — Backward Compatibility +# Group D — Backward Compatibility # ========================================================================= class TestToolBackwardCompat: - """HTTP endpoints work when no WebSocket is connected.""" - - def test_all_http_endpoints_work_without_socket(self, flask_client): - """All 7 tool HTTP endpoints work without any WebSocket connection.""" - for tool in TOOLS: - endpoint = ENDPOINTS[tool] - resp = flask_client.get(endpoint) - assert resp.status_code == 200 + """WebSocket clients still receive broadcast tool updates.""" def test_multiple_clients_get_tool_updates(self, test_app, shared_state): """Multiple WebSocket clients each receive tool events.""" diff --git a/tests/test_phase5_sync.py b/tests/test_phase5_sync.py index 7911fee1..71cfd6d5 100644 --- a/tests/test_phase5_sync.py +++ b/tests/test_phase5_sync.py @@ -29,28 +29,6 @@ SYNC_PLAYLIST_IDS = ['test-playlist-1'] class TestSyncEventDelivery: """sync:progress socket events are received by subscribed clients.""" - - def test_sync_event_received(self, test_app, shared_state): - """Client subscribes and receives sync:progress event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_sync_status'] - - # Subscribe to sync room - client.emit('sync:subscribe', {'playlist_ids': ['test-playlist-1']}) - - # Server emits to the room - socketio.emit('sync:progress', { - 'playlist_id': 'test-playlist-1', - **build('test-playlist-1') - }, room='sync:test-playlist-1') - - received = client.get_received() - events = [e for e in received if e['name'] == 'sync:progress'] - assert len(events) >= 1 - - client.disconnect() - def test_sync_only_subscribed(self, test_app, shared_state): """Unsubscribed client does NOT receive sync:progress events.""" app, socketio = test_app @@ -155,30 +133,6 @@ class TestSyncDataShape: class TestDiscoveryEventDelivery: """discovery:progress socket events are received by subscribed clients.""" - - @pytest.mark.parametrize('platform,pid', [ - ('tidal', 'test-tidal-1'), - ('youtube', 'test-yt-hash'), - ]) - def test_discovery_event_received(self, test_app, shared_state, platform, pid): - """Client subscribes and receives discovery:progress event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_discovery_status'] - - client.emit('discovery:subscribe', {'ids': [pid]}) - - payload = build(platform, pid) - payload['platform'] = platform - payload['id'] = pid - socketio.emit('discovery:progress', payload, room=f'discovery:{pid}') - - received = client.get_received() - events = [e for e in received if e['name'] == 'discovery:progress'] - assert len(events) >= 1 - - client.disconnect() - def test_discovery_only_subscribed(self, test_app, shared_state): """Unsubscribed client does NOT receive discovery:progress events.""" app, socketio = test_app @@ -281,24 +235,6 @@ class TestDiscoveryDataShape: class TestScanEventDelivery: """Broadcast scan events are received by all connected clients.""" - - def test_watchlist_scan_received(self, test_app, shared_state): - """All clients receive scan:watchlist event.""" - app, socketio = test_app - client1 = socketio.test_client(app) - client2 = socketio.test_client(app) - build = shared_state['build_watchlist_scan_status'] - - socketio.emit('scan:watchlist', build()) - - for client in [client1, client2]: - received = client.get_received() - events = [e for e in received if e['name'] == 'scan:watchlist'] - assert len(events) >= 1 - - client1.disconnect() - client2.disconnect() - def test_watchlist_scan_shape(self, test_app, shared_state): """scan:watchlist data has success, status, current_artist_name.""" app, socketio = test_app @@ -321,23 +257,6 @@ class TestScanEventDelivery: client.disconnect() - def test_media_scan_received(self, test_app, shared_state): - """All clients receive scan:media event.""" - app, socketio = test_app - client1 = socketio.test_client(app) - client2 = socketio.test_client(app) - build = shared_state['build_media_scan_status'] - - socketio.emit('scan:media', build()) - - for client in [client1, client2]: - received = client.get_received() - events = [e for e in received if e['name'] == 'scan:media'] - assert len(events) >= 1 - - client1.disconnect() - client2.disconnect() - def test_media_scan_shape(self, test_app, shared_state): """scan:media data has success and status with is_scanning.""" app, socketio = test_app @@ -491,33 +410,11 @@ class TestScanHttpParity: class TestHttpStillWorks: """HTTP endpoints return 200 with expected structure.""" - - def test_sync_http_works(self, flask_client): - """GET /api/sync/status/:id returns 200.""" - resp = flask_client.get('/api/sync/status/test-playlist-1') - assert resp.status_code == 200 - data = resp.get_json() - assert 'status' in data - assert 'progress' in data - def test_sync_http_404_unknown(self, flask_client): """GET /api/sync/status/:id returns 404 for unknown playlist.""" resp = flask_client.get('/api/sync/status/nonexistent') assert resp.status_code == 404 - @pytest.mark.parametrize('platform,endpoint', [ - ('tidal', '/api/tidal/discovery/status/test-tidal-1'), - ('youtube', '/api/youtube/discovery/status/test-yt-hash'), - ]) - def test_discovery_http_works(self, flask_client, platform, endpoint): - """GET /api//discovery/status/:id returns 200.""" - resp = flask_client.get(endpoint) - assert resp.status_code == 200 - data = resp.get_json() - assert 'phase' in data - assert 'status' in data - assert 'results' in data - def test_discovery_http_not_found(self, flask_client): """GET /api/tidal/discovery/status/:id returns error for unknown ID.""" resp = flask_client.get('/api/tidal/discovery/status/nonexistent') @@ -525,42 +422,12 @@ class TestHttpStillWorks: data = resp.get_json() assert 'error' in data - def test_watchlist_scan_http_works(self, flask_client): - """GET /api/watchlist/scan/status returns 200.""" - resp = flask_client.get('/api/watchlist/scan/status') - assert resp.status_code == 200 - data = resp.get_json() - assert data['success'] is True - assert 'status' in data - - def test_media_scan_http_works(self, flask_client): - """GET /api/scan/status returns 200.""" - resp = flask_client.get('/api/scan/status') - assert resp.status_code == 200 - data = resp.get_json() - assert data['success'] is True - assert 'status' in data - - # ========================================================================= -# Group H — Backward Compatibility +# Group H — Broadcast Updates # ========================================================================= class TestBackwardCompat: - """HTTP endpoints work when no WebSocket is connected.""" - - def test_all_http_endpoints_work_without_socket(self, flask_client): - """All Phase 5 HTTP endpoints work without any WebSocket connection.""" - endpoints = [ - '/api/sync/status/test-playlist-1', - '/api/tidal/discovery/status/test-tidal-1', - '/api/youtube/discovery/status/test-yt-hash', - '/api/watchlist/scan/status', - '/api/scan/status', - ] - for endpoint in endpoints: - resp = flask_client.get(endpoint) - assert resp.status_code == 200 + """Broadcast scan events still reach multiple clients.""" def test_multiple_clients_get_scan_updates(self, test_app, shared_state): """Multiple WebSocket clients each receive scan events.""" @@ -668,29 +535,6 @@ PLATFORM_SYNC_IDS = [ class TestPlatformSyncEventDelivery: """Platform sync pollers receive sync:progress via WS rooms.""" - - @pytest.mark.parametrize('platform,sync_id', PLATFORM_SYNC_IDS) - def test_platform_sync_event_received(self, test_app, shared_state, platform, sync_id): - """Client subscribes to platform sync_playlist_id and receives sync:progress.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_sync_status'] - - client.emit('sync:subscribe', {'playlist_ids': [sync_id]}) - - socketio.emit('sync:progress', { - 'playlist_id': sync_id, **build(sync_id) - }, room=f'sync:{sync_id}') - - received = client.get_received() - events = [e for e in received if e['name'] == 'sync:progress'] - assert len(events) >= 1 - data = events[0]['args'][0] - assert data['playlist_id'] == sync_id - assert data['status'] == 'syncing' - - client.disconnect() - @pytest.mark.parametrize('platform,sync_id', PLATFORM_SYNC_IDS) def test_platform_sync_not_received_when_unsubscribed( self, test_app, shared_state, platform, sync_id): @@ -796,35 +640,12 @@ class TestPlatformSyncEventDelivery: client.disconnect() - @pytest.mark.parametrize('platform,sync_id', PLATFORM_SYNC_IDS) - def test_platform_sync_http_still_works(self, flask_client, platform, sync_id): - """GET /api/sync/status/ returns 200.""" - resp = flask_client.get(f'/api/sync/status/{sync_id}') - assert resp.status_code == 200 - data = resp.get_json() - assert 'status' in data - assert 'progress' in data - - # ========================================================================= # Group H — Wishlist Stats (broadcast) # ========================================================================= class TestWishlistStatsEventDelivery: """wishlist:stats broadcast events are received by the client.""" - - def test_wishlist_stats_event_received(self, test_app, shared_state): - """Client receives a wishlist:stats event.""" - app, socketio = test_app - client = socketio.test_client(app) - build = shared_state['build_wishlist_stats'] - - socketio.emit('wishlist:stats', build()) - received = client.get_received() - events = [e for e in received if e['name'] == 'wishlist:stats'] - assert len(events) >= 1 - client.disconnect() - def test_wishlist_stats_data_shape(self, test_app, shared_state): """wishlist:stats has is_auto_processing and next_run_in_seconds.""" app, socketio = test_app @@ -843,14 +664,6 @@ class TestWishlistStatsEventDelivery: assert isinstance(data['next_run_in_seconds'], (int, float)) client.disconnect() - def test_wishlist_stats_http_still_works(self, flask_client): - """GET /api/wishlist/stats returns 200 with expected keys.""" - resp = flask_client.get('/api/wishlist/stats') - assert resp.status_code == 200 - data = resp.get_json() - assert 'is_auto_processing' in data - assert 'next_run_in_seconds' in data - def test_wishlist_stats_auto_processing_detection(self, test_app, shared_state): """When is_auto_processing is True, client detects it.""" app, socketio = test_app