Esempio n. 1
0
 def test_write(self):
     data = io.BytesIO()
     stream = JsonIOStream(data, data)
     for message in self.MESSAGES:
         stream.write_json(message)
     data = data.getvalue()
     assert data == self.SERIALIZED_MESSAGES
Esempio n. 2
0
 def test_read(self):
     data = io.BytesIO(self.SERIALIZED_MESSAGES)
     stream = JsonIOStream(data, data)
     for expected_message in self.MESSAGES:
         message = stream.read_json()
         assert message == expected_message
     with pytest.raises(EOFError):
         stream.read_json()
Esempio n. 3
0
 def _setup_channel(self):
     self.stream = LoggingJsonStream(JsonIOStream.from_socket(self.socket),
                                     'ptvsd#%d' % self.ptvsd_port)
     handlers = MessageHandlers(request=self._process_request,
                                event=self._process_event)
     self.channel = JsonMessageChannel(self.stream, handlers)
     self.channel.start()
     self.connected.set()
Esempio n. 4
0
def _subprocess_listener():
    counter = itertools.count(1)
    while subprocess_listener_socket:
        try:
            (sock, _) = subprocess_listener_socket.accept()
        except Exception:
            break
        stream = JsonIOStream.from_socket(sock)
        _handle_subprocess(next(counter), stream)
Esempio n. 5
0
def _subprocess_listener():
    counter = itertools.count(1)
    while subprocess_listener_socket:
        try:
            (sock, _) = subprocess_listener_socket.accept()
        except Exception:
            break
        stream = JsonIOStream.from_socket(sock)
        _handle_subprocess(next(counter), stream)
Esempio n. 6
0
    def prepare_to_run(self,
                       perform_handshake=True,
                       filename=None,
                       module=None):
        """Spawns ptvsd using the configured method, telling it to execute the
        provided Python file or module, and establishes a message channel to it.

        If perform_handshake is True, calls self.handshake() before returning.
        """

        argv = [sys.executable]
        if self.method != 'attach_pid':
            argv += ['-m', 'ptvsd']

        if self.method == 'attach_socket':
            if self.ptvsd_port is None:
                self.ptvsd_port = 5678
            argv += ['--port', str(self.ptvsd_port)]
        else:
            port = self._listen()
            argv += ['--host', 'localhost', '--port', str(port)]

        if filename:
            assert not module
            argv += [filename]
        elif module:
            assert not filename
            argv += ['-m', module]

        env = os.environ.copy()
        env.update({'PYTHONPATH': PTVSD_SYS_PATH})

        print('Spawning %r' % argv)
        self.process = subprocess.Popen(argv, env=env, stdin=subprocess.PIPE)
        if self.ptvsd_port:
            # ptvsd will take some time to spawn and start listening on the port,
            # so just hammer at it until it responds (or we time out).
            while not self.socket:
                try:
                    self._connect()
                except socket.error:
                    pass
                time.sleep(0.1)
        else:
            self.connected.wait()
            assert self.socket

        self.stream = LoggingJsonStream(JsonIOStream.from_socket(self.socket))

        handlers = MessageHandlers(request=self._process_request,
                                   event=self._process_event)
        self.channel = JsonMessageChannel(self.stream, handlers)
        self.channel.start()

        if perform_handshake:
            self.handshake()
Esempio n. 7
0
    def _backchannel_worker(self):
        print('Listening for incoming backchannel connection for bchan#%d' % self.ptvsd_port)
        sock = None

        try:
            sock, _ = self.backchannel_socket.accept()
        except socket.timeout:
            assert sock is not None, 'bchan#%r timed out!' % self.ptvsd_port

        print('Incoming bchan#%d backchannel connection accepted' % self.ptvsd_port)
        sock.settimeout(None)
        self._backchannel_stream = LoggingJsonStream(JsonIOStream.from_socket(sock), 'bchan#%d' % self.ptvsd_port)
        self.backchannel_established.set()
Esempio n. 8
0
def _subprocess_listener():
    counter = itertools.count(1)
    while subprocess_listener_socket:
        try:
            (sock, _) = subprocess_listener_socket.accept()
        except Exception:
            break

        n = next(counter)
        name = 'subprocess-{}'.format(n)
        ptvsd.log.debug('Accepted incoming connection from {0}', name)

        stream = JsonIOStream.from_socket(sock, name=name)
        _handle_subprocess(n, stream)
