This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
|
|
@ -0,0 +1,24 @@
|
|||
(cram
|
||||
(enabled_if
|
||||
;; On macos it looks like dune has a chance to miss filesystem events if they
|
||||
;; occur too close together in time. Tests of `dune exec -w` run a program with a
|
||||
;; visible side effect (touching a file), and wait for the side effect before
|
||||
;; modifying the program to trigger a rebuild/rerun. On macos, these changes can
|
||||
;; sometimes go undetected. Adding a delay (e.g. `sleep 1`) before modifying the
|
||||
;; program seems to guarantee a rebuild will be triggered, but that is too
|
||||
;; unreliable to depend on in a test so these tests are disabled on macos.
|
||||
(<> "macosx" %{ocaml-config:system})))
|
||||
|
||||
; These tests are explicitly disabled due to flakiness
|
||||
|
||||
(cram
|
||||
(applies_to exec-watch-server exec-watch-ignore-sigterm exec-signal)
|
||||
(enabled_if false))
|
||||
|
||||
; CR Alizter: renable all tests again, work out what causes the CI to hang
|
||||
|
||||
(cram
|
||||
(enabled_if false))
|
||||
|
||||
(cram
|
||||
(deps wait-for-file.sh))
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
(executable
|
||||
(name main))
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 3.6)
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
$ export OUTPUT=output.txt
|
||||
|
||||
In normal (non-watching) mode, pwd is the folder from which dune is launched
|
||||
$ cd bin
|
||||
$ dune exec --root .. -- pwd > $OUTPUT
|
||||
Entering directory '..'
|
||||
Leaving directory '..'
|
||||
$ cat $OUTPUT
|
||||
$TESTCASE_ROOT/bin
|
||||
$ rm -rf $OUTPUT
|
||||
$ cd ..
|
||||
|
||||
In watch mode, pwd is also the folder from which dune is launched.
|
||||
$ cd bin
|
||||
$ dune exec --root .. -w -- pwd > $OUTPUT &
|
||||
Entering directory '..'
|
||||
Success, waiting for filesystem changes...
|
||||
Leaving directory '..'
|
||||
$ PID=$!
|
||||
$ until test -s $OUTPUT; do sleep 0.1; done;
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
$ cat $OUTPUT
|
||||
$TESTCASE_ROOT/bin
|
||||
$ rm -rf $OUTPUT
|
||||
$ cd ..
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
Here we test what happens if there is a signal for the program to terminate when we are
|
||||
running with dune exec. Signals are dispatched from the operating system. It is usually
|
||||
impossible for a program to recover after recieving such a signal.
|
||||
|
||||
For dune exec -w, we are indifferent to what the process we are running is actually doing
|
||||
since it shouldn't affect dune's other functions.
|
||||
|
||||
$ DONE_FLAG=_build/done_flag
|
||||
|
||||
$ cat > dune-project <<EOF
|
||||
> (lang dune 3.18)
|
||||
> EOF
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (libraries unix))
|
||||
> EOF
|
||||
|
||||
$ cat > touch.ml <<EOF
|
||||
> let touch path =
|
||||
> let fd = Unix.openfile path [ Unix.O_CREAT ] 0o777 in
|
||||
> Unix.close fd
|
||||
> ;;
|
||||
> EOF
|
||||
|
||||
This first program will signal itself with a KILL signal.:
|
||||
$ cat > foo.ml <<EOF
|
||||
> let () =
|
||||
> Touch.touch "$DONE_FLAG";
|
||||
> print_endline "about to be killed";
|
||||
> let pid = Unix.getpid () in
|
||||
> Unix.kill pid Sys.sigkill
|
||||
> ;;
|
||||
> EOF
|
||||
|
||||
$ LOG_FILE=_build/log_file
|
||||
$ mkdir _build
|
||||
|
||||
When reaching a signal like SEGV dune exec -w will exit.
|
||||
$ dune exec -w ./foo.exe 2> >(tee "$LOG_FILE" >&2) &
|
||||
about to be killed
|
||||
Command got signal KILL.
|
||||
Had 1 error, waiting for filesystem changes...
|
||||
fixed signal
|
||||
Success, waiting for filesystem changes...
|
||||
$ PID=$!
|
||||
$ ./wait-for-file.sh $DONE_FLAG
|
||||
|
||||
Waiting for KILL signal...
|
||||
$ tail -f "$LOG_FILE" | while read line; do
|
||||
> echo "$line" | grep 'KILL' && break
|
||||
> done
|
||||
Command got signal KILL.
|
||||
|
||||
We can now start a new build by modifying the original program and removing the segfault.
|
||||
This rebuilds successfully as indicated by the above output.
|
||||
$ cat > foo.ml <<EOF
|
||||
> let () =
|
||||
> Touch.touch "$DONE_FLAG";
|
||||
> print_endline "fixed signal";
|
||||
> ;;
|
||||
> EOF
|
||||
|
||||
$ ./wait-for-file.sh $DONE_FLAG
|
||||
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
Testing stdin for watch mode dune exec
|
||||
|
||||
We use the done flag as a signal that the program has finished.
|
||||
$ DONE_FLAG=_build/done_flag
|
||||
|
||||
$ cat > dune-project <<EOF
|
||||
> (lang dune 3.18)
|
||||
> EOF
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (libraries unix))
|
||||
> EOF
|
||||
|
||||
$ cat > touch.ml <<EOF
|
||||
> let touch path =
|
||||
> let fd = Unix.openfile path [ Unix.O_CREAT ] 0o777 in
|
||||
> Unix.close fd
|
||||
> ;;
|
||||
> EOF
|
||||
|
||||
$ cat > foo.ml <<EOF
|
||||
> let () =
|
||||
> print_endline "what is your name?";
|
||||
> let name = read_line () in
|
||||
> print_endline ("hello " ^ name ^ "!");
|
||||
> Touch.touch "$DONE_FLAG"
|
||||
> ;;
|
||||
> EOF
|
||||
|
||||
Our program takes in some input from stdin, so we need to make sure dune passes this along
|
||||
correctly. To simulate giving this input later we use a pipe.
|
||||
$ mkfifo input.pipe
|
||||
$ dune exec -w -- ./foo.exe < input.pipe &
|
||||
what is your name?
|
||||
hello John Doe!
|
||||
Success, waiting for filesystem changes...
|
||||
(2) what is your name?
|
||||
(2) hello Alice Johnson!
|
||||
Success, waiting for filesystem changes...
|
||||
$ PID=$!
|
||||
|
||||
$ cat > input.pipe <<EOF
|
||||
> John Doe
|
||||
> EOF
|
||||
$ ./wait-for-file.sh $DONE_FLAG
|
||||
|
||||
We can trigger arebuild and give another input.
|
||||
$ cat > foo.ml <<EOF
|
||||
> let () =
|
||||
> print_endline "(2) what is your name?";
|
||||
> let name = read_line () in
|
||||
> print_endline ("(2) hello " ^ name ^ "!");
|
||||
> Touch.touch "$DONE_FLAG"
|
||||
> ;;
|
||||
> EOF
|
||||
$ cat > input.pipe <<EOF
|
||||
> Alice Johnson
|
||||
> EOF
|
||||
|
||||
$ ./wait-for-file.sh $DONE_FLAG
|
||||
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(public_name foo)
|
||||
(libraries unix))
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
(lang dune 3.6)
|
||||
(package (name foo))
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
Test exec --watch with a program that terminates immediately.
|
||||
|
||||
File created by the program being exec'd. In between each experiment we'll wait
|
||||
until the file exists so that dune has enough time to build and run the program
|
||||
between each change to its code.
|
||||
$ export DONE_FLAG=_build/done_flag
|
||||
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () = print_endline "foo"; Touch.touch "$DONE_FLAG"
|
||||
> EOF
|
||||
|
||||
$ dune exec --watch ./foo.exe &
|
||||
foo
|
||||
Success, waiting for filesystem changes...
|
||||
bar
|
||||
Success, waiting for filesystem changes...
|
||||
File "foo.ml", line 1, characters 23-24:
|
||||
1 | let () = print_endline "baz
|
||||
^
|
||||
Error: String literal not terminated
|
||||
Had 1 error, waiting for filesystem changes...
|
||||
baz
|
||||
Success, waiting for filesystem changes...
|
||||
$ PID=$!
|
||||
|
||||
Wait for the $DONE_FLAG file to exist, then delete the file. This file is
|
||||
created by the program being exec'd, so when it exists we know that it's safe to
|
||||
change the code and proceed with the test.
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () = print_endline "bar"; Touch.touch "$DONE_FLAG"
|
||||
> EOF
|
||||
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () = print_endline "baz
|
||||
> EOF
|
||||
|
||||
Wait until the error shows up in the log
|
||||
$ until grep 'print_endline "baz' _build/log > /dev/null; do sleep 0.1; done
|
||||
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () = print_endline "baz"; Touch.touch "$DONE_FLAG"
|
||||
> EOF
|
||||
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
|
||||
Prevent the test from leaking the dune process.
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
let touch path =
|
||||
let fd = Unix.openfile path [ Unix.O_CREAT ] 777 in
|
||||
Unix.close fd
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Here we test what happens if the program we are running with dune exec -w exits with a
|
||||
non-zero exit code.
|
||||
|
||||
$ DONE_FLAG=_build/done_flag
|
||||
|
||||
$ cat > dune-project <<EOF
|
||||
> (lang dune 3.18)
|
||||
> EOF
|
||||
|
||||
$ cat > dune <<EOF
|
||||
> (executable
|
||||
> (name foo)
|
||||
> (libraries unix))
|
||||
> EOF
|
||||
|
||||
$ cat > foo.ml <<EOF
|
||||
> let touch path =
|
||||
> let fd = Unix.openfile path [ Unix.O_CREAT ] 0o777 in
|
||||
> Unix.close fd
|
||||
> ;;
|
||||
>
|
||||
> let () =
|
||||
> touch "$DONE_FLAG";
|
||||
> Printf.eprintf "oh no!\n";
|
||||
> exit 1
|
||||
> ;;
|
||||
> EOF
|
||||
|
||||
The build will still be considered successful even if the program being run fails. We
|
||||
output the exit code of the program to be clear to the user. It's not useful anyway since
|
||||
we are in watch mode.
|
||||
$ dune exec -w -- ./foo.exe &
|
||||
oh no!
|
||||
Program exited with code [1]
|
||||
Success, waiting for filesystem changes...
|
||||
$ PID=$!
|
||||
$ ./wait-for-file.sh $DONE_FLAG
|
||||
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(public_name foo)
|
||||
(libraries unix))
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
(lang dune 3.6)
|
||||
(package (name foo))
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
let touch path =
|
||||
let fd = Unix.openfile path [ Unix.O_CREAT ] 777 in
|
||||
Unix.close fd
|
||||
|
||||
let () =
|
||||
let _ = Unix.sigprocmask Unix.SIG_BLOCK [ Sys.sigterm ] in
|
||||
print_endline "1: before";
|
||||
touch "_build/done_flag";
|
||||
Unix.sleep 1000
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Test exec --watch with a program that ignores sigterm.
|
||||
|
||||
$ dune exec --watch ./foo.exe &
|
||||
1: before
|
||||
2: before
|
||||
$ PID=$!
|
||||
|
||||
$ ../wait-for-file.sh _build/done_flag
|
||||
|
||||
$ sed -i -e 's/1: before/2: before/' foo.ml
|
||||
|
||||
$ ../wait-for-file.sh _build/done_flag
|
||||
|
||||
Prevent the test from leaking the dune process.
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(name main)
|
||||
(libraries unix))
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
let () =
|
||||
let touch path =
|
||||
let fd = Unix.openfile path [ Unix.O_CREAT ] 0o777 in
|
||||
Unix.close fd
|
||||
in
|
||||
print_endline "foo";
|
||||
match Sys.argv.(1) with
|
||||
| exception _ -> ()
|
||||
| path -> touch path
|
||||
|
|
@ -0,0 +1 @@
|
|||
(lang dune 3.6)
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
Test the behaviour of exec watch mode when the current directory is not the
|
||||
project root directory.
|
||||
|
||||
"dune exec --watch" works fine when invoked at the root level
|
||||
$ DONE_FLAG=_build/done_flag
|
||||
$ dune exec --watch ./bin/main.exe $DONE_FLAG &
|
||||
foo
|
||||
Success, waiting for filesystem changes...
|
||||
$ PID=$!
|
||||
|
||||
Wait for the $DONE_FLAG file to exist, then delete the file. This file is
|
||||
created by the program being exec'd, so when it exists we know that it's safe to
|
||||
change the code and proceed with the test.
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
|
||||
Perform the same test above but first enter the "bin" directory.
|
||||
$ dune clean
|
||||
$ cd bin
|
||||
$ dune exec --root .. --watch ./bin/main.exe ../$DONE_FLAG &
|
||||
Entering directory '..'
|
||||
foo
|
||||
Success, waiting for filesystem changes...
|
||||
Leaving directory '..'
|
||||
$ PID=$!
|
||||
$ cd ..
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
$ kill $PID
|
||||
$ wait $PID
|
||||
[130]
|
||||
|
||||
Test that the behaviour is the same when not running with "--watch"
|
||||
$ cd bin && dune exec --root .. ./bin/main.exe
|
||||
Entering directory '..'
|
||||
Leaving directory '..'
|
||||
foo
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
Trying to run exec in passive watch mode produces and error.
|
||||
|
||||
$ cat >dune-project <<EOF
|
||||
> (lang dune 3.6)
|
||||
> (package (name foo))
|
||||
> EOF
|
||||
|
||||
$ cat >dune <<EOF
|
||||
> (executable
|
||||
> (public_name foo))
|
||||
> EOF
|
||||
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () = print_endline "foo"
|
||||
> EOF
|
||||
|
||||
$ dune exec --passive-watch-mode ./foo.exe
|
||||
Error: passive watch mode is unsupported by exec
|
||||
[1]
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
(executable
|
||||
(public_name foo)
|
||||
(libraries unix))
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
(lang dune 3.6)
|
||||
(package (name foo))
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
Test exec --watch with a program that doesn't terminate immediately.
|
||||
|
||||
File created by the program being exec'd. In between each experiment we'll wait
|
||||
until the file exists so that dune has enough time to build and run the program
|
||||
between each change to its code.
|
||||
$ export DONE_FLAG=_build/done_flag
|
||||
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () =
|
||||
> print_endline "0: before";
|
||||
> Touch.touch "$DONE_FLAG";
|
||||
> Unix.sleep 1000;
|
||||
> print_endline "0: after"
|
||||
> EOF
|
||||
|
||||
$ dune exec --watch ./foo.exe &
|
||||
0: before
|
||||
1: before
|
||||
1: after
|
||||
Success, waiting for filesystem changes...
|
||||
2: before
|
||||
$ PID=$!
|
||||
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
|
||||
Change the program so that it terminates immediately.
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () =
|
||||
> print_endline "1: before";
|
||||
> Unix.sleep 0;
|
||||
> print_endline "1: after";
|
||||
> Touch.touch "$DONE_FLAG"
|
||||
> EOF
|
||||
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
|
||||
Change the program so that it no longer terminates immediately.
|
||||
$ cat >foo.ml <<EOF
|
||||
> let () =
|
||||
> print_endline "2: before";
|
||||
> Touch.touch "$DONE_FLAG";
|
||||
> Unix.sleep 1000;
|
||||
> print_endline "2: after"
|
||||
> EOF
|
||||
|
||||
$ ../wait-for-file.sh $DONE_FLAG
|
||||
|
||||
Prevent the test from leaking the dune process.
|
||||
$ kill $PID
|
||||
|
||||
Checking for the child process
|
||||
$ pgrep -c "foo.exe" || true
|
||||
0
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
let touch path =
|
||||
let fd = Unix.openfile path [ Unix.O_CREAT ] 777 in
|
||||
Unix.close fd
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Wait until a file exists, then delete the file and exit
|
||||
#
|
||||
|
||||
set -u
|
||||
FILE=$1
|
||||
until test -e $FILE
|
||||
do
|
||||
sleep 0.01
|
||||
done
|
||||
rm $FILE
|
||||
Loading…
Add table
Add a link
Reference in a new issue