Repository: microsoft/ptvsd

Issue:
LogpointTests failing on Windows
On Windows:
```
======================================================================
FAIL: test_basic (tests.highlevel.test_live_pydevd.LogpointTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\GIT\ptvsd\tests\highlevel\test_live_pydevd.py", line 268, in test_basic
    self.new_event('output', **dict(category='stdout', output='1+2=3' + os.linesep)), # noqa
  File "C:\GIT\ptvsd\tests\highlevel\__init__.py", line 788, in assert_vsc_received
    self.assertEqual(received, expected)
AssertionError: Lists differ: [Even[1452 chars]='output', body={'category': 'stdout', 'output': '1+2=3\n'})] != [Even[1452 chars]='output', body={'category': 'stdout', 'output': '1+2=3\r\n'})]

First differing element 9:
Event(seq=9, event='output', body={'category': 'stdout', 'output': '1+2=3\n'})
Event(seq=9, event='output', body={'category': 'stdout', 'output': '1+2=3\r\n'})

  [Event(seq=0, event='output', body={'category': 'telemetry', 'output': 'ptvsd', 'data': {'version': '4.1.1a2+4.gaffbf99'}}),
   Response(seq=1, request_seq=0, command='initialize', success=True, message='', body={'supportsExceptionInfoRequest': True, 'supportsConfigurationDoneRequest': True, 'supportsConditionalBreakpoints': True, 'supportsHitConditionalBreakpoints': True, 'supportsSetVariable': True, 'supportsExceptionOptions': True, 'supportsEvaluateForHovers': True, 'supportsValueFormattingOptions': True, 'supportsSetExpression': True, 'supportsModulesRequest': True, 'supportsLogPoints': True, 'exceptionBreakpointFilters': [{'filter': 'raised', 'label': 'Raised Exceptions', 'default': False}, {'filter': 'uncaught', 'label': 'Uncaught Exceptions', 'default': True}]}),
   Event(seq=2, event='initialized', body={}),
   Response(seq=3, request_seq=1, command='attach', success=True, message='', body={}),
   Response(seq=4, request_seq=2, command='setBreakpoints', success=True, message='', body={'breakpoints': [{'id': 1, 'verified': True, 'line': '4'}]}),
   Response(seq=5, request_seq=3, command='configurationDone', success=True, message='', body={}),
   Event(seq=6, event='process', body={'name': 'C:\\Users\\karth\\AppData\\Local\\Temp\\workspace-qp7h6f2r\\spam.py', 'systemProcessId': 7924, 'isLocalProcess': True, 'startMethod': 'attach'}),
   Event(seq=7, event='exited', body={'exitCode': 0}),
   Event(seq=8, event='terminated', body={}),
-  Event(seq=9, event='output', body={'category': 'stdout', 'output': '1+2=3\n'})]
+  Event(seq=9, event='output', body={'category': 'stdout', 'output': '1+2=3\r\n'})]
?                                                                            ++
```

