Skip to content

Commit 916713c

Browse files
committed
test: add e2e test written in ocaml
to eventually move from typescript Signed-off-by: Rudi Grinberg <[email protected]> ps-id: 4CC3EB73-8829-4570-A406-CF9BAF35BFC2
1 parent 922f637 commit 916713c

File tree

4 files changed

+156
-10
lines changed

4 files changed

+156
-10
lines changed

jsonrpc-fiber/src/jsonrpc_fiber.ml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ struct
275275
close t)
276276

277277
let check_running t =
278-
(* TODO we should also error out when making requests after a disconnect. *)
279278
if not t.running then Code_error.raise "jsonrpc must be running" []
280279

281280
let notification t (n : Notification.t) =

lsp-fiber/src/rpc.ml

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,17 @@ struct
162162
Format.eprintf "dropped notification@.%!";
163163
assert false
164164

165-
let make ?on_request ?(on_notification = on_notification_default) () =
166-
let h_on_request =
167-
match on_request with
168-
| Some t -> t
169-
| None -> assert false
170-
in
171-
{ h_on_request; h_on_notification = on_notification }
165+
let on_request_default =
166+
{ on_request =
167+
(fun _ _ ->
168+
Jsonrpc.Response.Error.make ~code:InternalError
169+
~message:"Not supported" ()
170+
|> Jsonrpc.Response.Error.raise)
171+
}
172+
173+
let make ?(on_request = on_request_default)
174+
?(on_notification = on_notification_default) () =
175+
{ h_on_request = on_request; h_on_notification = on_notification }
172176
end
173177

174178
let state t = Session.state (Fdecl.get t.session)
@@ -379,7 +383,7 @@ module Client = struct
379383
let start (t : _ t) (p : InitializeParams.t) =
380384
Fiber.of_thunk (fun () ->
381385
assert (t.state = Waiting_for_init);
382-
let loop = start_loop t in
386+
let loop () = start_loop t in
383387
let init () =
384388
let* resp = request t (Client_request.Initialize p) in
385389
Log.log ~section:"client" (fun () ->
@@ -388,7 +392,7 @@ module Client = struct
388392
t.state <- Running;
389393
Fiber.Ivar.fill t.initialized resp
390394
in
391-
Fiber.fork_and_join_unit (fun () -> loop) init)
395+
Fiber.fork_and_join_unit loop init)
392396
end
393397

394398
module Server = struct