Esempio n. 9
0
def _subprocess_listener():
    counter = itertools.count(1)
    while subprocess_listener_socket:
        try:
            (sock, _) = subprocess_listener_socket.accept()
        except Exception:
            break

        n = next(counter)
        name = 'subprocess-{}'.format(n)
        ptvsd.log.debug('Accepted incoming connection from {0}', name)

        stream = JsonIOStream.from_socket(sock, name=name)
        _handle_subprocess(n, stream)
Esempio n. 10
0
def notify_root(port):
    assert options.subprocess_of

    debug('Subprocess %d notifying root process at port %d' %
          (os.getpid(), options.subprocess_notify))
    conn = create_client()
    conn.connect(('localhost', options.subprocess_notify))
    stream = JsonIOStream.from_socket(conn)
    channel = JsonMessageChannel(stream)
    channel.start()

    # Send the notification about ourselves to root, and wait for it to tell us
    # whether an incoming connection is anticipated. This will be true if root
    # had successfully propagated the notification to the IDE, and false if it
    # couldn't do so (e.g. because the IDE is not attached). There's also the
    # possibility that connection to root will just drop, e.g. if it crashes -
    # in that case, just exit immediately.

    request = channel.send_request(
        'ptvsd_subprocess', {
            'parentProcessId': options.subprocess_of,
            'processId': os.getpid(),
            'port': port,
        })

    try:
        response = request.wait_for_response()
    except Exception:
        print('Failed to send subprocess notification; exiting',
              file=sys.__stderr__)
        traceback.print_exc()
        sys.exit(0)

    # Keep the channel open until we exit - root process uses open channels to keep
    # track of which subprocesses are alive and which are not.
    atexit.register(lambda: channel.close())

    if not response['incomingConnection']:
        debugger = get_global_debugger()
        while debugger is None:
            time.sleep(0.1)
            debugger = get_global_debugger()
        debugger.ready_to_run = True
Esempio n. 11
0
def notify_root(port):
    assert options.subprocess_of

    debug('Subprocess %d notifying root process at port %d' % (os.getpid(), options.subprocess_notify))
    conn = create_client()
    conn.connect(('localhost', options.subprocess_notify))
    stream = JsonIOStream.from_socket(conn)
    channel = JsonMessageChannel(stream)
    channel.start()

    # Send the notification about ourselves to root, and wait for it to tell us
    # whether an incoming connection is anticipated. This will be true if root
    # had successfully propagated the notification to the IDE, and false if it
    # couldn't do so (e.g. because the IDE is not attached). There's also the
    # possibility that connection to root will just drop, e.g. if it crashes -
    # in that case, just exit immediately.

    request = channel.send_request('ptvsd_subprocess', {
        'parentProcessId': options.subprocess_of,
        'processId': os.getpid(),
        'port': port,
    })

    try:
        response = request.wait_for_response()
    except Exception:
        print('Failed to send subprocess notification; exiting', file=sys.__stderr__)
        traceback.print_exc()
        sys.exit(0)

    # Keep the channel open until we exit - root process uses open channels to keep
    # track of which subprocesses are alive and which are not.
    atexit.register(lambda: channel.close())

    if not response['incomingConnection']:
        debugger = get_global_debugger()
        while debugger is None:
            time.sleep(0.1)
            debugger = get_global_debugger()
        debugger.ready_to_run = True
