video_monitor/tests/test_local_webcam.py
2026-08-30 22:23:12 +08:00

60 lines
3.2 KiB
Python

import configparser
import socket
import unittest
from types import SimpleNamespace
from unittest import mock
import psutil
from scripts import local_webcam as webcam
class LocalWebcamTests(unittest.TestCase):
def test_config_disables_audio_recording_and_other_protocols(self):
config = webcam.make_config('[hook]\non_server_started=http://remote/\n[protocol]\nenable_mp4=1\n',
'test-secret', 'http://127.0.0.1:12345/publish/test')
self.assertEqual(config['general']['listen_ip'], '127.0.0.1')
for name in ('enable_audio', 'add_mute_audio', 'enable_mp4', 'enable_hls', 'enable_hls_fmp4'):
self.assertEqual(config['protocol'][name], '0')
for section in ('rtc', 'rtp_proxy', 'srt', 'shell', 'onvif'):
self.assertEqual(config[section]['port'], '0')
self.assertNotIn('on_server_started', config['hook'])
self.assertEqual(config['rtsp']['rtpTransportType'], '0')
self.assertEqual(config['ffmpeg']['bin'], '')
def test_command_is_video_only_and_fixed_loopback_destination(self):
command = webcam.capture_command('ffmpeg.exe')
self.assertIn('-an', command)
self.assertEqual(command[command.index('-i') + 1], 'video=Integrated Camera')
self.assertEqual(command[command.index('-map') + 1], '0:v:0')
self.assertEqual(command[-1], 'rtmp://127.0.0.1:10935/live/laptop_cam')
self.assertNotIn('audio=', ' '.join(command))
def test_publish_gate_rejects_other_streams_and_remote_publishers(self):
data = {'app': 'live', 'stream': 'laptop_cam', 'schema': 'rtmp', 'ip': '127.0.0.1'}
self.assertTrue(webcam.allowed_publish(data))
for key, value in [('stream', 'other'), ('ip', '192.168.1.2'), ('app', 'rtp'), ('schema', 'rtsp')]:
self.assertFalse(webcam.allowed_publish({**data, key: value}))
def test_network_guard_rejects_exposure_udp_and_outbound_connections(self):
proc = mock.Mock()
local = SimpleNamespace(ip='127.0.0.1', port=10935)
good = SimpleNamespace(type=socket.SOCK_STREAM, laddr=local, raddr=(), status=psutil.CONN_LISTEN)
proc.connections.return_value = [good]
self.assertEqual(webcam.check_connections([proc], {10935}), {10935})
proc.connections.return_value = [SimpleNamespace(
type=socket.SOCK_STREAM, laddr=SimpleNamespace(ip='::1', port=60001),
raddr=SimpleNamespace(ip='::1', port=60002), status=psutil.CONN_ESTABLISHED)]
self.assertEqual(webcam.check_connections([proc], {10935}), set())
for bad in [dict(type=socket.SOCK_DGRAM),
dict(laddr=SimpleNamespace(ip='0.0.0.0', port=10935)),
dict(raddr=SimpleNamespace(ip='8.8.8.8', port=443))]:
proc.connections.return_value = [SimpleNamespace(**{**vars(good), **bad})]
with self.assertRaises(RuntimeError):
webcam.check_connections([proc], {10935})
def test_webcam_does_not_bootstrap_full_service_manager(self):
source = webcam.SCRIPT.read_text(encoding='utf-8')
self.assertNotIn('get_service_manager().start()', source)
self.assertNotIn('shell=True', source)
self.assertIn('ServiceLeaderLock()', source)