On Linux (WSL): The output here changes with each run.
```
======================================================================
FAIL: test_basic (tests.highlevel.test_live_pydevd.LogpointTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/c/GIT/ptvsd/tests/highlevel/test_live_pydevd.py", line 268, in test_basic
    self.new_event('output', **dict(category='stdout', output='1+2=3' + os.linesep)), # noqa
  File "/mnt/c/GIT/ptvsd/tests/highlevel/__init__.py", line 788, in assert_vsc_received
    self.assertEqual(received, expected)
AssertionError: Lists differ: [Even[1187 chars]y={'startMethod': 'attach', 'systemProcessId':[472 chars]r'})] != [Even[1187 chars]y={'systemProcessId': 67, 'startMethod': 'atta[243 chars]t'})]

First list contains 1 additional elements.
First extra element 10:
Event(seq=10, event='output', body={'output': "/mnt/c/GIT/ptvsd/ptvsd/wrapper.py:808: UserWarning: timed out waiting for disconnect request\n  warnings.warn('timed out waiting for disconnect request')\n", 'category': 'stderr'})

  [Event(seq=0, event='output', body={'output': 'ptvsd', 'data': {'version': '4.1.1a2+4.gaffbf99.dirty'}, 'category': 'telemetry'}),
   Response(seq=1, request_seq=0, command='initialize', success=True, message='', body={'supportsLogPoints': True, 'supportsEvaluateForHovers': True, 'supportsSetVariable': True, 'supportsExceptionInfoRequest': True, 'exceptionBreakpointFilters': [{'filter': 'raised', 'label': 'Raised Exceptions', 'default': False}, {'filter': 'uncaught', 'label': 'Uncaught Exceptions', 'default': True}], 'supportsSetExpression': True, 'supportsModulesRequest': True, 'supportsHitConditionalBreakpoints': True, 'supportsConfigurationDoneRequest': True, 'supportsConditionalBreakpoints': True, 'supportsValueFormattingOptions': True, 'supportsExceptionOptions': True}),
   Event(seq=2, event='initialized', body={}),
   Response(seq=3, request_seq=1, command='attach', success=True, message='', body={}),
   Response(seq=4, request_seq=2, command='setBreakpoints', success=True, message='', body={'breakpoints': [{'id': 1, 'verified': True, 'line': '4'}]}),
   Response(seq=5, request_seq=3, command='configurationDone', success=True, message='', body={}),
-  Event(seq=6, event='process', body={'startMethod': 'attach', 'systemProcessId': 67, 'name': '/tmp/workspace-uem1gno3/spam.py', 'isLocalProcess': True}),
?                                      -------------------------

+  Event(seq=6, event='process', body={'systemProcessId': 67, 'startMethod': 'attach', 'name': '/tmp/workspace-uem1gno3/spam.py', 'isLocalProcess': True}),
?                                                            +++++++++++++++++++++++++

   Event(seq=7, event='exited', body={'exitCode': 0}),
   Event(seq=8, event='terminated', body={}),
-  Event(seq=9, event='output', body={'output': '1+2=3\n', 'category': 'stdout'}),
?                                                                                ^

+  Event(seq=9, event='output', body={'output': '1+2=3\n', 'category': 'stdout'})]
?                                                                                ^

-  Event(seq=10, event='output', body={'output': "/mnt/c/GIT/ptvsd/ptvsd/wrapper.py:808: UserWarning: timed out waiting for disconnect request\n  warnings.warn('timed out waiting for disconnect request')\n", 'category': 'stderr'})]

```


Discussion:
I don't have a Windows machine to debug this.

Resolving patch:
diff --git a/ptvsd/ipcjson.py b/ptvsd/ipcjson.py
--- a/ptvsd/ipcjson.py
+++ b/ptvsd/ipcjson.py
@@ -21,7 +21,7 @@
 import time
 import traceback
 
-from .socket import TimeoutError
+from .socket import TimeoutError, convert_eof
 
 
 _TRACE = None
@@ -300,25 +300,22 @@ def process_messages(self):
         # TODO: docstring
         if self._timeout is not None:
             self._fail_after = time.time() + self._timeout
-        while True:
-            if self.process_one_message():
-                return
+        while not self.__exit:
+            try:
+                self.process_one_message()
+                _trace('self.__exit is ', self.__exit)
+            except Exception:
+                if not self.__exit:
+                    raise
+                # TODO: log the error?
 
     def process_one_message(self):
         # TODO: docstring
         try:
             msg = self.__message.pop(0)
         except IndexError:
-            try:
+            with convert_eof():
                 self._wait_for_message()
-            except OSError as exc:
-                if exc.errno == errno.EBADF or self.__exit:  # socket closed
-                    return self.__exit
-                raise
-            except Exception:
-                if self.__exit:
-                    return True
-                raise
             try:
                 msg = self.__message.pop(0)
             except IndexError:
@@ -326,7 +323,7 @@ def process_one_message(self):
                 if self._fail_after is not None:
                     if time.time() < self._fail_after:
                         raise TimeoutError('connection closed?')
-                return self.__exit
+                raise EOFError('no more messages')
         if self._fail_after is not None:
             self._fail_after = time.time() + self._timeout
 
@@ -347,9 +344,6 @@ def process_one_message(self):
             _trace('Error ', traceback.format_exc)
             traceback.print_exc()
 
-        _trace('self.__exit is ', self.__exit)
-        return self.__exit
-
     def on_request(self, request):
         # TODO: docstring
         assert request.get('type', '') == 'request', \
diff --git a/ptvsd/socket.py b/ptvsd/socket.py
--- a/ptvsd/socket.py
+++ b/ptvsd/socket.py
@@ -10,11 +10,51 @@
     from urlparse import urlparse
 
 
