def test_simple(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), STILL_PLUGIN_NAME: ProcessPack(camera=StillPlugin) } with ProcessesHost(plugins): pass
def test_take_motion_image(self): plugins = { MOTION_DETECTOR_PLUGIN_NAME: ProcessPack(camera=MotionDetectorCameraPlugin), PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), 'InjectDemoData': ProcessPack(camera=InjectDemoData), ControlledMediaReceiver.plugin_name(): ProcessPack(camera=ControlledMediaReceiver), MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(camera=MediaManagerPlugin) } with ProcessesHost(plugins) as host: injector = host.plugin_instances['InjectDemoData'].camera detector = host.plugin_instances[ MOTION_DETECTOR_PLUGIN_NAME].camera media_rcv = host.plugin_instances[ ControlledMediaReceiver.plugin_name()].camera injector.wait_for_completion() detector.take_motion_picture(123) self.retry_until_timeout(lambda: media_rcv.media is not None) self.assertTrue(os.path.isfile(media_rcv.media.path)) self.assertEqual(media_rcv.media.kind, 'jpeg') self.assertEqual(media_rcv.media.info, 123) media_rcv.let_media_go() self.retry_until_timeout( lambda: not os.path.isfile(media_rcv.media.path))
def test_media_dispatch(self): plugins = { ControlledMediaReceiver.plugin_name(): ProcessPack(main=ControlledMediaReceiver), MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(main=RemoteMediaManager) } with ProcessesHost(plugins) as phost: with tempfile.NamedTemporaryFile(delete=False) as media_file: path = media_file.name media_mgr = phost.plugin_instances[MEDIA_MANAGER_PLUGIN_NAME].main media_rcv = phost.plugin_instances[ ControlledMediaReceiver.plugin_name()].main media_mgr.test_deliver_media(path, 'mp4', 45) # Make sure it gets delivered if self.retry_until_timeout(lambda: media_rcv.media is not None): self.assertTrue(os.path.isfile(path)) self.assertEqual(media_rcv.media.path, path) self.assertEqual(media_rcv.media.kind, 'mp4') self.assertEqual(media_rcv.media.info, 45) self.assertEqual(media_rcv.media.owning_process, Process.MAIN) time.sleep(0.5) self.assertTrue(os.path.isfile(path)) media_rcv.let_media_go() self.retry_until_timeout(lambda: not os.path.isfile(path))
def test_runs_with_demo_data(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), BUFFERED_RECORDER_PLUGIN_NAME: ProcessPack(camera=BufferedRecorderPlugin), 'InjectDemoData': ProcessPack(camera=InjectDemoData) } with ProcessesHost(plugins) as host: injector = host.plugin_instances['InjectDemoData'].camera buffered_recorder = host.plugin_instances[ BUFFERED_RECORDER_PLUGIN_NAME].camera buffered_recorder.record(12345) self.assertTrue(buffered_recorder.is_recording) injector.wait_for_completion() self.assertGreater(buffered_recorder.footage_age, 0) buffered_recorder.stop_and_discard() buffered_recorder.record(54321) injector.replay() # Wait until the buffer is cleared self.retry_until_footage_age_changes(buffered_recorder) # Wait until at least one frame is recorded self.retry_until_footage_age_changes(buffered_recorder) self.assertTrue(buffered_recorder.is_recording) self.assertGreater(buffered_recorder.footage_age, 0) buffered_recorder.stop_and_finalize() self.assertTrue(buffered_recorder.is_finalizing) injector.wait_for_completion()
def test_simple(self): with ProcessesHost( {MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(main=RemoteMediaManager)}) as phost: self.assertIn(MEDIA_MANAGER_PLUGIN_NAME, phost.plugin_instances) self.assertIsNotNone( phost.plugin_instances[MEDIA_MANAGER_PLUGIN_NAME].main)
def test_dispatches_media(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), BUFFERED_RECORDER_PLUGIN_NAME: ProcessPack(camera=BufferedRecorderPlugin), 'InjectDemoData': ProcessPack(camera=InjectDemoData), ControlledMediaReceiver.plugin_name(): ProcessPack(camera=ControlledMediaReceiver), MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(camera=MediaManagerPlugin) } with ProcessesHost(plugins) as host: injector = host.plugin_instances['InjectDemoData'].camera buffered_recorder = host.plugin_instances[ BUFFERED_RECORDER_PLUGIN_NAME].camera media_rcv = host.plugin_instances[ ControlledMediaReceiver.plugin_name()].camera buffered_recorder.record(12345) injector.wait_for_completion() buffered_recorder.stop_and_discard() buffered_recorder.record(54321) injector.replay() injector.wait_for_completion() buffered_recorder.stop_and_finalize() self.assertTrue(os.path.isfile(media_rcv.media.path)) self.assertEqual(media_rcv.media.kind, 'mp4') self.assertEqual(media_rcv.media.info, 54321) media_rcv.let_media_go() self.retry_until_timeout( lambda: not os.path.isfile(media_rcv.media.path))
def test_runs_with_demo_data(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), STILL_PLUGIN_NAME: ProcessPack(camera=StillPlugin) } with ProcessesHost(plugins) as host: still = host.plugin_instances[STILL_PLUGIN_NAME].camera still.take_picture()
def test_simple(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), BUFFERED_RECORDER_PLUGIN_NAME: ProcessPack(camera=BufferedRecorderPlugin) } with ProcessesHost(plugins): pass
def test_file_deletion(self): with ProcessesHost( {MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(main=RemoteMediaManager)}) as phost: with tempfile.NamedTemporaryFile(delete=False) as media_file: path = media_file.name assert os.path.isfile(path) phost.plugin_instances[ MEDIA_MANAGER_PLUGIN_NAME].main.test_deliver_media(path, None) self.retry_until_timeout(lambda: not os.path.isfile(path))
def test_with_another_plugin(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), 'TestCam': ProcessPack(camera=TestCam) } with ProcessesHost(plugins) as host: picamera_plugin = host.plugin_instances[ PICAMERA_ROOT_PLUGIN_NAME].camera testcam_plugin = host.plugin_instances['TestCam'].camera # Test that they agree on who is who self.assertEqual(picamera_plugin.get_remote_id(), testcam_plugin.get_picamera_root_plugin_id())
def test_with_demo_data(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), 'TestCam': ProcessPack(camera=TestCam), 'InjectDemoData': ProcessPack(camera=InjectDemoData) } with ProcessesHost(plugins) as host: injector = host.plugin_instances['InjectDemoData'].camera test_cam_plugin = host.plugin_instances['TestCam'].camera injector.wait_for_completion() self.assertGreater(test_cam_plugin.num_writes, 0) self.assertGreater(test_cam_plugin.num_flushes, 0) self.assertGreater(test_cam_plugin.num_analysis, 0)
def test_simple(self): plugins = { MOTION_DETECTOR_PLUGIN_NAME: ProcessPack(camera=MotionDetectorCameraPlugin, main=MotionDetectorDispatcherPlugin), PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), 'InjectDemoData': ProcessPack(camera=InjectDemoData) } with ProcessesHost(plugins) as host: injector = host.plugin_instances['InjectDemoData'].camera injector.wait_for_completion()
def test_process_host(self): with ProcessesHost({ k: v for k, v in get_all_plugins().items() if k == 'TestPluginDecorator' }) as processes: self.assertIn('TestPluginDecorator', processes.plugin_instances) instance_pack = processes.plugin_instances['TestPluginDecorator'] for process, instance in instance_pack.items(): if process is Process.MAIN: self.assertIsNotNone(instance) self.assertEqual(instance.get_two(), 2) else: self.assertIsNone(instance)
def test_rewinds(self): # Identify the max age of a split point max_sps_age = 0 age = 0 for evt in InjectDemoData.DEMO_DATA['events']: # pragma: no cover if evt.frame is None: continue elif evt.frame.frame_type == PiVideoFrameType.sps_header: max_sps_age = max(max_sps_age, age) age = 0 elif evt.frame.frame_type == PiVideoFrameType.key_frame or evt.frame.frame_type == PiVideoFrameType.frame: age += 1 # We will play in a loop max_sps_age = max(age, max_sps_age) self.assertGreater(max_sps_age, 0) del age plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), BUFFERED_RECORDER_PLUGIN_NAME: ProcessPack(camera=BufferedRecorderPlugin), 'InjectDemoData': ProcessPack(camera=InjectDemoData) } with ProcessesHost(plugins) as host: buffered_recorder = host.plugin_instances[ BUFFERED_RECORDER_PLUGIN_NAME].camera # Patch the recorder to prevent frames to get too old buffered_recorder.sps_header_max_age = max_sps_age / 2 buffered_recorder.buffer_max_age = max_sps_age / 2 injector = host.plugin_instances['InjectDemoData'].camera max_buffer_age = 0 max_footage_age = 0 while not injector.wait_for_completion(0.1): max_buffer_age = max(buffered_recorder.buffer_age, max_buffer_age) max_footage_age = max(buffered_recorder.buffer_age, max_footage_age) injector.replay() while not injector.wait_for_completion(0.1): max_buffer_age = max(buffered_recorder.buffer_age, max_buffer_age) max_footage_age = max(buffered_recorder.buffer_age, max_footage_age) # On average we must not exceed by that much the max allowed buffer length self.assertLessEqual(max_buffer_age, buffered_recorder.total_age) self.assertLessEqual(max_footage_age, buffered_recorder.total_age) self.assertLessEqual(max_buffer_age, max_sps_age) self.assertLessEqual(max_footage_age, max_sps_age)
def test_intra_instance_talk(self): plugins = { 'main': ProcessPack(TestPluginProcess.TestProcess, TestPluginProcess.TestProcess, TestPluginProcess.TestProcess) } with ProcessesHost(plugins) as processes: instance_pack = processes.plugin_instances['main'] pid_sets = list( [instance.get_sibling_pid_set() for instance in instance_pack]) self.assertEqual(len(pid_sets), len(AVAILABLE_PROCESSES)) if len(pid_sets) > 0: for pid_set in pid_sets[1:]: self.assertEqual(pid_set, pid_sets[0])
def test_spurious_consume_calls(self): plugins = { MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(main=MediaManagerPlugin) } dummy_media = Media(UUID('4b878c8a-de5a-402b-9f9b-127f5a3a78de'), Process.MAIN, None, None, None) with ProcessesHost(plugins) as phost: media_mgr = phost.plugin_instances[MEDIA_MANAGER_PLUGIN_NAME].main # Nothing should happen here media_mgr.consume_media(dummy_media, Process.MAIN) media_mgr.consume_media(dummy_media, Process.CAMERA) another_dummy_media = Media(dummy_media.uuid, Process.TELEGRAM, None, None, None) media_mgr.consume_media(another_dummy_media, Process.TELEGRAM) media_mgr.consume_media(another_dummy_media, Process.MAIN) media_mgr.consume_media(another_dummy_media, Process.CAMERA)
def test_process_host(self): plugins = { TestPluginProcess.TestProcess.PLUGIN_NAME: ProcessPack(TestPluginProcess.TestProcess, TestPluginProcess.TestProcess, TestPluginProcess.TestProcess) } with ProcessesHost(plugins) as processes: self.assertIn('main', processes.plugin_instances) instance_pack = processes.plugin_instances['main'] for process, instance in instance_pack.items(): self.assertIsNotNone(instance) if instance is not None: process_in_instance = instance.get_remote_process() pid_in_instance = instance.get_remote_pid() self.assertIsNotNone(process_in_instance) self.assertIsNotNone(pid_in_instance) self.assertNotEqual(pid_in_instance, os.getpid()) # Need to explicitly convert because the serialization engine may not preserve the Enum self.assertEqual(Process(process_in_instance), process)
def test_manual_dispatch(self): plugins = { ControlledMediaReceiver.plugin_name(): ProcessPack(main=ControlledMediaReceiver), MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(main=MediaManagerPlugin) } dummy_media = Media(UUID('4b878c8a-de5a-402b-9f9b-127f5a3a78de'), Process.CAMERA, 'KIND', 'PATH', 'INFO') with ProcessesHost(plugins) as phost: media_mgr = phost.plugin_instances[MEDIA_MANAGER_PLUGIN_NAME].main media_rcv = phost.plugin_instances[ ControlledMediaReceiver.plugin_name()].main media_mgr.dispatch_media(dummy_media) # Make sure it gets delivered if self.retry_until_timeout(lambda: media_rcv.media is not None): self.assertEqual(media_rcv.media.path, 'PATH') self.assertEqual(media_rcv.media.kind, 'KIND') self.assertEqual(media_rcv.media.info, 'INFO') self.assertEqual(media_rcv.media.owning_process, Process.CAMERA) media_rcv.let_media_go()
def test_dispatches_media(self): plugins = { PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), STILL_PLUGIN_NAME: ProcessPack(camera=StillPlugin), ControlledMediaReceiver.plugin_name(): ProcessPack(camera=ControlledMediaReceiver), MEDIA_MANAGER_PLUGIN_NAME: ProcessPack(camera=MediaManagerPlugin) } with ProcessesHost(plugins) as host: media_rcv = host.plugin_instances[ ControlledMediaReceiver.plugin_name()].camera still = host.plugin_instances[STILL_PLUGIN_NAME].camera still.take_picture(123) self.retry_until_timeout(lambda: media_rcv.media is not None) self.assertTrue(os.path.isfile(media_rcv.media.path)) self.assertEqual(media_rcv.media.kind, 'jpeg') self.assertEqual(media_rcv.media.info, 123) media_rcv.let_media_go() self.retry_until_timeout( lambda: not os.path.isfile(media_rcv.media.path))
def main(args): if args.token: SETTINGS.telegram.token = args.token if args.logfile is not None: logging.info('Switching over to logging to %s', args.logfile) ensure_logging_setup(logging.DEBUG if args.verbose else logging.INFO, reset=True, filename=args.logfile) else: ensure_logging_setup(logging.DEBUG if args.verbose else logging.INFO, reset=True) plugins = get_all_plugins() assert plugin_telegram.TELEGRAM_ROOT_PLUGIN_NAME in plugins assert plugin_picamera.PICAMERA_ROOT_PLUGIN_NAME in plugins assert plugin_media_manager.MEDIA_MANAGER_PLUGIN_NAME in plugins assert plugin_buffered_recorder.BUFFERED_RECORDER_PLUGIN_NAME in plugins assert plugin_motion_detector.MOTION_DETECTOR_PLUGIN_NAME in plugins assert plugin_still.STILL_PLUGIN_NAME in plugins assert plugin_ratcam.RATCAM_PLUGIN_NAME in plugins assert plugin_pwmled.PWMLED_PLUGIN_NAME in plugins assert plugin_status_led.STATUS_LED_PLUGIN_NAME in plugins if not args.camera: del plugins[plugin_picamera.PICAMERA_ROOT_PLUGIN_NAME] if not args.light: del plugins[plugin_pwmled.PWMLED_PLUGIN_NAME] if not args.status_led: del plugins[plugin_status_led.STATUS_LED_PLUGIN_NAME] logging.info('Running the following plugins: ' + ', '.join(plugins.keys())) # Ignore KeyboardInterrupt. If we don't do so, it will be raised also in the child processes. We do not have control # over the threads running in the child processes, so they will terminate, and here we get some network exception # because the socket is closed. We want instead to terminate gracefully. with GracefulSignal() as sigint: with ProcessesHost(plugins): logging.info('Ready.') sigint.wait() logging.info('Turning off...')
def try_report_motion_on(process): motion_detection_pack = ProcessPack(camera=MotionDetectorCameraPlugin) if process != Process.CAMERA: motion_detection_pack[process] = MotionDetectorDispatcherPlugin responder_pack = ProcessPack() responder_pack[ process] = TestMotionDetectorPlugin.TestMovementResponder plugins = { MOTION_DETECTOR_PLUGIN_NAME: motion_detection_pack, PICAMERA_ROOT_PLUGIN_NAME: ProcessPack(camera=PiCameraRootPlugin), 'InjectDemoData': ProcessPack(camera=InjectDemoData), TestMotionDetectorPlugin.TestMovementResponder.plugin_name(): responder_pack } with ProcessesHost(plugins) as host: injector = host.plugin_instances['InjectDemoData'].camera responder = host.plugin_instances[ TestMotionDetectorPlugin.TestMovementResponder.plugin_name( )][process] injector.wait_for_completion() return responder.num_distinct_movements, responder.num_wrong_changed_events
def test_none_process_host(self): plugins = {'main': ProcessPack(None, None, None)} with ProcessesHost(plugins) as processes: instance_pack = processes.plugin_instances['main'] for instance in instance_pack.values(): self.assertIsNone(instance)