Esempio n. 12
0
    def test_fuzz(self):
        # Set up two channels over the same stream that send messages to each other
        # asynchronously, and record everything that they send and receive.
        # All records should match at the end.

        class Fuzzer(object):
            def __init__(self, name):
                self.name = name
                self.lock = threading.Lock()
                self.sent = []
                self.received = []
                self.responses_sent = []
                self.responses_received = []

            def start(self, channel):
                self._worker = threading.Thread(name=self.name, target=lambda: self._send_requests_and_events(channel))
                self._worker.daemon = True
                self._worker.start()

            def wait(self):
                self._worker.join()

            def fizz_event(self, channel, body):
                with self.lock:
                    self.received.append(('event', 'fizz', body))

            def buzz_event(self, channel, body):
                with self.lock:
                    self.received.append(('event', 'buzz', body))

            def event(self, channel, event, body):
                with self.lock:
                    self.received.append(('event', event, body))

            def make_and_log_response(self, command):
                x = random.randint(-100, 100)
                if x >= 0:
                    response = Response(True, command, body=x)
                else:
                    response = Response(False, command, error_message=str(x))
                with self.lock:
                    self.responses_sent.append(response)
                if response.success:
                    return x
                else:
                    raise RuntimeError(response.error_message)

            def fizz_request(self, channel, arguments):
                with self.lock:
                    self.received.append(('request', 'fizz', arguments))
                return self.make_and_log_response('fizz')

            def buzz_request(self, channel, arguments):
                with self.lock:
                    self.received.append(('request', 'buzz', arguments))
                return self.make_and_log_response('buzz')

            def request(self, channel, command, arguments):
                with self.lock:
                    self.received.append(('request', command, arguments))
                return self.make_and_log_response(command)

            def _send_requests_and_events(self, channel):
                pending_requests = [0]
                for _ in range(0, 100):
                    typ = random.choice(('event', 'request'))
                    name = random.choice(('fizz', 'buzz', 'fizzbuzz'))
                    body = random.randint(0, 100)
                    with self.lock:
                        self.sent.append((typ, name, body))
                    if typ == 'event':
                        channel.send_event(name, body)
                    elif typ == 'request':
                        with self.lock:
                            pending_requests[0] += 1
                        req = channel.send_request(name, body)
                        def response_handler(response):
                            with self.lock:
                                self.responses_received.append(response)
                                pending_requests[0] -= 1
                        req.on_response(response_handler)
                # Spin until we get responses to all requests.
                while True:
                    with self.lock:
                        if pending_requests[0] == 0:
                            break
                    time.sleep(0.1)

        fuzzer1 = Fuzzer('fuzzer1')
        fuzzer2 = Fuzzer('fuzzer2')

        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.bind(('localhost', 0))
        _, port = server_socket.getsockname()
        server_socket.listen(0)

        socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        socket1_thread = threading.Thread(target=lambda: socket1.connect(('localhost', port)))
        socket1_thread.start()
        socket2, _ = server_socket.accept()
        socket1_thread.join()

        try:
            io1 = socket1.makefile('rwb', 0)
            io2 = socket2.makefile('rwb', 0)

            stream1 = LoggingJsonStream(JsonIOStream(io1, io1))
            channel1 = JsonMessageChannel(stream1, fuzzer1)
            channel1.start()
            fuzzer1.start(channel1)

            stream2 = LoggingJsonStream(JsonIOStream(io2, io2))
            channel2 = JsonMessageChannel(stream2, fuzzer2)
            channel2.start()
            fuzzer2.start(channel2)

            fuzzer1.wait()
            fuzzer2.wait()

        finally:
            socket1.close()
            socket2.close()

        assert fuzzer1.sent == fuzzer2.received
        assert fuzzer2.sent == fuzzer1.received
        assert fuzzer1.responses_sent == fuzzer2.responses_received
        assert fuzzer2.responses_sent == fuzzer1.responses_received
Esempio n. 13
0
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.

from __future__ import print_function, with_statement, absolute_import
"""Imported from test code that runs under ptvsd, and allows that code
to communcate back to the test. Works in conjunction with debug_session
fixture and its backchannel method."""

import os
import socket

from ptvsd.messaging import JsonIOStream

port = int(os.getenv('PTVSD_BACKCHANNEL_PORT'))
# print('Connecting to bchan#%d' % port)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', port))
stream = JsonIOStream.from_socket(sock)


def read_json():
    return stream.read_json()


def write_json(value):
    stream.write_json(value)
Esempio n. 14
0
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.

from __future__ import print_function, with_statement, absolute_import
"""Imported from test code that runs under ptvsd, and allows that code
to communcate back to the test. Works in conjunction with debug_session
fixture and its backchannel method."""

import os
import socket

import ptvsd.log
from ptvsd.messaging import JsonIOStream

port = int(os.getenv('PTVSD_BACKCHANNEL_PORT'))
ptvsd.log.debug('Connecting to bchan#{0}', port)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', port))
stream = JsonIOStream.from_socket(sock, name='test')


def read_json():
    return stream.read_json()


def write_json(value):
    stream.write_json(value)