+try:
+    ConnectionError  # noqa
+    BrokenPipeError  # noqa
+    ConnectionResetError  # noqa
+except NameError:
+    class BrokenPipeError(Exception):
+        # EPIPE and ESHUTDOWN
+        pass
+
+    class ConnectionResetError(Exception):
+        # ECONNRESET
+        pass
+
+
 NOT_CONNECTED = (
     errno.ENOTCONN,
     errno.EBADF,
 )
 
+CLOSED = (
+    errno.EPIPE,
+    errno.ESHUTDOWN,
+    errno.ECONNRESET,
+    # Windows
+    10038,  # "An operation was attempted on something that is not a socket"
+    10058,
+)
+
+EOF = NOT_CONNECTED + CLOSED
+
+
+@contextlib.contextmanager
+def convert_eof():
+    """A context manager to convert some socket errors into EOFError."""
+    try:
+        yield
+    except ConnectionResetError:
+        raise EOFError
+    except BrokenPipeError:
+        raise EOFError
+    except OSError as exc:
+        if exc.errno in EOF:
+            raise EOFError
+        raise
+
 
 class TimeoutError(socket.timeout):
     """A socket timeout happened."""
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -774,7 +774,7 @@ def process_messages():
             self.readylock.acquire()
             try:
                 self.process_messages()
