This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
17
unikernel/duniverse/dune_/test/unit-tests/fswatch_win/dune
Normal file
17
unikernel/duniverse/dune_/test/unit-tests/fswatch_win/dune
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
(executable
|
||||
(name fswatch_win_tests)
|
||||
(libraries fswatch_win unix stdune))
|
||||
|
||||
(rule
|
||||
(alias fswatch_win_tests)
|
||||
(deps
|
||||
(sandbox always))
|
||||
(action
|
||||
(run ./fswatch_win_tests.exe)))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(enabled_if
|
||||
(= %{os_type} Win32))
|
||||
(deps
|
||||
(alias fswatch_win_tests)))
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
open Stdune
|
||||
|
||||
let remove_dot_slash s = String.drop_prefix s ~prefix:".\\" |> Option.value ~default:s
|
||||
let create_file fn = Io.String_path.write_file fn ""
|
||||
let mkdir fn = Unix.mkdir fn 0o777
|
||||
|
||||
type event =
|
||||
{ action : string
|
||||
; path : string
|
||||
}
|
||||
|
||||
let dyn_of_event ev =
|
||||
let action =
|
||||
match Fswatch_win.Event.action ev with
|
||||
| Added -> "added"
|
||||
| Removed -> "removed"
|
||||
| Modified -> "modified"
|
||||
| Renamed_old -> "renamed_old"
|
||||
| Renamed_new -> "renamed_new"
|
||||
in
|
||||
let path = remove_dot_slash (Fswatch_win.Event.path ev) in
|
||||
Dyn.record [ "action", Dyn.string action; "path", Dyn.string path ]
|
||||
;;
|
||||
|
||||
let dyn_of_event' { action; path } =
|
||||
let path = remove_dot_slash path in
|
||||
Dyn.record [ "action", Dyn.string action; "path", Dyn.string path ]
|
||||
;;
|
||||
|
||||
let print_events events = print_endline (Dyn.to_string (Dyn.list Fun.id events))
|
||||
let markdir = Filename.concat (Sys.getcwd ()) "mark"
|
||||
let beginning_of_test = "BEGINNING_OF_TEST"
|
||||
let end_of_test = "END_OF_TEST"
|
||||
|
||||
let watch, collect_events =
|
||||
(* File used to mark the beginning and end of tests. *)
|
||||
mkdir markdir;
|
||||
let beginning_of_test_file = Filename.concat markdir beginning_of_test in
|
||||
let end_of_test_file = Filename.concat markdir end_of_test in
|
||||
create_file beginning_of_test_file;
|
||||
create_file end_of_test_file;
|
||||
let fswatch = Fswatch_win.create () in
|
||||
let watch dir =
|
||||
let dir =
|
||||
if Filename.is_relative dir then Filename.concat (Sys.getcwd ()) dir else dir
|
||||
in
|
||||
Fswatch_win.add fswatch dir
|
||||
in
|
||||
watch markdir;
|
||||
let rec collect_events acc = function
|
||||
| [] ->
|
||||
let events = Fswatch_win.wait fswatch ~sleep:0 in
|
||||
collect_events acc events
|
||||
| e :: events when Fswatch_win.Event.path e = end_of_test ->
|
||||
if not (List.is_empty events)
|
||||
then (
|
||||
Printf.printf "***** Leftover events after end of test marker event *****\n";
|
||||
print_events (List.map ~f:dyn_of_event events));
|
||||
List.rev_map ~f:dyn_of_event acc
|
||||
| ev :: events -> collect_events (ev :: acc) events
|
||||
in
|
||||
let collect_events () =
|
||||
(* Mark the beginning of the current test *)
|
||||
create_file end_of_test_file;
|
||||
let events =
|
||||
let events = Fswatch_win.wait fswatch ~sleep:0 in
|
||||
(* List.iter ~f:(fun ev -> print_endline (Dyn.to_string (Fswatch_win.Event.to_dyn ev))) events; *)
|
||||
match events with
|
||||
| [] -> assert false
|
||||
| e :: events when Fswatch_win.Event.path e = beginning_of_test ->
|
||||
collect_events [] events
|
||||
| events ->
|
||||
Printf.printf "***** First event is not the beginning of test marker *****\n";
|
||||
collect_events [] events
|
||||
in
|
||||
(* Mark the beginning of the next test *)
|
||||
create_file beginning_of_test_file;
|
||||
events
|
||||
in
|
||||
create_file beginning_of_test_file;
|
||||
watch, collect_events
|
||||
;;
|
||||
|
||||
(* Run a function in a sub-directory *)
|
||||
let in_sub_dir =
|
||||
let n = ref 0 in
|
||||
fun f ->
|
||||
incr n;
|
||||
let dir = Printf.sprintf "test%d" !n in
|
||||
mkdir dir;
|
||||
Sys.chdir dir;
|
||||
Exn.protect ~finally:(fun () -> Sys.chdir "..") ~f
|
||||
;;
|
||||
|
||||
let check_events ~real_events expected_events =
|
||||
let expected_events = List.map ~f:dyn_of_event' expected_events in
|
||||
if real_events = expected_events
|
||||
then ()
|
||||
else (
|
||||
print_endline "** FAILURE **";
|
||||
print_endline "ACTUAL:";
|
||||
print_events real_events;
|
||||
print_endline "EXPECTED:";
|
||||
print_events expected_events;
|
||||
exit 1)
|
||||
;;
|
||||
|
||||
let _ =
|
||||
in_sub_dir
|
||||
@@ fun () ->
|
||||
let fn = "file" in
|
||||
create_file fn;
|
||||
watch ".";
|
||||
create_file fn;
|
||||
check_events ~real_events:(collect_events ()) [ { action = "modified"; path = fn } ]
|
||||
;;
|
||||
|
||||
let fold_int n ~init ~f =
|
||||
let rec loop i acc = if i = n then acc else loop (i + 1) (f i acc) in
|
||||
loop 0 init
|
||||
;;
|
||||
|
||||
type kind =
|
||||
| File
|
||||
| Dir
|
||||
|
||||
let rec gen_tree acc ~dir ~depth ~files_per_dir ~sub_dirs_per_dir =
|
||||
let acc =
|
||||
fold_int files_per_dir ~init:acc ~f:(fun n acc ->
|
||||
let fn = Filename.concat dir (Printf.sprintf "f%d" (n + 1)) in
|
||||
create_file fn;
|
||||
(File, fn) :: acc)
|
||||
in
|
||||
if depth = 0
|
||||
then acc
|
||||
else
|
||||
fold_int sub_dirs_per_dir ~init:acc ~f:(fun n acc ->
|
||||
let dir = Filename.concat dir (Printf.sprintf "d%d" (n + 1)) in
|
||||
let acc = (Dir, dir) :: acc in
|
||||
mkdir dir;
|
||||
gen_tree acc ~dir ~depth:(depth - 1) ~files_per_dir ~sub_dirs_per_dir)
|
||||
;;
|
||||
|
||||
let gen_tree ~depth ~files_per_dir ~sub_dirs_per_dir =
|
||||
List.rev (gen_tree [ Dir, "." ] ~dir:"." ~depth ~files_per_dir ~sub_dirs_per_dir)
|
||||
;;
|
||||
|
||||
let _ =
|
||||
(* Show that gen_tree generates filenames in the right order *)
|
||||
in_sub_dir
|
||||
@@ fun () ->
|
||||
let entries =
|
||||
List.map (gen_tree ~depth:1 ~files_per_dir:2 ~sub_dirs_per_dir:2) ~f:Stdlib.snd
|
||||
in
|
||||
(* List.iter ~f:print_endline entries; *)
|
||||
assert (
|
||||
List.map ~f:remove_dot_slash entries
|
||||
= [ "."; "f1"; "f2"; "d1"; "d1\\f1"; "d1\\f2"; "d2"; "d2\\f1"; "d2\\f2" ])
|
||||
;;
|
||||
|
||||
(* Return the expected set of inotify events *)
|
||||
let gen_changes files =
|
||||
List.iter files ~f:(function
|
||||
| Dir, fn ->
|
||||
let new_file = Filename.concat fn "new-file" in
|
||||
let new_dir = Filename.concat fn "new-dir" in
|
||||
create_file new_file;
|
||||
mkdir new_dir;
|
||||
Unix.rmdir new_dir;
|
||||
Sys.remove new_file
|
||||
| File, fn -> create_file fn)
|
||||
;;
|
||||
|
||||
let setup1 ~depth ~files_per_dir ~sub_dirs_per_dir =
|
||||
let files = gen_tree ~depth ~files_per_dir ~sub_dirs_per_dir in
|
||||
watch ".";
|
||||
files, collect_events
|
||||
;;
|
||||
|
||||
let _ =
|
||||
(* Check that FS events are reported chronologically *)
|
||||
in_sub_dir
|
||||
@@ fun () ->
|
||||
let files, collect_events = setup1 ~depth:2 ~files_per_dir:3 ~sub_dirs_per_dir:2 in
|
||||
gen_changes files;
|
||||
check_events
|
||||
~real_events:(collect_events ())
|
||||
[ { action = "added"; path = "new-file" }
|
||||
; { action = "added"; path = "new-dir" }
|
||||
; { action = "removed"; path = "new-dir" }
|
||||
; { action = "removed"; path = "new-file" }
|
||||
; { action = "modified"; path = "f1" }
|
||||
; { action = "modified"; path = "f2" }
|
||||
; { action = "modified"; path = "f3" }
|
||||
; { action = "added"; path = "d1\\new-file" }
|
||||
; { action = "added"; path = "d1\\new-dir" }
|
||||
; { action = "removed"; path = "d1\\new-dir" }
|
||||
; { action = "removed"; path = "d1\\new-file" }
|
||||
; { action = "modified"; path = "d1\\f1" }
|
||||
; { action = "modified"; path = "d1\\f2" }
|
||||
; { action = "modified"; path = "d1\\f3" }
|
||||
; { action = "added"; path = "d1\\d1\\new-file" }
|
||||
; { action = "added"; path = "d1\\d1\\new-dir" }
|
||||
; { action = "removed"; path = "d1\\d1\\new-dir" }
|
||||
; { action = "removed"; path = "d1\\d1\\new-file" }
|
||||
; { action = "modified"; path = "d1\\d1\\f1" }
|
||||
; { action = "modified"; path = "d1\\d1\\f2" }
|
||||
; { action = "modified"; path = "d1\\d1\\f3" }
|
||||
; { action = "added"; path = "d1\\d2\\new-file" }
|
||||
; { action = "added"; path = "d1\\d2\\new-dir" }
|
||||
; { action = "removed"; path = "d1\\d2\\new-dir" }
|
||||
; { action = "removed"; path = "d1\\d2\\new-file" }
|
||||
; { action = "modified"; path = "d1\\d2\\f1" }
|
||||
; { action = "modified"; path = "d1\\d2\\f2" }
|
||||
; { action = "modified"; path = "d1\\d2\\f3" }
|
||||
; { action = "added"; path = "d2\\new-file" }
|
||||
; { action = "added"; path = "d2\\new-dir" }
|
||||
; { action = "removed"; path = "d2\\new-dir" }
|
||||
; { action = "removed"; path = "d2\\new-file" }
|
||||
; { action = "modified"; path = "d2\\f1" }
|
||||
; { action = "modified"; path = "d2\\f2" }
|
||||
; { action = "modified"; path = "d2\\f3" }
|
||||
; { action = "added"; path = "d2\\d1\\new-file" }
|
||||
; { action = "added"; path = "d2\\d1\\new-dir" }
|
||||
; { action = "removed"; path = "d2\\d1\\new-dir" }
|
||||
; { action = "removed"; path = "d2\\d1\\new-file" }
|
||||
; { action = "modified"; path = "d2\\d1\\f1" }
|
||||
; { action = "modified"; path = "d2\\d1\\f2" }
|
||||
; { action = "modified"; path = "d2\\d1\\f3" }
|
||||
; { action = "added"; path = "d2\\d2\\new-file" }
|
||||
; { action = "added"; path = "d2\\d2\\new-dir" }
|
||||
; { action = "removed"; path = "d2\\d2\\new-dir" }
|
||||
; { action = "removed"; path = "d2\\d2\\new-file" }
|
||||
; { action = "modified"; path = "d2\\d2\\f1" }
|
||||
; { action = "modified"; path = "d2\\d2\\f2" }
|
||||
; { action = "modified"; path = "d2\\d2\\f3" }
|
||||
]
|
||||
;;
|
||||
|
||||
(* Check interleaving more specifically *)
|
||||
let _ =
|
||||
in_sub_dir
|
||||
@@ fun () ->
|
||||
mkdir "a";
|
||||
mkdir "b";
|
||||
watch ".";
|
||||
create_file "a\\x";
|
||||
create_file "b\\x";
|
||||
create_file "a\\y";
|
||||
check_events
|
||||
~real_events:(collect_events ())
|
||||
[ { action = "added"; path = "a\\x" }
|
||||
; { action = "added"; path = "b\\x" }
|
||||
; { action = "added"; path = "a\\y" }
|
||||
]
|
||||
;;
|
||||
|
||||
let run cmd =
|
||||
match
|
||||
snd
|
||||
(Unix.waitpid
|
||||
[]
|
||||
(Unix.create_process
|
||||
(List.hd cmd)
|
||||
(Array.of_list cmd)
|
||||
Unix.stdin
|
||||
Unix.stdout
|
||||
Unix.stderr))
|
||||
with
|
||||
| WEXITED 0 -> ()
|
||||
| _ -> assert false
|
||||
;;
|
||||
|
||||
(* Check that ordering is respected when the changes are made by an external
|
||||
process. Which is the assumption we are making for the fs sync mechanism of
|
||||
the file watcher. *)
|
||||
let _ =
|
||||
in_sub_dir
|
||||
@@ fun () ->
|
||||
mkdir "_build";
|
||||
mkdir "_build\\.sync";
|
||||
watch ".";
|
||||
let actions =
|
||||
[ `Me; `Ext; `Me; `Ext; `Ext ] |> List.mapi ~f:(fun i who -> string_of_int i, who)
|
||||
in
|
||||
let actions = actions @ [ "_build\\.sync\\1", `Me ] in
|
||||
let do_actions () =
|
||||
List.iter actions ~f:(fun (fn, who) ->
|
||||
match who with
|
||||
| `Me -> create_file fn
|
||||
| `Ext -> run [ "touch"; fn ])
|
||||
in
|
||||
do_actions ();
|
||||
let real_events = collect_events () in
|
||||
let expected_events =
|
||||
[ { action = "added"; path = "0" }
|
||||
; { action = "added"; path = "1" }
|
||||
; { action = "modified"; path = "1" }
|
||||
; { action = "added"; path = "2" }
|
||||
; { action = "added"; path = "3" }
|
||||
; { action = "modified"; path = "3" }
|
||||
; { action = "added"; path = "4" }
|
||||
; { action = "modified"; path = "4" }
|
||||
; { action = "added"; path = "_build\\.sync\\1" }
|
||||
]
|
||||
in
|
||||
check_events ~real_events expected_events
|
||||
;;
|
||||
Loading…
Add table
Add a link
Reference in a new issue