Example #1
0
    def is_process_alive(pid):
        from robocorp_ls_core.subprocess_wrapper import subprocess

        if _is_process_alive(pid):
            # Check if zombie...
            try:
                cmd = ["ps", "-p", str(pid), "-o", "stat"]
                try:
                    process = subprocess.Popen(cmd,
                                               stdout=subprocess.PIPE,
                                               stderr=subprocess.PIPE)
                except:
                    log.exception("Error calling: %s." % (cmd, ))
                else:
                    stdout, _ = process.communicate()
                    stdout = stdout.decode("utf-8", "replace")
                    lines = [line.strip() for line in stdout.splitlines()]
                    if len(lines) > 1:
                        if lines[1].startswith("Z"):
                            return False  # It's a zombie
            except:
                log.exception("Error checking if process is alive.")

            return True
        return False
def test_exit_with_parent_process_died(
    language_server_process: IRobocorpLanguageServerClient,
    language_server_io,
    ws_root_path,
    initialization_options,
):
    """
    :note: Only check with the language_server_io (because that's in another process).
    """
    from robocorp_ls_core.subprocess_wrapper import subprocess
    from robocorp_ls_core.basic import is_process_alive
    from robocorp_ls_core.basic import kill_process_and_subprocesses
    from robocorp_ls_core.unittest_tools.fixtures import wait_for_test_condition

    language_server = language_server_io
    dummy_process = subprocess.Popen(
        [sys.executable, "-c", "import time;time.sleep(10000)"])

    language_server.initialize(
        ws_root_path,
        process_id=dummy_process.pid,
        initialization_options=initialization_options,
    )

    assert is_process_alive(dummy_process.pid)
    assert is_process_alive(language_server_process.pid)

    kill_process_and_subprocesses(dummy_process.pid)

    wait_for_test_condition(lambda: not is_process_alive(dummy_process.pid))
    wait_for_test_condition(
        lambda: not is_process_alive(language_server_process.pid))
    language_server_io.require_exit_messages = False
Example #3
0
    def on_any_event(self, event):
        from string import Template

        if self.drop_during_process and self.process and self.process.poll(
        ) is None:
            return

        if event.is_directory:
            object_type = 'directory'
        else:
            object_type = 'file'

        context = {
            'watch_src_path': event.src_path,
            'watch_dest_path': '',
            'watch_event_type': event.event_type,
            'watch_object': object_type,
        }

        if self.shell_command is None:
            if has_attribute(event, 'dest_path'):
                context.update({'dest_path': event.dest_path})
                command = 'echo "${watch_event_type} ${watch_object} from ${watch_src_path} to ${watch_dest_path}"'
            else:
                command = 'echo "${watch_event_type} ${watch_object} ${watch_src_path}"'
        else:
            if has_attribute(event, 'dest_path'):
                context.update({'watch_dest_path': event.dest_path})
            command = self.shell_command

        command = Template(command).safe_substitute(**context)
        self.process = subprocess.Popen(command, shell=True)
        if self.wait_for_process:
            self.process.wait()
