Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
87 lines
5.7 KiB
Python
87 lines
5.7 KiB
Python
import importlib.util
|
|
import os
|
|
from pathlib import Path
|
|
import tempfile
|
|
import time
|
|
import unittest
|
|
|
|
WIN = Path(__file__).resolve().parents[1]
|
|
ROOT = WIN.parent
|
|
|
|
def load(name, path):
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
|
|
return m
|
|
|
|
shim = load('nvenc', WIN / 'ffmpeg-nvenc.py')
|
|
worker = load('nvenc_worker', WIN / 'pt-worker-nvenc.py')
|
|
linux = load('linux_worker', ROOT / 'pt-worker.py')
|
|
PROBE = {'streams': [{'codec_type': 'video', 'codec_name': 'h264', 'pix_fmt': 'yuv420p', 'width': 1920, 'height': 1080}], 'format': {'duration': '10'}}
|
|
|
|
class AdapterTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.temp = tempfile.TemporaryDirectory(); self.old = shim.STATE
|
|
shim.STATE = Path(self.temp.name)
|
|
def tearDown(self):
|
|
shim.STATE = self.old; self.temp.cleanup()
|
|
def test_runner_default_becomes_nvdec_cuda_scale_nvenc(self):
|
|
args, info = shim.rewrite(['-i','source.mp4','-vcodec','libx264','-vf','scale=w=-2:h=720','-pix_fmt','yuv420p','-preset','veryfast','-maxrate:v','2000000','-bufsize:v','4000000','-b_strategy','1','-bf','16','-g:v','60','-r','30','-c:a','aac','-movflags','faststart','-f','mp4','out.mp4'], PROBE)
|
|
self.assertIn('h264_nvenc', args); self.assertIn('cuda', args)
|
|
self.assertIn('scale_cuda=w=1280:h=720:format=nv12', args)
|
|
self.assertIn('p4', args); self.assertNotIn('libx264', args)
|
|
self.assertNotIn('-b_strategy', args); self.assertEqual(info['target_height'],720)
|
|
def test_unknown_args_aliases_codecs_filters_and_extra_outputs_refused(self):
|
|
base=['-i','a','-c:v','libx264']
|
|
for extra in (['-unknown','1'],['-c:v:0','libx264'],['-c','libx264'],['-filter_complex','null'],['-vf','scale=640:360,eq=contrast=2'],['-hwaccel','none'],['-x264-params','no-scenecut=1'],['other.mp4'],['-c:v','libx265']):
|
|
with self.subTest(extra=extra),self.assertRaises(ValueError):
|
|
shim.rewrite(base+extra+['out'],PROBE)
|
|
def test_source_rotation_hdr_unknown_codec_refused(self):
|
|
for change in ({'codec_name':'mpeg4'},{'side_data_list':[{'rotation':90}]},{'color_transfer':'smpte2084'}):
|
|
p={**PROBE,'streams':[{**PROBE['streams'][0],**change}]}
|
|
with self.assertRaises(ValueError):shim.rewrite(['-i','a','-c:v','libx264','out'],p)
|
|
def test_hevc_sdr_source_cuda_decode(self):
|
|
p={**PROBE,'streams':[{**PROBE['streams'][0],'codec_name':'hevc','pix_fmt':'yuv420p10le'}]}
|
|
args,_=shim.rewrite(['-i','a','-c:v','libx264','out'],p)
|
|
self.assertIn('h264_nvenc',args);self.assertIn('cuda',args)
|
|
def test_hevc_target_is_hardware_only_and_unknown_target_refused(self):
|
|
old=shim.TARGET
|
|
try:
|
|
shim.TARGET='hevc_nvenc'
|
|
args,info=shim.rewrite(['-i','a','-c:v','libx264','out'],PROBE)
|
|
self.assertIn('hevc_nvenc',args);self.assertEqual(info['target_codec'],'hevc')
|
|
shim.TARGET='libx265'
|
|
with self.assertRaises(ValueError):shim.rewrite(['-i','a','-c:v','libx264','out'],PROBE)
|
|
finally:shim.TARGET=old
|
|
def test_gpu_unavailable_marker_refuses_video_and_remux(self):
|
|
(shim.STATE/'gpu-unavailable').touch()
|
|
for args in (['-i','a','-c:v','libx264','out'],['-i','a','-c','copy','out']):
|
|
with self.assertRaises(ValueError):shim.rewrite(args,PROBE)
|
|
def test_queries_audio_and_copy_are_explicit(self):
|
|
for args in (['-version'],['-encoders'],['-i','a','-vn','-c:a','aac','out'],['-i','a','-c','copy','out']):
|
|
out,info=shim.rewrite(args,PROBE);self.assertEqual(out,args);self.assertIsNone(info)
|
|
with self.assertRaises(ValueError):shim.rewrite(['-i','a','-vn','-c:v','libx264','out'],PROBE)
|
|
|
|
class AdmissionTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.temp=tempfile.TemporaryDirectory();self.old=(linux.STATE,worker.STATE)
|
|
linux.STATE=worker.STATE=Path(self.temp.name);self.now=time.time()
|
|
def tearDown(self):linux.STATE,worker.STATE=self.old;self.temp.cleanup()
|
|
def test_linux_windows_decisions_match_for_entire_sequence(self):
|
|
overrides=[{}, {}, {}, {'active_jobs':2}, {'on_ac':False}, {'on_ac':None}, {}, {}, {}, {'temperature_c':90}, {'temperature_c':50}, {'gpu_ready':False}, {'disk_free_bytes':0}, {'network_ok':False}, {'tailscale_path':'DERP'}]
|
|
traces=[]
|
|
for mod in (linux,worker):
|
|
meter=mod.Meter();policy=mod.Admission({})
|
|
for d in ('download','upload'):meter.consume({'kind':'transfer','time':self.now,'ok':True,'direction':d,'bytes':10_000_000,'seconds':1})
|
|
trace=[]
|
|
for i,o in enumerate(overrides):
|
|
sample={'tailscale_path':'direct','latency_ms':5,'network_ok':True,'registered':True,'gpu_ready':True,'gpu_accessible':True,'gpu_tested_at':self.now,'on_ac':True,'disk_free_bytes':100*1024**3,'temperature_c':50,'throttle_counts':{},'active_jobs':0,**o}
|
|
trace.append(policy.decide(sample,meter,{'paused':False},self.now+i*130))
|
|
traces.append(trace)
|
|
self.assertEqual(traces[0],traces[1]);self.assertEqual(traces[0][:6],['NETWORK_DEGRADED','NETWORK_DEGRADED','AVAILABLE','BUSY','DRAINING','DRAINING'])
|
|
def test_gpu_failure_latched_until_later_proof(self):
|
|
policy=worker.Admission({});meter=worker.Meter()
|
|
meter.consume({'kind':'gpu_failure','time':self.now+1})
|
|
sample={'tailscale_path':'direct','latency_ms':1,'network_ok':True,'registered':True,'gpu_ready':True,'gpu_accessible':True,'gpu_tested_at':self.now,'on_ac':True,'disk_free_bytes':100*1024**3,'temperature_c':None,'throttle_counts':{},'active_jobs':0}
|
|
self.assertEqual(policy.decide(sample,meter,{'paused':False},self.now+2),'GPU_UNAVAILABLE')
|
|
|
|
if __name__=='__main__':unittest.main()
|