-            except TimeoutError:
+            except (EOFError, TimeoutError):
                 debug('client socket closed')
                 self.close()
         self.server_thread = threading.Thread(


Test patch:
diff --git a/tests/helpers/debugadapter.py b/tests/helpers/debugadapter.py
--- a/tests/helpers/debugadapter.py
+++ b/tests/helpers/debugadapter.py
@@ -1,8 +1,66 @@
+import os
+
 from ptvsd.socket import Address
 from . import Closeable
 from .proc import Proc
 
 
+COPIED_ENV = [
+    'PYTHONHASHSEED',
+
+    # Windows
+    #'ALLUSERSPROFILE',
+    #'APPDATA',
+    #'CLIENTNAME',
+    #'COMMONPROGRAMFILES',
+    #'COMMONPROGRAMFILES(X86)',
+    #'COMMONPROGRAMW6432',
+    #'COMPUTERNAME',
+    #'COMSPEC',
+    #'DRIVERDATA',
+    #'HOMEDRIVE',
+    #'HOMEPATH',
+    #'LOCALAPPDATA',
+    #'LOGONSERVER',
+    #'NUMBER_OF_PROCESSORS',
+    #'OS',
+    #'PATH',
+    #'PATHEXT',
+    #'PROCESSOR_ARCHITECTURE',
+    #'PROCESSOR_IDENTIFIER',
+    #'PROCESSOR_LEVEL',
+    #'PROCESSOR_REVISION',
+    #'PROGRAMDATA',
+    #'PROGRAMFILES',
+    #'PROGRAMFILES(X86)',
+    #'PROGRAMW6432',
+    #'PSMODULEPATH',
+    #'PUBLIC',
+    #'SESSIONNAME',
+    'SYSTEMDRIVE',
+    'SYSTEMROOT',
+    #'TEMP',
+    #'TMP',
+    #'USERDOMAIN',
+    #'USERDOMAIN_ROAMINGPROFILE',
+    #'USERNAME',
+    #'USERPROFILE',
+    'WINDIR',
+]
+
+
+def _copy_env(verbose=False):
+    env = {k: v for k, v in os.environ.items() if k in COPIED_ENV}
+    # TODO: Be smarter about the seed?
+    env.setdefault('PYTHONHASHSEED', '1234')
+    if verbose:
+        env.update({
+            'PTVSD_DEBUG': '1',
+            'PTVSD_SOCKET_TIMEOUT': '1',
+        })
+    return env
+
+
 class DebugAdapter(Closeable):
 
     VERBOSE = False
@@ -15,13 +73,7 @@ class DebugAdapter(Closeable):
     @classmethod
     def start(cls, argv, **kwargs):
         def new_proc(argv, addr):
-            if cls.VERBOSE:
-                env = {
-                    'PTVSD_DEBUG': '1',
-                    'PTVSD_SOCKET_TIMEOUT': '1',
-                }
-            else:
-                env = {}
+            env = _copy_env(verbose=cls.VERBOSE)
             argv = list(argv)
             cls._ensure_addr(argv, addr)
             return Proc.start_python_module('ptvsd', argv, env=env)
@@ -30,7 +82,8 @@ def new_proc(argv, addr):
     @classmethod
     def start_wrapper_script(cls, filename, argv, **kwargs):
         def new_proc(argv, addr):
-            return Proc.start_python_script(filename, argv)
+            env = _copy_env(verbose=cls.VERBOSE)
+            return Proc.start_python_script(filename, argv, env=env)
         return cls._start(new_proc, argv, **kwargs)
 
     # specific factory cases
diff --git a/tests/helpers/socket.py b/tests/helpers/socket.py
--- a/tests/helpers/socket.py
+++ b/tests/helpers/socket.py
@@ -2,52 +2,11 @@
 
 from collections import namedtuple
 import contextlib
-import errno
 
 import ptvsd.socket as _ptvsd
 
 
-try:
-    ConnectionError  # noqa
-    BrokenPipeError  # noqa
-    ConnectionResetError  # noqa
-except NameError:
-    class BrokenPipeError(Exception):
-        # EPIPE and ESHUTDOWN
-        pass
-
-    class ConnectionResetError(Exception):
-        # ECONNRESET
-        pass
-
-
-NOT_CONNECTED = (
-    errno.ENOTCONN,
-    errno.EBADF,
-)
-
-CLOSED = (
-    errno.EPIPE,
-    errno.ESHUTDOWN,
-    errno.ECONNRESET,
-)
-
-EOF = NOT_CONNECTED + CLOSED
-
-
-@contextlib.contextmanager
-def convert_eof():
-    """A context manager to convert some socket errors into EOFError."""
-    try:
-        yield
-    except ConnectionResetError:
-        raise EOFError
-    except BrokenPipeError:
-        raise EOFError
-    except OSError as exc:
-        if exc.errno in EOF:
-            raise EOFError
-        raise
+convert_eof = _ptvsd.convert_eof
 
 
 # TODO: Add timeouts to the functions.
diff --git a/tests/highlevel/__init__.py b/tests/highlevel/__init__.py
--- a/tests/highlevel/__init__.py
+++ b/tests/highlevel/__init__.py
@@ -3,6 +3,7 @@
 import inspect
 import platform
 import threading
+import time
 import warnings
 
 from _pydevd_bundle.pydevd_comm import (
@@ -413,9 +414,9 @@ def new_fake(self, handler=None, **kwargs):
     def assert_no_failures(self):
         assert self.fake.failures == [], self.fake.failures
 
-    def reset(self):
+    def reset(self, **kwargs):
         self.assert_no_failures()
-        self.fake.reset()
+        self.fake.reset(**kwargs)
 
 
 class PyDevdFixture(FixtureBase):
@@ -700,9 +701,9 @@ def assert_no_failures(self):
         self._vsc.assert_no_failures()
         self._pydevd.assert_no_failures()
 
-    def reset(self):
-        self._vsc.reset()
-        self._debugger.reset()
+    def reset(self, **kwargs):
+        self._vsc.reset(**kwargs)
+        self._debugger.reset(**kwargs)
 
     # wrappers
 
@@ -949,6 +950,19 @@ def new_fake(self, debugger=None, handler=None):
         vsc, debugger = self.fix.new_fake(debugger, handler)
         return vsc, debugger
 
+    def wait_for_pydevd(self, *msgs, **kwargs):
+        timeout = kwargs.pop('timeout', 10.0)
+        assert not kwargs
+        steps = int(timeout * 100) + 1
+        for _ in range(steps):
+            # TODO: Watch for the specific messages.
+            if len(self.pydevd.received) >= len(msgs):
+                break
+            time.sleep(0.01)
+        else:
+            if len(self.pydevd.received) < len(msgs):
+                raise RuntimeError('timed out')
+
 
 class RunningTest(HighlevelTest):
     """The mixin class for high-level tests for post-start operations."""
diff --git a/tests/highlevel/test_lifecycle.py b/tests/highlevel/test_lifecycle.py
--- a/tests/highlevel/test_lifecycle.py
+++ b/tests/highlevel/test_lifecycle.py
@@ -116,6 +116,7 @@ def test_launch(self):
 
             # configuration
             req_config = self.send_request('configurationDone')
+            self.wait_for_pydevd('version', 'redirect-output', 'run')
 
             # Normal ops would go here.
 
diff --git a/tests/highlevel/test_live_pydevd.py b/tests/highlevel/test_live_pydevd.py
--- a/tests/highlevel/test_live_pydevd.py
+++ b/tests/highlevel/test_live_pydevd.py
@@ -206,7 +206,8 @@ class MyError(RuntimeError):
         # <a>
         def inc(value, count=1):
             # <b>
-            return value + count
+            result = value + count
+            return result
 
         # <c>
         x = 1
@@ -303,7 +304,7 @@ def _set_lock(self, label=None, script=None):
                     ])
                     break
                 leading.append(line)
