def test_stbt_control_relay(stbt_control_relay_on_path): # pylint: disable=unused-argument with named_temporary_directory("stbt-control-relay-test.XXXXXX") as tmpdir: def t(filename): return os.path.join(tmpdir, filename) proc = subprocess.Popen( ["stbt-control-relay", "--socket", t("lircd.sock"), "file:" + t("one-file")]) with scoped_process(proc): wait_until(lambda: ( os.path.exists(t("lircd.sock")) or proc.poll() is not None)) testcontrol = uri_to_control("lirc:%s:stbt-test" % t("lircd.sock")) testcontrol.press("KEY_LEFT") testcontrol.press("KEY_RIGHT") testcontrol.keydown("KEY_MENU") testcontrol.keyup("KEY_MENU") expected = dedent("""\ KEY_LEFT KEY_RIGHT Holding KEY_MENU Released KEY_MENU """) assert expected == open(t("one-file")).read()
def test_stbt_control_relay(stbt_control_relay_on_path): # pylint: disable=unused-argument with named_temporary_directory("stbt-control-relay-test.XXXXXX") as tmpdir: def t(filename): return os.path.join(tmpdir, filename) proc = subprocess.Popen([ "stbt-control-relay", "--socket", t("lircd.sock"), "file:" + t("one-file") ]) with scoped_process(proc): wait_until(lambda: (os.path.exists(t("lircd.sock")) or proc.poll() is not None)) testcontrol = uri_to_control("lirc:%s:stbt-test" % t("lircd.sock")) testcontrol.press("KEY_LEFT") testcontrol.press("KEY_RIGHT") testcontrol.keydown("KEY_MENU") testcontrol.keyup("KEY_MENU") expected = dedent("""\ KEY_LEFT KEY_RIGHT Holding KEY_MENU Released KEY_MENU """) assert expected == open(t("one-file")).read()
def main(argv): parser = argparse.ArgumentParser( epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--socket", default="/var/run/lirc/lircd", help="""LIRC socket to read remote control presses from (defaults to %(default)s).""") parser.add_argument("output", help="""Remote control configuration to transmit on. Values are the same as stbt run's --control.""") _stbt.logging.argparser_add_verbose_argument(parser) args = parser.parse_args(argv[1:]) signal.signal(signal.SIGTERM, lambda _signo, _stack_frame: sys.exit(0)) if os.environ.get('LISTEN_FDS') == '1' and \ os.environ.get('LISTEN_PID') == str(os.getpid()): s = socket.fromfd(3, socket.AF_UNIX, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.bind(args.socket) s.listen(5) control = uri_to_control(args.output) while True: conn, _ = s.accept() f = conn.makefile('r', 0) while True: cmd = f.readline() if not cmd: break cmd = cmd.rstrip("\n") m = re.match( r"(?P<action>SEND_ONCE|SEND_START|SEND_STOP) " r"(?P<ctrl>\S+) (?P<key>\S+)", cmd) if not m: debug("Invalid command: %s" % cmd) send_response(conn, cmd, success=False, data="Invalid command: %s" % cmd) continue action = m.groupdict()["action"] key = m.groupdict()["key"] debug("Received %s %s" % (action, key)) try: if action == "SEND_ONCE": control.press(key) elif action == "SEND_START": control.keydown(key) elif action == "SEND_STOP": control.keyup(key) except Exception as e: # pylint: disable=broad-except debug("Error pressing key %r: %r" % (key, e)) send_response(conn, cmd, success=False, data=str(e)) continue send_response(conn, cmd, success=True)
def main(argv): parser = argparse.ArgumentParser( epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( "--socket", default="/var/run/lirc/lircd", help="""LIRC socket to read remote control presses from (defaults to %(default)s).""") parser.add_argument("output", help="""Remote control configuration to transmit on. Values are the same as stbt run's --control.""") _stbt.logging.argparser_add_verbose_argument(parser) args = parser.parse_args(argv[1:]) signal.signal(signal.SIGTERM, lambda _signo, _stack_frame: sys.exit(0)) if os.environ.get('LISTEN_FDS') == '1' and \ os.environ.get('LISTEN_PID') == str(os.getpid()): s = socket.fromfd(3, socket.AF_UNIX, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.bind(args.socket) s.listen(5) control = uri_to_control(args.output) while True: conn, _ = s.accept() f = conn.makefile('r', 0) while True: cmd = f.readline() if not cmd: break cmd = cmd.rstrip("\n") m = re.match(r"(?P<action>SEND_ONCE|SEND_START|SEND_STOP) " r"(?P<ctrl>\S+) (?P<key>\S+)", cmd) if not m: debug("Invalid command: %s" % cmd) send_response(conn, cmd, success=False, data="Invalid command: %s" % cmd) continue action = m.groupdict()["action"] key = m.groupdict()["key"] debug("Received %s %s" % (action, key)) try: if action == "SEND_ONCE": control.press(key) elif action == "SEND_START": control.keydown(key) elif action == "SEND_STOP": control.keyup(key) except Exception as e: # pylint: disable=broad-except debug("Error pressing key %r: %r" % (key, e)) send_response(conn, cmd, success=False, data=str(e)) continue send_response(conn, cmd, success=True)
def test_stbt_control_relay_with_socket_passing(stbt_control_relay_on_path): # pylint: disable=unused-argument with NamedTemporaryFile(prefix="stbt-control-relay-test-") as tmpfile: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 0)) s.listen(5) proc = subprocess.Popen( ["stbt-control-relay", "-vv", "file:" + tmpfile.name], preexec_fn=socket_passing_setup(s)) with scoped_process(proc): testcontrol = uri_to_control("lirc:%s:%i:stbt" % s.getsockname()) testcontrol.press("KEY_UP") testcontrol.press("KEY_DOWN") expected = "KEY_UP\nKEY_DOWN\n" assert tmpfile.read() == expected
def new_device_under_test_from_config(parsed_args=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display(args.source_pipeline, sink_pipeline, args.restart_source, source_teardown_eos) return DeviceUnderTest(display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop)
def new_device_under_test_from_config(parsed_args=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display( args.source_pipeline, sink_pipeline, args.restart_source, source_teardown_eos) return DeviceUnderTest( display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop)
def main(argv): parser = argparse.ArgumentParser( epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--socket", default="/var/run/lirc/lircd", help="""LIRC socket to read remote control presses from (defaults to %(default)s).""") parser.add_argument("--timeout", default=0, type=float, help=""" Timeout, in seconds, before exiting if no commands are received. If not specified, never times out.""") parser.add_argument("-v", "--verbose", action="store_true") parser.add_argument("output", help="""Remote control configuration to transmit on. Values are the same as stbt run's --control.""") args = parser.parse_args(argv[1:]) logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG if args.verbose else logging.INFO) if args.verbose: _stbt.logging._debug_level = 1 # pylint:disable=protected-access signal.signal(signal.SIGTERM, lambda _signo, _stack_frame: sys.exit(0)) if os.environ.get('LISTEN_FDS') == '1' and \ os.environ.get('LISTEN_PID') == str(os.getpid()): s = socket.fromfd(3, socket.AF_UNIX, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.bind(args.socket) s.listen(5) if args.timeout: s.settimeout(args.timeout) control = uri_to_control(args.output) logging.info("stbt-control-relay started up with output '%s'", args.output) while True: try: conn, _ = s.accept() except socket.timeout: return 0 f = conn.makefile('rb', 0) while True: cmd = f.readline() if not cmd: break cmd = cmd.rstrip(b"\n") m = re.match( br"(?P<action>SEND_ONCE|SEND_START|SEND_STOP) " br"(?P<ctrl>\S+) (?P<key>\S+)", cmd) if not m: logging.error("Invalid command: %s", cmd) send_response(conn, cmd, success=False, data=b"Invalid command: %s" % cmd) continue action = m.group("action") key = m.group("key") logging.debug("Received %s %s", action, key) try: key = key.decode("utf-8") if action == b"SEND_ONCE": control.press(key) elif action == b"SEND_START": control.keydown(key) elif action == b"SEND_STOP": control.keyup(key) except Exception as e: # pylint: disable=broad-except logging.error("Error pressing or releasing key %r: %s", key, e, exc_info=True) send_response(conn, cmd, success=False, data=to_bytes(str(e))) continue send_response(conn, cmd, success=True)
def new_device_under_test_from_config(parsed_args=None, transformation_pipeline=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) if transformation_pipeline is None: transformation_pipeline = get_config('global', 'transformation_pipeline') source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) use_old_threading_behaviour = get_config('global', 'use_old_threading_behaviour', type_=bool) if use_old_threading_behaviour: warn( dedent("""\ global.use_old_threading_behaviour is enabled. This is intended as a stop-gap measure to allow upgrading to stb-tester v28. We recommend porting functions that depend on stbt.get_frame() returning consecutive frames on each call to use stbt.frames() instead. This should make your functions usable from multiple threads. If porting to stbt.frames is not suitable please let us know on https://github.com/stb-tester/stb-tester/pull/449 otherwise this configuration option will be removed in a future release of stb-tester. """)) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display(args.source_pipeline, sink_pipeline, args.restart_source, transformation_pipeline, source_teardown_eos) return DeviceUnderTest( display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop, use_old_threading_behaviour=use_old_threading_behaviour)
def test_press(lircd): control = uri_to_control("lirc:%s:Apple_TV" % lircd.socket) control.press("KEY_OK") lircd_output = open(lircd.logfile, "r").read() expected = dedent("""\ pulse 9000 space 4500 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 527 pulse 527 space 527 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 38000 """) assert expected == lircd_output
def test_press_with_unknown_key(lircd): control = uri_to_control("lirc:%s:Apple_TV" % lircd.socket) with pytest.raises(RuntimeError) as excinfo: control.press("KEY_MAGIC") assert 'unknown command: "KEY_MAGIC"' in str(excinfo.value)
def test_press_with_unknown_remote(lircd): control = uri_to_control("lirc:%s:roku" % lircd.socket) with pytest.raises(RuntimeError) as excinfo: control.press("KEY_OK") assert 'unknown remote: "roku"' in str(excinfo.value)
def test_press(lircd): logfile = open(lircd.logfile) # newbytes doesn't play well with parameterize here, so we use a for loop: for key in [b'KEY_OK', u'KEY_OK', newbytes(b'KEY_OK'), newstr(u'KEY_OK')]: print("key = %r (%s)" % (key, type(key))) # pylint: disable=superfluous-parens control = uri_to_control("lirc:%s:Apple_TV" % lircd.socket) control.press(key) lircd_output = logfile.read() expected = dedent("""\ pulse 9000 space 4500 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 527 pulse 527 space 527 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 1703 pulse 527 space 527 pulse 527 space 38000 """) assert expected == lircd_output