Example #4
0
def test_system_mutex_locked_on_subprocess():
    import sys
    from robocorp_ls_core.subprocess_wrapper import subprocess
    from robocorp_ls_core.basic import kill_process_and_subprocesses
    from robocorp_ls_core.system_mutex import SystemMutex
    from robocorp_ls_core.basic import wait_for_condition

    code = '''
import sys
import time
print('initialized')
from robocorp_ls_core.system_mutex import SystemMutex
mutex = SystemMutex('test_system_mutex_locked_on_subprocess')
assert mutex.get_mutex_aquired()
print('acquired mutex')
sys.stdout.flush()
time.sleep(30)
'''
    p = subprocess.Popen([sys.executable, '-c', code], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
    wait_for_condition(lambda: p.stdout.readline().strip() == b'acquired mutex')
    mutex = SystemMutex('test_system_mutex_locked_on_subprocess')
    assert not mutex.get_mutex_aquired()
    
    # i.e.: check that we can acquire the mutex if the related process dies.
    kill_process_and_subprocesses(p.pid)
    
    def acquire_mutex():
        mutex = SystemMutex('test_system_mutex_locked_on_subprocess')
        return mutex.get_mutex_aquired()
    wait_for_condition(acquire_mutex, timeout=5)
Example #5
0
def _popen(cmdline, **kwargs):
    import subprocess

    try:
        return subprocess.Popen(cmdline, **kwargs)
    except:
        log.exception("Error running: %s", (" ".join(cmdline)))
        return None
Example #6
0
def start_server_process(args=(), python_exe=None, env=None):
    """
    Calls this __main__ in another process.

    :param args:
        The list of arguments for the server process.
        i.e.:
            ["-vv", "--log-file=%s" % log_file]
    """
    from robocorp_ls_core.robotframework_log import get_logger
    from robocorp_ls_core.subprocess_wrapper import subprocess
    import threading
    from robotframework_ls.options import Setup

    log = get_logger(__name__)

    if python_exe:
        if not os.path.exists(python_exe):
            raise RuntimeError("Expected %s to exist" % (python_exe, ))

    args = [python_exe or sys.executable, "-u", __file__] + list(args)
    log.debug('Starting server api process with args: "%s"' %
              ('" "'.join(args), ))
    environ = os.environ.copy()
    environ.pop("PYTHONPATH", "")
    environ.pop("PYTHONHOME", "")
    environ.pop("VIRTUAL_ENV", "")
    if env is not None:
        for key, val in env.items():
            environ[key] = val

    environ["PYTHONIOENCODING"] = "utf-8"
    environ["PYTHONUNBUFFERED"] = "1"

    env_log = ["Environ:"]
    for key, val in environ.items():
        env_log.append("  %s=%s" % (key, val))

    if Setup.options.DEBUG_PROCESS_ENVIRON:
        log.debug("\n".join(env_log))

    language_server_process = subprocess.Popen(
        args,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE,
        env=environ,
        bufsize=0,
    )

    t = threading.Thread(target=_stderr_reader,
                         args=(language_server_process.stderr, ))
    t.setName("Stderr from ServerAPI (%s)" % (args, ))
    t.setDaemon(True)
    t.start()

    return language_server_process
Example #7
0
    def launch(
        self,
        target,
        debug=True,
        success=True,
        terminal="none",
        args: Optional[Iterable[str]] = None,
    ):
        """
        :param args:
            The arguments to the launch (for instance:
                ["--variable", "my_var:22"]
            )
        """
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import LaunchRequest
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import (
            LaunchRequestArguments, )
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import LaunchResponse
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import (
            RunInTerminalRequest, )
        from robocorp_ls_core.basic import as_str
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import InitializedEvent
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import Response
        from robocorp_ls_core.debug_adapter_core.dap.dap_schema import ProcessEvent

        launch_args = LaunchRequestArguments(__sessionId="some_id",
                                             noDebug=not debug,
                                             target=target,
                                             terminal=terminal)
        if args:
            launch_args.kwargs["args"] = args
        self.write(LaunchRequest(launch_args))

        if terminal == "external":
            run_in_terminal_request = self.read(RunInTerminalRequest)
            env = os.environ.copy()
            for key, val in run_in_terminal_request.arguments.env.to_dict(
            ).items():
                env[as_str(key)] = as_str(val)

            cwd = run_in_terminal_request.arguments.cwd
            popen_args = run_in_terminal_request.arguments.args

            subprocess.Popen(popen_args, cwd=cwd, env=env)

        if success:
            # Initialized is sent just before the launch response (at which
            # point it's possible to send breakpoints).
            self.read(ProcessEvent)
            event = self.read(InitializedEvent)
            assert isinstance(event, InitializedEvent)

        if success:
            launch_response = self.read(LaunchResponse)
        else:
            launch_response = self.read(Response)
        assert launch_response.success == success
Example #8
0
def dap_process(dap_log_file, dap_process_stderr_file):
    from robotframework_debug_adapter import __main__
    from robocorp_ls_core.basic import kill_process_and_subprocesses

    env = os.environ.copy()
    env["ROBOTFRAMEWORK_DAP_LOG_LEVEL"] = "3"
    env["ROBOTFRAMEWORK_DAP_LOG_FILENAME"] = dap_log_file

    dap_process = subprocess.Popen(
        [sys.executable, "-u", __main__.__file__],
        stdout=subprocess.PIPE,
        stderr=dap_process_stderr_file,
        stdin=subprocess.PIPE,
        env=env,
    )
    assert dap_process.returncode is None
    yield dap_process
    if dap_process.returncode is None:
        kill_process_and_subprocesses(dap_process.pid)
Example #9
0
def not_supported_test_launch_in_external_terminal(
    debugger_api: _DebuggerAPI, rcc_config_location: str
):
    """
    This is an integrated test of the debug adapter. It communicates with it as if it was
    VSCode.
    
    Note: we don't currently support launching in an external terminal because there's
    no easy way to get the pid (it'd be possible to do that by creating a wrapper script
    which would then really launch rcc and then it'd connect back to some port and
    provide the pid of the process which was spawned, but the value gained vs the
    effort to do so seems low, which means we can only run without a terminal for
    now so that we have an easy way of tracking the RCC process pid).
    """
    from robocorp_ls_core.debug_adapter_core.dap.dap_schema import TerminatedEvent
    from robocorp_ls_core.debug_adapter_core.dap.dap_schema import RunInTerminalRequest
    import os
    from robocorp_ls_core.basic import as_str
    from robocorp_ls_core.subprocess_wrapper import subprocess

    debugger_api.initialize(rcc_config_location=rcc_config_location)

    robot = debugger_api.get_dap_case_file("minimal/robot.yaml")
    debugger_api.launch(robot, "task2", debug=False, terminal="external")
    debugger_api.configuration_done()

    run_in_terminal_request = debugger_api.read(RunInTerminalRequest)
    env = os.environ.copy()
    for key, val in run_in_terminal_request.arguments.env.to_dict().items():
        env[as_str(key)] = as_str(val)

    cwd = run_in_terminal_request.arguments.cwd
    popen_args = run_in_terminal_request.arguments.args

    subprocess.Popen(popen_args, cwd=cwd, env=env)

    # i.e.: Big timeout because creating the environment may be slow.
    debugger_api.read(TerminatedEvent, timeout=120)
Example #10
0
def create_language_server_process(log_file, __main__module):
    from robocorp_ls_core.basic import kill_process_and_subprocesses

    from robocorp_ls_core.subprocess_wrapper import subprocess

    language_server_process = subprocess.Popen(
        [
            sys.executable,
            "-u",
            __main__module.__file__,
            "-vv",
            "--log-file=%s" % log_file,
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE,
    )
    stderr = language_server_process.stderr
    buf = []
    t = threading.Thread(target=_stderr_reader, args=(stderr, buf))
    t.name = "Stderr reader"
    t.start()

    returncode = language_server_process.poll()
    assert returncode is None
    try:
        yield language_server_process
    finally:
        t.join(1)
        stderr_contents = b"".join(buf).decode("utf-8")
        if stderr_contents:
            sys.stderr.write(
                f"Found stderr contents: >>\n{stderr_contents}\n<<")
        returncode = language_server_process.poll()
        if returncode is None:
            kill_process_and_subprocesses(language_server_process.pid)
Example #11
0
 def start(self):
     self.process = subprocess.Popen(self.command, preexec_fn=os.setsid)