ocaml-lsp-server/test/e2e-new/dune

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
(library
2+
(name ocaml_lsp_e2e)
3+
(inline_tests
4+
(deps
5+
(package ocaml-lsp-server)))
6+
(libraries
7+
stdune
8+
fiber
9+
yojson
10+
lev_fiber
11+
lev
12+
spawn
13+
lsp
14+
lsp_fiber
15+
;; This is because of the (implicit_transitive_deps false)
16+
;; in dune-project
17+
base
18+
ppx_expect.common
19+
ppx_expect.config
20+
ppx_expect.config_types
21+
ppx_inline_test.config)
22+
(preprocess
23+
(pps ppx_expect)))
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
open Stdune
2+
open Fiber.O
3+
4+
let _PATH =
5+
Bin.parse_path (Option.value ~default:"" @@ Env.get Env.initial "PATH")
6+
7+
let bin = Bin.which "ocamllsp" ~path:_PATH |> Option.value_exn |> Path.to_string
8+
9+
let env = Spawn.Env.of_list [ "OCAMLLSP_TEST=true" ]
10+
11+
module Client = Lsp_fiber.Client
12+
open Lsp.Types
13+
14+
let%expect_test "start/stop" =
15+
let stdin_i, stdin_o = Unix.pipe ~cloexec:true () in
16+
let stdout_i, stdout_o = Unix.pipe ~cloexec:true () in
17+
let pid =
18+
Spawn.spawn ~env ~prog:bin ~argv:[ bin ] ~stdin:stdin_i ~stdout:stdout_o ()
19+
in
20+
Unix.close stdin_i;
21+
Unix.close stdout_o;
22+
let handler = Client.Handler.make () in
23+
let init =
24+
let blockity =
25+
if Sys.win32 then `Blocking
26+
else (
27+
Unix.set_nonblock stdout_i;
28+
Unix.set_nonblock stdin_o;
29+
`Non_blocking true)
30+
in
31+
let make fd what =
32+
let fd = Lev_fiber.Fd.create fd blockity in
33+
Lev_fiber.Io.create fd what
34+
in
35+
let* in_ = make stdout_i Input in
36+
let* out = make stdin_o Output in
37+
let io = Lsp_fiber.Fiber_io.make in_ out in
38+
let client = Client.make handler io () in
39+
let run_client () =
40+
let capabilities = ClientCapabilities.create () in
41+
Client.start client (InitializeParams.create ~capabilities ())
42+
in
43+
let print_init =
44+
let+ resp = Client.initialized client in
45+
print_endline "client: server initialized with:";
46+
InitializeResult.yojson_of_t resp
47+
|> Yojson.Safe.pretty_to_string ~std:false
48+
|> print_endline
49+
in
50+
let run =
51+
let* () = print_init in
52+
print_endline "client: shutting down server";
53+
Client.request client Shutdown
54+
in
55+
Fiber.fork_and_join_unit run_client (fun () -> run >>> Client.stop client)
56+
in
57+
let waitpid =
58+
let+ (_ : Unix.process_status) = Lev_fiber.waitpid ~pid in
59+
()
60+
in
61+
Lev_fiber.run
62+
~f:(fun () -> Fiber.all_concurrently_unit [ init; waitpid ])
63+
(Lev.Loop.default ());
64+
[%expect
65+
{|
66+
client: server initialized with:
67+
{
68+
"capabilities": {
69+
"textDocumentSync": {
70+
"openClose": true,
71+
"change": 2,
72+
"willSave": false,
73+
"willSaveWaitUntil": false,
74+
"save": true
75+
},
76+
"completionProvider": {
77+
"triggerCharacters": [ ".", "#" ],
78+
"resolveProvider": true
79+
},
80+
"hoverProvider": true,
81+
"signatureHelpProvider": {
82+
"triggerCharacters": [ " ", "~", "?", ":", "(" ]
83+
},
84+
"declarationProvider": true,
85+
"definitionProvider": true,
86+
"typeDefinitionProvider": true,
87+
"referencesProvider": true,
88+
"documentHighlightProvider": true,
89+
"documentSymbolProvider": true,
90+
"codeActionProvider": {
91+
"codeActionKinds": [
92+
"quickfix", "construct", "destruct", "inferred_intf",
93+
"put module name in identifiers",
94+
"remove module name from identifiers", "type-annotate"
95+
]
96+
},
97+
"codeLensProvider": { "resolveProvider": false },
98+
"documentFormattingProvider": true,
99+
"renameProvider": { "prepareProvider": true },
100+
"foldingRangeProvider": true,
101+
"executeCommandProvider": { "commands": [ "dune/promote" ] },
102+
"selectionRangeProvider": true,
103+
"workspaceSymbolProvider": true,
104+
"workspace": {
105+
"workspaceFolders": { "supported": true, "changeNotifications": true }
106+
},
107+
"experimental": {
108+
"ocamllsp": {
109+
"interfaceSpecificLangId": true,
110+
"handleSwitchImplIntf": true,
111+
"handleInferIntf": true,
112+
"handleTypedHoles": true,
113+
"handleWrappingAstNode": true,
114+
"diagnostic_promotions": true
115+
}
116+
}
117+
},
118+
"serverInfo": { "name": "ocamllsp", "version": "dev" }
119+
}
120+
client: shutting down server |}]

0 commit comments

Comments
 (0)