-            script = os.linesep.join(leading) + os.linesep.join(lines)
+            script = '\n'.join(leading) + '\n'.join(lines)
 
         with open(self.filename, 'w') as scriptfile:
             scriptfile.write(script)
@@ -490,9 +491,10 @@ def running(self):
     def test_basic(self):
         with open(self.filename) as scriptfile:
             script = scriptfile.read()
+        donescript, wait = self.workspace.lockfile().wait_for_script()
         done, waitscript = self.workspace.lockfile().wait_in_script()
         with open(self.filename, 'w') as scriptfile:
-            scriptfile.write(script + waitscript)
+            scriptfile.write(script + donescript + waitscript)
         addr = (None, 8888)
         with self.fake.start(addr):
             with self.vsc.wait_for_event('output'):
@@ -518,13 +520,14 @@ def test_basic(self):
                 with self.vsc.wait_for_event('thread'):
                     req_config = self.send_request('configurationDone')
 
+            wait()
+            received = self.vsc.received
             done()
 
             self.fix.binder.done(close=False)
             self.fix.binder.wait_until_done()
             with self.closing():
                 self.fix.binder.ptvsd.close()
-            received = self.vsc.received
 
         self.assert_vsc_received(received, [
             self.new_event(
@@ -548,8 +551,6 @@ def test_basic(self):
             self.new_event('thread', reason='started', threadId=1),
             self.new_event('output', **dict(
                 category='stdout',
-                output='1+2=3' + os.linesep,
+                output='1+2=3\n',
             )),
-            self.new_event('exited', exitCode=0),
-            self.new_event('terminated'),
         ])
diff --git a/tests/highlevel/test_messages.py b/tests/highlevel/test_messages.py
--- a/tests/highlevel/test_messages.py
+++ b/tests/highlevel/test_messages.py
@@ -35,6 +35,10 @@
 from ptvsd.wrapper import UnsupportedPyDevdCommandError, INITIALIZE_RESPONSE
 
 
+def fail(msg):
+    raise RuntimeError(msg)
+
+
 # TODO: Make sure we are handling all args properly and sending the
 # correct response/event bpdies.
 
@@ -1073,9 +1077,9 @@ def test_with_existing(self):
         with self.launched():
             with self.hidden():
                 self.PYDEVD_CMD = CMD_SET_BREAK
-                self.expected_pydevd_request(
+                p1 = self.expected_pydevd_request(
                     '1\tpython-line\tspam.py\t10\tNone\tNone\tNone\tNone\tNone') # noqa
-                self.expected_pydevd_request(
+                p2 = self.expected_pydevd_request(
                     '2\tpython-line\tspam.py\t17\tNone\tNone\tNone\tNone\tNone') # noqa
                 self.fix.send_request('setBreakpoints', dict(
                     source={'path': 'spam.py'},
@@ -1084,6 +1088,7 @@ def test_with_existing(self):
                         {'line': '17'},
                     ],
                 ))
+                self.wait_for_pydevd(p1, p2)
             self.send_request(
                 source={'path': 'spam.py'},
                 breakpoints=[
@@ -1643,12 +1648,15 @@ def test_options_with_existing_filters(self):
         with self.launched():
             with self.hidden():
                 self.PYDEVD_CMD = CMD_ADD_EXCEPTION_BREAK
-                self.expected_pydevd_request('python-BaseException\t0\t1\t0')
+                p1 = self.expected_pydevd_request(
+                    'python-BaseException\t0\t1\t0',
+                )
                 self.fix.send_request('setExceptionBreakpoints', dict(
                     filters=[
                         'uncaught',
                     ],
                 ))
+                self.wait_for_pydevd(p1)
             self.send_request(
                 filters=[],
                 exceptionOptions=[
@@ -1683,8 +1691,12 @@ def test_options_with_existing_options(self):
         with self.launched():
             with self.hidden():
                 self.PYDEVD_CMD = CMD_ADD_EXCEPTION_BREAK
-                self.expected_pydevd_request('python-ImportError\t0\t1\t0')
-                self.expected_pydevd_request('python-BaseException\t3\t0\t0')
+                p1 = self.expected_pydevd_request(
+                    'python-ImportError\t0\t1\t0',
+                )
+                p2 = self.expected_pydevd_request(
+                    'python-BaseException\t3\t0\t0',
+                )
                 self.fix.send_request('setExceptionBreakpoints', dict(
                     filters=[],
                     exceptionOptions=[
@@ -1699,6 +1711,7 @@ def test_options_with_existing_options(self):
                          'breakMode': 'always'},
                     ],
                 ))
+                self.wait_for_pydevd(p1, p2)
             self.send_request(
                 filters=[],
                 exceptionOptions=[
@@ -1826,12 +1839,15 @@ def test_filters_with_existing_filters(self):
         with self.launched():
             with self.hidden():
                 self.PYDEVD_CMD = CMD_ADD_EXCEPTION_BREAK
-                self.expected_pydevd_request('python-BaseException\t0\t1\t0')
+                p1 = self.expected_pydevd_request(
+                    'python-BaseException\t0\t1\t0',
+                )
                 self.fix.send_request('setExceptionBreakpoints', dict(
                     filters=[
                         'uncaught',
                     ],
                 ))
+                self.wait_for_pydevd(p1)
             self.send_request(
                 filters=[
                     'raised',
@@ -1855,8 +1871,12 @@ def test_filters_with_existing_options(self):
         with self.launched():
             with self.hidden():
                 self.PYDEVD_CMD = CMD_ADD_EXCEPTION_BREAK
-                self.expected_pydevd_request('python-ImportError\t0\t1\t0')
-                self.expected_pydevd_request('python-BaseException\t3\t0\t0')
+                p1 = self.expected_pydevd_request(
+                    'python-ImportError\t0\t1\t0',
+                )
+                p2 = self.expected_pydevd_request(
+                    'python-BaseException\t3\t0\t0',
+                )
                 self.fix.send_request('setExceptionBreakpoints', dict(
                     filters=[],
                     exceptionOptions=[
@@ -1871,6 +1891,7 @@ def test_filters_with_existing_options(self):
                          'breakMode': 'always'},
                     ],
                 ))
+                self.wait_for_pydevd(p1, p2)
             self.send_request(
                 filters=[
                     'raised',
@@ -1972,7 +1993,8 @@ class ExceptionInfoTests(NormalRequestTest, unittest.TestCase):
 
     def test_active_exception(self):
         exc = RuntimeError('something went wrong')
-        frame = (2, 'spam', 'abc.py', 10)  # (pfid, func, file, line)
+        lineno = fail.__code__.co_firstlineno + 1
+        frame = (2, 'fail', __file__, lineno)  # (pfid, func, file, line)
         with self.launched():
             with self.hidden():
                 tid, _ = self.error('x', exc, frame)
@@ -1993,10 +2015,11 @@ def test_active_exception(self):
                 details=dict(
                     message=excstr,
                     typeName='RuntimeError',
-                    source='abc.py',
+                    source=__file__,
                     stackTrace='\n'.join([
-                        '  File "abc.py", line 10, in spam',
-                        '    """A decorator indicating abstract methods.',
+                        '  File "{}", line {}, in fail'.format(__file__,
+                                                               lineno),
+                        '    raise RuntimeError(msg)',
                         '',
                     ]),
                 ),
diff --git a/tests/system_tests/test_main.py b/tests/system_tests/test_main.py
--- a/tests/system_tests/test_main.py
+++ b/tests/system_tests/test_main.py
@@ -11,9 +11,6 @@
 from tests.helpers.vsc import parse_message, VSCMessages
 from tests.helpers.workspace import Workspace, PathEntry
 
-#VERSION = '0+unknown'
-VERSION = ptvsd.__version__
-
 
 def _strip_pydevd_output(out):
     # TODO: Leave relevant lines from before the marker?
@@ -105,8 +102,8 @@ def test_script_args(self):
             session.send_request('disconnect')
         out = adapter.output
 
-        self.assertEqual(out.decode('utf-8').strip().splitlines()[-1],
-                         u"[{!r}, '--eggs']".format(filename))
+        self.assertIn(u"[{!r}, '--eggs']".format(filename),
+                      out.decode('utf-8').strip().splitlines())
 
     def test_run_to_completion(self):
         filename = self.pathentry.write_module('spam', """
@@ -203,6 +200,17 @@ def assert_received(self, received, expected):
         expected = [parse_message(msg) for msg in expected]
         self.assertEqual(received, expected)
 
+    def new_version_event(self, received):
+        version = ptvsd.__version__
+        if received[0].body['data']['version'] != version:
+            version = '0+unknown'
+        return self.new_event(
+            'output',
+            category='telemetry',
+            output='ptvsd',
+            data={'version': version},
+        )
+
     def test_pre_init(self):
         filename = self.pathentry.write_module('spam', '')
         handlers, wait_for_started = self._wait_for_started()
@@ -216,19 +224,7 @@ def test_pre_init(self):
         out = adapter.output.decode('utf-8')
 
         self.assert_received(session.received, [
-            # TODO: Use self.new_event()...
-            {
-                'type': 'event',
-                'seq': 0,
-                'event': 'output',
-                'body': {
-                    'output': 'ptvsd',
-                    'data': {
-                        'version': VERSION,
-                    },
-                    'category': 'telemetry',
-                },
-            },
+            self.new_version_event(session.received),
         ])
         out = _strip_pydevd_output(out)
         self.assertEqual(out, '')
@@ -252,11 +248,7 @@ def test_launch_ptvsd_client(self):
             adapter.wait()
 
         self.assert_received(session.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session.received),
             self.new_response(req_initialize, **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(req_launch),
@@ -291,11 +283,7 @@ def test_launch_ptvsd_server(self):
 
         self.maxDiff = None
         self.assert_received(session.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session.received),
             self.new_response(req_initialize, **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(req_launch),
@@ -328,11 +316,7 @@ def test_attach_started_separately(self):
                 adapter.wait()
 
         self.assert_received(session.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session.received),
             self.new_response(req_initialize, **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(req_launch),
@@ -375,11 +359,7 @@ def test_attach_embedded(self):
         out = adapter.output.decode('utf-8')
 
         self.assert_received(session.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session.received),
             self.new_response(req_initialize, **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(req_launch),
@@ -423,11 +403,7 @@ def test_reattach(self):
 
         # self.maxDiff = None
         self.assert_received(session1.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session1.received),
             self.new_response(reqs[0], **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(reqs[1]),
@@ -445,11 +421,7 @@ def test_reattach(self):
         ])
         self.messages.reset_all()
         self.assert_received(session2.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session2.received),
             self.new_response(req_initialize, **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(req_launch),
@@ -491,11 +463,7 @@ def test_attach_unknown(self):
             adapter.wait()
 
         self.assert_received(session.received, [
-            self.new_event(
-                'output',
-                category='telemetry',
-                output='ptvsd',
-                data={'version': VERSION}),
+            self.new_version_event(session.received),
             self.new_response(req_initialize, **INITIALIZE_RESPONSE),
             self.new_event('initialized'),
             self.new_response(req_launch),
diff --git a/tests/test_setup.py b/tests/test_setup.py
--- a/tests/test_setup.py
+++ b/tests/test_setup.py
@@ -1,3 +1,4 @@
+import os.path
 import unittest
 
 from setup import iter_vendored_files
@@ -11,7 +12,7 @@ def test_all(self):
         self.assertEqual(filenames, VENDORED)
 
 
-VENDORED = {
+VENDORED = {file.replace('/', os.path.sep) for file in [
     'pydevd/pydev_run_in_console.py',
     'pydevd/setup_cython.py',
     'pydevd/pydev_app_engine_debug_startup.py',
@@ -211,4 +212,4 @@ def test_all(self):
     'pydevd/_pydevd_bundle/pydevd_save_locals.py',
     'pydevd/pydev_sitecustomize/sitecustomize.py',
     'pydevd/pydev_sitecustomize/__not_in_default_pythonpath.txt',
-}
+]}