1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
import asyncio
import json
import os
from threading import Thread
from unittest.mock import Mock
import pytest
from pygls import IS_PYODIDE
from pygls.server import LanguageServer
try:
import websockets
WEBSOCKETS_AVAILABLE = True
except ImportError:
WEBSOCKETS_AVAILABLE = False
@pytest.mark.asyncio
@pytest.mark.skipif(IS_PYODIDE, reason="threads are not available in pyodide.")
async def test_tcp_connection_lost():
loop = asyncio.new_event_loop()
server = LanguageServer("pygls-test", "v1", loop=loop)
server.lsp.connection_made = Mock()
server.lsp.connection_lost = Mock()
# Run the server over TCP in a separate thread
server_thread = Thread(
target=server.start_tcp,
args=(
"127.0.0.1",
0,
),
)
server_thread.daemon = True
server_thread.start()
# Wait for server to be ready
while server._server is None:
await asyncio.sleep(0.5)
# Simulate client's connection
port = server._server.sockets[0].getsockname()[1]
reader, writer = await asyncio.open_connection("127.0.0.1", port)
await asyncio.sleep(1)
assert server.lsp.connection_made.called
# Socket is closed (client's process is terminated)
writer.close()
await asyncio.sleep(1)
assert server.lsp.connection_lost.called
@pytest.mark.asyncio
@pytest.mark.skipif(IS_PYODIDE, reason="threads are not available in pyodide.")
async def test_io_connection_lost():
# Client to Server pipe.
csr, csw = os.pipe()
# Server to client pipe.
scr, scw = os.pipe()
server = LanguageServer("pygls-test", "v1", loop=asyncio.new_event_loop())
server.lsp.connection_made = Mock()
server_thread = Thread(
target=server.start_io, args=(os.fdopen(csr, "rb"), os.fdopen(scw, "wb"))
)
server_thread.daemon = True
server_thread.start()
# Wait for server to be ready
while not server.lsp.connection_made.called:
await asyncio.sleep(0.5)
# Pipe is closed (client's process is terminated)
os.close(csw)
server_thread.join()
@pytest.mark.asyncio
@pytest.mark.skipif(
IS_PYODIDE or not WEBSOCKETS_AVAILABLE,
reason="threads are not available in pyodide",
)
async def test_ws_server():
"""Smoke test to ensure we can send/receive messages over websockets"""
loop = asyncio.new_event_loop()
server = LanguageServer("pygls-test", "v1", loop=loop)
# Run the server over Websockets in a separate thread
server_thread = Thread(
target=server.start_ws,
args=(
"127.0.0.1",
0,
),
)
server_thread.daemon = True
server_thread.start()
# Wait for server to be ready
while server._server is None:
await asyncio.sleep(0.5)
port = server._server.sockets[0].getsockname()[1]
# Simulate client's connection
async with websockets.connect(f"ws://127.0.0.1:{port}") as connection:
# Send an 'initialize' request
msg = dict(
jsonrpc="2.0", id=1, method="initialize", params=dict(capabilities=dict())
)
await connection.send(json.dumps(msg))
response = await connection.recv()
assert "result" in response
# Shut the server down
msg = dict(
jsonrpc="2.0", id=2, method="shutdown", params=dict(capabilities=dict())
)
await connection.send(json.dumps(msg))
response = await connection.recv()
assert "result" in response
# Finally, tell it to exit
msg = dict(jsonrpc="2.0", id=2, method="exit", params=None)
await connection.send(json.dumps(msg))
server_thread.join()
|