You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.2 KiB
Python
164 lines
4.2 KiB
Python
import json
|
|
import os
|
|
import pathlib
|
|
import shutil
|
|
from pathlib import Path
|
|
from typing import Text
|
|
|
|
from jupyter_server.serverapp import ServerApp
|
|
from pytest import fixture
|
|
from tornado.httpserver import HTTPRequest
|
|
from tornado.httputil import HTTPServerRequest
|
|
from tornado.queues import Queue
|
|
from tornado.web import Application
|
|
|
|
# local imports
|
|
from jupyter_lsp import LanguageServerManager
|
|
from jupyter_lsp.constants import APP_CONFIG_D_SECTIONS
|
|
from jupyter_lsp.handlers import LanguageServersHandler, LanguageServerWebSocketHandler
|
|
|
|
# these should always be available in a test environment
|
|
KNOWN_SERVERS = [
|
|
"bash-language-server",
|
|
"dockerfile-language-server-nodejs",
|
|
"typescript-language-server",
|
|
"pylsp",
|
|
"unified-language-server",
|
|
"sql-language-server",
|
|
"vscode-css-languageserver-bin",
|
|
"vscode-html-languageserver-bin",
|
|
"vscode-json-languageserver-bin",
|
|
"yaml-language-server",
|
|
]
|
|
|
|
CMD_BASED_SERVERS = {
|
|
"Rscript": ["r-languageserver"],
|
|
"texlab": ["texlab"],
|
|
"jedi-language-server": ["jedi-language-server"],
|
|
"julia": ["julia-language-server"],
|
|
}
|
|
|
|
KNOWN_SERVERS += sum(
|
|
[langs for cmd, langs in CMD_BASED_SERVERS.items() if shutil.which(cmd)], []
|
|
)
|
|
|
|
KNOWN_UNKNOWN_SERVERS = ["foo-language-server"]
|
|
|
|
|
|
def extra_node_roots():
|
|
root = Path(os.environ.get("JLSP_TEST_ROOT") or Path.cwd())
|
|
return dict(extra_node_roots=[str(root)] if root else [])
|
|
|
|
|
|
@fixture
|
|
def manager() -> LanguageServerManager:
|
|
return LanguageServerManager(**extra_node_roots())
|
|
|
|
|
|
@fixture
|
|
def echo_spec():
|
|
return {"argv": ["echo", "no server here"], "languages": ["klingon"], "version": 2}
|
|
|
|
|
|
@fixture
|
|
def echo_conf_json(echo_spec) -> str:
|
|
return json.dumps(
|
|
{"LanguageServerManager": {"language_servers": {"_echo_": echo_spec}}},
|
|
indent=2,
|
|
sort_keys=True,
|
|
)
|
|
|
|
|
|
@fixture(params=sorted(APP_CONFIG_D_SECTIONS))
|
|
def app_config_d(request, tmp_path, monkeypatch) -> pathlib.Path:
|
|
conf_d = tmp_path / f"jupyter{request.param}config.d"
|
|
conf_d.mkdir()
|
|
monkeypatch.setenv("JUPYTER_CONFIG_PATH", f"{tmp_path}")
|
|
return conf_d
|
|
|
|
|
|
@fixture(params=sorted(KNOWN_SERVERS))
|
|
def known_server(request):
|
|
return request.param
|
|
|
|
|
|
@fixture(params=sorted(KNOWN_UNKNOWN_SERVERS))
|
|
def known_unknown_server(request):
|
|
return request.param
|
|
|
|
|
|
@fixture
|
|
def handlers(manager):
|
|
ws_handler = MockWebsocketHandler()
|
|
ws_handler.initialize(manager)
|
|
handler = MockHandler()
|
|
handler.initialize(manager)
|
|
return handler, ws_handler
|
|
|
|
|
|
@fixture
|
|
def jsonrpc_init_msg():
|
|
return json.dumps(
|
|
{
|
|
"id": 0,
|
|
"jsonrpc": "2.0",
|
|
"method": "initialize",
|
|
"params": {
|
|
"capabilities": {
|
|
# see: https://github.com/julia-vscode/LanguageServer.jl/issues/1008
|
|
# LanguageServer.jl assumes that it is not missing
|
|
"workspace": {"didChangeConfiguration": {}},
|
|
# LanguageServer.jl assumes that it is not missing
|
|
"textDocument": {},
|
|
},
|
|
"initializationOptions": None,
|
|
"processId": None,
|
|
"rootUri": pathlib.Path(__file__).parent.as_uri(),
|
|
"workspaceFolders": None,
|
|
},
|
|
}
|
|
)
|
|
|
|
|
|
@fixture
|
|
def app():
|
|
return MockServerApp()
|
|
|
|
|
|
# mocks
|
|
class MockWebsocketHandler(LanguageServerWebSocketHandler):
|
|
_messages_wrote = None # type: Queue
|
|
_ping_sent = None # type: bool
|
|
|
|
def __init__(self):
|
|
self.request = HTTPServerRequest()
|
|
self.application = Application()
|
|
|
|
def initialize(self, manager):
|
|
super().initialize(manager)
|
|
self._messages_wrote = Queue()
|
|
self._ping_sent = False
|
|
|
|
def write_message(self, message: Text) -> None: # type: ignore
|
|
self.log.warning("write_message %s", message)
|
|
self._messages_wrote.put_nowait(message)
|
|
|
|
def send_ping(self):
|
|
self._ping_sent = True
|
|
|
|
|
|
class MockHandler(LanguageServersHandler):
|
|
_payload = None
|
|
_jupyter_current_user = "foo" # type:ignore[assignment]
|
|
|
|
def __init__(self):
|
|
self.request = HTTPRequest("GET")
|
|
self.application = Application()
|
|
|
|
def finish(self, payload):
|
|
self._payload = payload
|
|
|
|
|
|
class MockServerApp(ServerApp):
|
|
pass
|