From 91b10d0409eeaf16c597bad05a3758daf30b2493 Mon Sep 17 00:00:00 2001 From: Anton Bachin Date: Sat, 27 Jan 2024 04:22:02 +0300 Subject: [PATCH] Convert pipe tests to cram and port to Windows --- test/pipe.ml | 300 ---------------------------- test/tester.ml | 1 - test/unit/pipe/bind.ml | 4 + test/unit/pipe/chmod.ml | 5 + test/unit/pipe/chmod_error.ml | 4 + test/unit/pipe/connect_exception.ml | 8 + test/unit/pipe/dune | 32 +++ test/unit/pipe/getpeername.ml | 9 + test/unit/pipe/getsockname.ml | 7 + test/unit/pipe/handle.ml | 12 ++ test/unit/pipe/helpers.ml | 30 +++ test/unit/pipe/listen_accept.ml | 9 + test/unit/pipe/pipe.t | 31 +++ test/unit/pipe/read_write.ml | 20 ++ test/unit/pipe/receive_handle.ml | 34 ++++ test/unit/pipe/trivial.ml | 3 + 16 files changed, 208 insertions(+), 301 deletions(-) delete mode 100644 test/pipe.ml create mode 100644 test/unit/pipe/bind.ml create mode 100644 test/unit/pipe/chmod.ml create mode 100644 test/unit/pipe/chmod_error.ml create mode 100644 test/unit/pipe/connect_exception.ml create mode 100644 test/unit/pipe/dune create mode 100644 test/unit/pipe/getpeername.ml create mode 100644 test/unit/pipe/getsockname.ml create mode 100644 test/unit/pipe/handle.ml create mode 100644 test/unit/pipe/helpers.ml create mode 100644 test/unit/pipe/listen_accept.ml create mode 100644 test/unit/pipe/pipe.t create mode 100644 test/unit/pipe/read_write.ml create mode 100644 test/unit/pipe/receive_handle.ml create mode 100644 test/unit/pipe/trivial.ml diff --git a/test/pipe.ml b/test/pipe.ml deleted file mode 100644 index 5b1cf035..00000000 --- a/test/pipe.ml +++ /dev/null @@ -1,300 +0,0 @@ -(* This file is part of Luv, released under the MIT license. See LICENSE.md for - details, or visit https://github.com/aantron/luv/blob/master/LICENSE.md. *) - - - -open Test_helpers - -let filename = - if not Sys.win32 then - "pipe" - else - "\\\\.\\pipe\\pipe" - -let with_pipe f = - let pipe = - Luv.Pipe.init () - |> check_success_result "init" - in - - f pipe; - - Luv.Handle.close pipe ignore; - run (); - - Alcotest.(check bool) "file deleted" false (Sys.file_exists filename) - -let with_server_and_client ?for_handle_passing () ~server_logic ~client_logic = - let server = - Luv.Pipe.init ?for_handle_passing () - |> check_success_result "server init" - in - Luv.Pipe.bind server filename |> check_success_result "bind"; - Luv.Stream.listen server begin fun result -> - check_success_result "listen" result; - let client = - Luv.Pipe.init ?for_handle_passing () - |> check_success_result "remote client init" - in - Luv.Stream.accept ~server ~client |> check_success_result "accept"; - server_logic server client - end; - - let client = - Luv.Pipe.init ?for_handle_passing () - |> check_success_result "client init" - in - Luv.Pipe.connect client filename begin fun result -> - check_success_result "connect" result; - client_logic client - end; - - run (); - - Alcotest.(check bool) "file deleted" false (Sys.file_exists filename) - -(* Until https://github.com/libuv/libuv/pull/1498. Should be out in 1.41.0. *) -let unix_fd_to_file unix_fd = - unix_fd - |> Luv.Unix.Os_fd.Fd.from_unix - |> check_success_result "from_unix" - |> Luv.File.open_osfhandle - |> check_success_result "get_osfhandle" - -let tests = [ - "pipe", [ - "init, close", `Quick, begin fun () -> - with_pipe ignore - end; - - "pipe", `Quick, begin fun () -> - let wrap file = - let pipe = Luv.Pipe.init () |> check_success_result "init" in - Luv.Pipe.open_ pipe file |> check_success_result "open_"; - pipe - in - let read_file, write_file = - Luv.Pipe.pipe () |> check_success_result "pipe" in - let read_pipe = wrap read_file in - let write_pipe = wrap write_file in - - Luv.Stream.write write_pipe [Luv.Buffer.from_string "x"] (fun _ _ -> ()); - Luv.Handle.close write_pipe ignore; - - let read = ref false in - - Luv.Stream.read_start read_pipe begin fun result -> - check_success_result "read_start" result - |> Luv.Buffer.to_string - |> Alcotest.(check string) "byte" "x"; - read := true; - Luv.Handle.close read_pipe ignore - end; - - run (); - - Alcotest.(check bool) "read" true !read - end; - - "bind", `Quick, begin fun () -> - with_pipe begin fun pipe -> - Luv.Pipe.bind pipe filename - |> check_success_result "bind"; - - Alcotest.(check bool) "created" true (Sys.file_exists filename) - end - end; - - "listen, accept", `Quick, begin fun () -> - let accepted = ref false in - let connected = ref false in - - (* On macOS, getpeername fails with EINVAL if the server closes the pipe - first. So, defer closing of handles until both the server and the - client have executed their main test logic. *) - let server_ran = event () in - let client_ran = event () in - - with_server_and_client () - ~server_logic: - begin fun server client -> - Luv.Pipe.getsockname client - |> check_success_result "getsockname result" - |> fun name -> - if not @@ List.mem name [filename; ""] then - Alcotest.failf "getpeername address: %s" name; - accepted := true; - proceed server_ran; - defer client_ran begin fun () -> - Luv.Handle.close client ignore; - Luv.Handle.close server ignore - end - end - ~client_logic: - begin fun client -> - Luv.Pipe.getpeername client - |> check_success_result "getpeername result" - |> fun name -> - if not @@ List.mem name [filename; "\\\\?\\pipe\\pipe"] then - Alcotest.failf "getpeername address: %s" name; - connected := true; - proceed client_ran; - defer server_ran (fun () -> Luv.Handle.close client ignore) - end; - - Alcotest.(check bool) "accepted" true !accepted; - Alcotest.(check bool) "connected" true !connected - end; - - "connect: exception", `Quick, begin fun () -> - check_exception Exit begin fun () -> - with_server_and_client () - ~server_logic: - begin fun server client -> - Luv.Handle.close client ignore; - Luv.Handle.close server ignore - end - ~client_logic: - begin fun client -> - Luv.Handle.close client ignore; - raise Exit - end - end - end; - - "read, write", `Quick, begin fun () -> - let write_finished = ref false in - let read_finished = ref false in - - with_server_and_client () - ~server_logic: - begin fun server client -> - Luv.Stream.read_start client begin fun result -> - check_success_result "read_start" result - |> Luv.Buffer.to_string - |> Alcotest.(check string) "data" "foo"; - - Luv.Handle.close client ignore; - Luv.Handle.close server ignore; - - read_finished := true - end - end - ~client_logic: - begin fun client -> - let buffer1 = Luv.Buffer.from_string "fo" in - let buffer2 = Luv.Buffer.from_string "o" in - - Luv.Stream.write client [buffer1; buffer2] begin fun result count -> - check_success_result "write" result; - Alcotest.(check int) "count" 3 count; - Luv.Handle.close client ignore; - write_finished := true - end - end; - - Alcotest.(check bool) "write finished" true !write_finished; - Alcotest.(check bool) "read finished" true !read_finished - end; - - "open_, receive_handle, write2", `Quick, begin fun () -> - let wrap ~for_handle_passing fd = - let pipe = - Luv.Pipe.init ~for_handle_passing () |> check_success_result "init" in - Luv.Pipe.open_ pipe (unix_fd_to_file fd) - |> check_success_result "open_"; - pipe - in - - let ipc_1, ipc_2 = Unix.(socketpair PF_UNIX SOCK_STREAM) 0 in - let ipc_1 = wrap ~for_handle_passing:true ipc_1 in - let ipc_2 = wrap ~for_handle_passing:true ipc_2 in - - let passed_1, passed_2 = Unix.(socketpair PF_UNIX SOCK_STREAM) 0 in - let passed_1 = wrap ~for_handle_passing:false passed_1 in - let passed_2 = wrap ~for_handle_passing:false passed_2 in - - Luv.Stream.read_start ipc_1 begin fun result -> - Luv.Stream.read_stop ipc_1 |> check_success_result "read_stop"; - - check_success_result "read_start" result - |> Luv.Buffer.size - |> Alcotest.(check int) "read byte count" 1; - - begin match Luv.Pipe.receive_handle ipc_1 with - | `Pipe receive -> - let received = - Luv.Pipe.init () |> check_success_result "init received" in - receive received |> check_success_result "handle accept"; - let buffer = Luv.Buffer.from_string "x" in - Luv.Stream.try_write received [buffer] - |> check_success_result "try_write" - |> Alcotest.(check int) "write byte count" 1; - Luv.Handle.close received ignore - | `TCP _ -> - ignore (Alcotest.fail "expected a pipe, got a TCP handle") - | `None -> - ignore (Alcotest.fail "expected a pipe, got nothing") - end - end; - - let buffer = Luv.Buffer.create 1 in - Luv.Stream.write2 ipc_2 [buffer] ~send_handle:passed_1 - begin fun result count -> - - check_success_result "write2" result; - Alcotest.(check int) "count" 1 count; - end; - - let did_read = ref false in - - Luv.Stream.read_start passed_2 begin fun result -> - Luv.Stream.read_stop passed_2 |> check_success_result "read_stop"; - check_success_result "read_start" result - |> Luv.Buffer.to_string - |> Alcotest.(check string) "data" "x"; - did_read := true - end; - - run (); - - Luv.Handle.close ipc_1 ignore; - Luv.Handle.close ipc_2 ignore; - Luv.Handle.close passed_1 ignore; - Luv.Handle.close passed_2 ignore; - - run (); - - Alcotest.(check bool) "did read" true !did_read - end; - - "chmod, unbound", `Quick, begin fun () -> - with_pipe begin fun pipe -> - Luv.Pipe.chmod pipe [`READABLE] - |> check_error_result "chmod" `EBADF - end - end; - - "chmod", `Quick, begin fun () -> - with_pipe begin fun pipe -> - Luv.Pipe.bind pipe filename - |> check_success_result "bind"; - - Luv.Pipe.chmod pipe [`READABLE] - |> check_success_result "chmod" - end - end; - - (* This is a compilation test. If the type constraints in handle.mli are - wrong, there will be a type error in this test. *) - "handle functions", `Quick, begin fun () -> - with_pipe begin fun pipe -> - ignore @@ Luv.Handle.send_buffer_size pipe; - ignore @@ Luv.Handle.recv_buffer_size pipe; - ignore @@ Luv.Handle.set_send_buffer_size pipe 4096; - ignore @@ Luv.Handle.set_recv_buffer_size pipe 4096; - ignore @@ Luv.Handle.fileno pipe - end - end; - ] -] diff --git a/test/tester.ml b/test/tester.ml index 5882ba4b..34449157 100644 --- a/test/tester.ml +++ b/test/tester.ml @@ -5,7 +5,6 @@ let () = Alcotest.run "luv" (List.flatten [ - if not Sys.win32 then Pipe.tests else []; UDP.tests; TTY.tests; File.tests; diff --git a/test/unit/pipe/bind.ml b/test/unit/pipe/bind.ml new file mode 100644 index 00000000..52994c72 --- /dev/null +++ b/test/unit/pipe/bind.ml @@ -0,0 +1,4 @@ +let () = + Helpers.with_pipe @@ fun pipe -> + Luv.Pipe.bind pipe Helpers.filename |> ok "bind" @@ fun () -> + print_endline "Ok" diff --git a/test/unit/pipe/chmod.ml b/test/unit/pipe/chmod.ml new file mode 100644 index 00000000..12195b4e --- /dev/null +++ b/test/unit/pipe/chmod.ml @@ -0,0 +1,5 @@ +let () = + Helpers.with_pipe @@ fun pipe -> + Luv.Pipe.bind pipe Helpers.filename |> ok "bind" @@ fun () -> + Luv.Pipe.chmod pipe [`READABLE] |> ok "chmod" @@ fun () -> + print_endline "Ok" diff --git a/test/unit/pipe/chmod_error.ml b/test/unit/pipe/chmod_error.ml new file mode 100644 index 00000000..22bd12b7 --- /dev/null +++ b/test/unit/pipe/chmod_error.ml @@ -0,0 +1,4 @@ +let () = + Helpers.with_pipe @@ fun pipe -> + Luv.Pipe.chmod pipe [`READABLE] |> error [`EBADF] "chmod" @@ fun () -> + print_endline "Ok" diff --git a/test/unit/pipe/connect_exception.ml b/test/unit/pipe/connect_exception.ml new file mode 100644 index 00000000..c12c1c04 --- /dev/null +++ b/test/unit/pipe/connect_exception.ml @@ -0,0 +1,8 @@ +let () = + Luv.Error.set_on_unhandled_exception (function + | Exit -> print_endline "Ok"; exit 0 + | _ -> ()); + + Helpers.with_server_and_client () + ~server:(fun server_pipe accept_pipe -> Luv.Handle.close server_pipe ignore) + ~client:(fun client_pipe -> raise Exit) diff --git a/test/unit/pipe/dune b/test/unit/pipe/dune new file mode 100644 index 00000000..851e1940 --- /dev/null +++ b/test/unit/pipe/dune @@ -0,0 +1,32 @@ +(cram + (alias runtest-windows) + (deps + trivial.exe + bind.exe + listen_accept.exe + getsockname.exe + getpeername.exe + connect_exception.exe + read_write.exe + receive_handle.exe + chmod.exe + chmod_error.exe + handle.exe + )) + +(executables + (names + trivial + bind + listen_accept + getsockname + getpeername + connect_exception + read_write + receive_handle + chmod + chmod_error + handle + ) + (libraries luv unit_helpers) + (flags -open Unit_helpers)) diff --git a/test/unit/pipe/getpeername.ml b/test/unit/pipe/getpeername.ml new file mode 100644 index 00000000..22e34768 --- /dev/null +++ b/test/unit/pipe/getpeername.ml @@ -0,0 +1,9 @@ +let () = + Helpers.with_server_and_client () + ~server:begin fun server_pipe accept_pipe -> + Luv.Handle.close server_pipe ignore + end + ~client:begin fun client_pipe -> + Luv.Pipe.getpeername client_pipe |> ok "getpeername" @@ fun filename' -> + Printf.printf "%b\n" (filename' = Helpers.filename) + end diff --git a/test/unit/pipe/getsockname.ml b/test/unit/pipe/getsockname.ml new file mode 100644 index 00000000..8f9d18d4 --- /dev/null +++ b/test/unit/pipe/getsockname.ml @@ -0,0 +1,7 @@ +let () = + Helpers.with_pipe @@ fun pipe -> + + Luv.Pipe.bind pipe Helpers.filename |> ok "bind" @@ fun () -> + Luv.Pipe.getsockname pipe |> ok "getsockname" @@ fun filename' -> + + Printf.printf "%b\n" (filename' = Helpers.filename) diff --git a/test/unit/pipe/handle.ml b/test/unit/pipe/handle.ml new file mode 100644 index 00000000..6111743f --- /dev/null +++ b/test/unit/pipe/handle.ml @@ -0,0 +1,12 @@ +(* This is a compilation test. If the type constraints in handle.mli are wrong, + there will be a type error in this test. *) +let () = + Helpers.with_pipe begin fun pipe -> + ignore @@ Luv.Handle.send_buffer_size pipe; + ignore @@ Luv.Handle.recv_buffer_size pipe; + ignore @@ Luv.Handle.set_send_buffer_size pipe 4096; + ignore @@ Luv.Handle.set_recv_buffer_size pipe 4096; + ignore @@ Luv.Handle.fileno pipe + end; + + print_endline "Ok" diff --git a/test/unit/pipe/helpers.ml b/test/unit/pipe/helpers.ml new file mode 100644 index 00000000..866fa995 --- /dev/null +++ b/test/unit/pipe/helpers.ml @@ -0,0 +1,30 @@ +let filename = + if Sys.win32 then + {|\\.\pipe\pipe|} + else + "pipe" + +let with_pipe f = + Luv.Pipe.init () |> ok "init" @@ fun tcp -> + f tcp; + Luv.Handle.close tcp ignore + +let with_server_and_client ?(for_handle_passing = false) () ~server ~client = + Luv.Pipe.init () |> ok "server init" @@ fun server_pipe -> + Luv.Pipe.bind server_pipe filename |> ok "bind" @@ fun () -> + Luv.Stream.listen server_pipe begin fun result -> + result |> ok "listen" @@ fun () -> + Luv.Pipe.init ~for_handle_passing () + |> ok "accept init" @@ fun accept_pipe -> + Luv.Stream.accept ~server:server_pipe ~client:accept_pipe + |> ok "accept" @@ fun () -> + server server_pipe accept_pipe + end; + + Luv.Pipe.init ~for_handle_passing () |> ok "client init" @@ fun client_pipe -> + Luv.Pipe.connect client_pipe filename begin fun result -> + result |> ok "connect" @@ fun () -> + client client_pipe + end; + + Luv.Loop.run () |> ignore diff --git a/test/unit/pipe/listen_accept.ml b/test/unit/pipe/listen_accept.ml new file mode 100644 index 00000000..e4ad5a4e --- /dev/null +++ b/test/unit/pipe/listen_accept.ml @@ -0,0 +1,9 @@ +let () = + Helpers.with_server_and_client () + ~server:begin fun server_pipe accept_pipe -> + prerr_endline "Accepted"; + Luv.Handle.close server_pipe ignore + end + ~client:begin fun client_pipe -> + Luv.Handle.close client_pipe ignore + end diff --git a/test/unit/pipe/pipe.t b/test/unit/pipe/pipe.t new file mode 100644 index 00000000..4b71808e --- /dev/null +++ b/test/unit/pipe/pipe.t @@ -0,0 +1,31 @@ + $ dune exec ./trivial.exe + Ok + + $ dune exec ./bind.exe + Ok + + $ dune exec ./listen_accept.exe + Accepted + + $ dune exec ./getsockname.exe + true + + $ dune exec ./getpeername.exe + true + + $ dune exec ./connect_exception.exe + Ok + + $ dune exec ./receive_handle.exe + 3 + "foo" + Ok + + $ dune exec ./chmod.exe + Ok + + $ dune exec ./chmod_error.exe + Ok + + $ dune exec ./handle.exe + Ok diff --git a/test/unit/pipe/read_write.ml b/test/unit/pipe/read_write.ml new file mode 100644 index 00000000..3998d5d9 --- /dev/null +++ b/test/unit/pipe/read_write.ml @@ -0,0 +1,20 @@ +let () = + Helpers.with_server_and_client () + ~server:begin fun server_pipe accept_pipe -> + Luv.Stream.read_start accept_pipe begin fun result -> + result |> ok "read_start" @@ fun b -> + Printf.printf "%S\n" (Luv.Buffer.to_string b); + Luv.Handle.close accept_pipe ignore; + Luv.Handle.close server_pipe ignore + end + end + ~client:begin fun client_pipe -> + let b1 = Luv.Buffer.from_string "fo" in + let b2 = Luv.Buffer.from_string "o" in + + Luv.Stream.write client_pipe [b1; b2] begin fun result count -> + Luv.Handle.close client_pipe ignore; + result |> ok "write" @@ fun () -> + Printf.printf "%i\n" count + end + end diff --git a/test/unit/pipe/receive_handle.ml b/test/unit/pipe/receive_handle.ml new file mode 100644 index 00000000..098d853e --- /dev/null +++ b/test/unit/pipe/receive_handle.ml @@ -0,0 +1,34 @@ +let () = + Helpers.with_server_and_client ~for_handle_passing:true () + ~server:begin fun server_pipe accept_pipe -> + Luv.Stream.read_start accept_pipe begin fun result -> + result |> ok "read_start" @@ fun b -> + Printf.printf "%S\n" (Luv.Buffer.to_string b); + begin match Luv.Pipe.receive_handle accept_pipe with + | `TCP receive -> + Luv.TCP.init () |> ok "received tcp init" @@ fun tcp -> + receive tcp |> ok "receive" @@ fun () -> + Luv.Handle.close tcp ignore; + print_endline "Ok" + | `Pipe _ -> + print_endline "Got a pipe" + | `None -> + print_endline "No handle" + end; + Luv.Handle.close accept_pipe ignore; + Luv.Handle.close server_pipe ignore + end + end + ~client:begin fun client_pipe -> + Luv.TCP.init () |> ok "tcp init" @@ fun tcp -> + Luv.Sockaddr.ipv4 "127.0.0.1" 5199 |> ok "ipv4" @@ fun address -> + Luv.TCP.bind tcp address |> ok "tcp bind" @@ fun () -> + + let b = Luv.Buffer.from_string "foo" in + let send_handle = tcp in + Luv.Stream.write2 client_pipe [b] ~send_handle begin fun result count -> + Luv.Handle.close client_pipe ignore; + result |> ok "write" @@ fun () -> + Printf.printf "%i\n" count + end + end diff --git a/test/unit/pipe/trivial.ml b/test/unit/pipe/trivial.ml new file mode 100644 index 00000000..d9ae5721 --- /dev/null +++ b/test/unit/pipe/trivial.ml @@ -0,0 +1,3 @@ +let () = + Helpers.with_pipe ignore; + print_endline "Ok"