Skip to content

Commit 3debc17

Browse files
committed
feature(cram): add [setup_script] to cram tests
Signed-off-by: Rudi Grinberg <[email protected]> refactor: my personal tweaks Signed-off-by: Rudi Grinberg <[email protected]>
1 parent a9a399e commit 3debc17

File tree

11 files changed

+381
-16
lines changed

11 files changed

+381
-16
lines changed

src/dune_rules/cram/cram_exec.ml

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ let cram_commmands commands =
335335
Buffer.contents buf
336336
;;
337337

338-
let create_sh_script cram_stanzas ~temp_dir : sh_script Fiber.t =
338+
let create_sh_script cram_stanzas ~temp_dir ~setup_scripts : sh_script Fiber.t =
339339
let script = Path.relative temp_dir "main.sh" in
340340
let oc = Io.open_out ~binary:true script in
341341
Fiber.finalize ~finally:(fun () -> Fiber.return @@ close_out oc)
@@ -384,6 +384,15 @@ let create_sh_script cram_stanzas ~temp_dir : sh_script Fiber.t =
384384
}
385385
in
386386
fprln oc "trap 'exit 0' EXIT";
387+
let* () =
388+
Fiber.sequential_iter setup_scripts ~f:(fun (script_path : Path.t) ->
389+
let+ script_sh_path = sh_path script_path in
390+
fprln oc ". %s" script_sh_path;
391+
match script_path with
392+
| In_source_tree _ -> assert false
393+
| External _ -> ()
394+
| In_build_dir _ -> fprln oc "rm -f %s" script_sh_path)
395+
in
387396
let+ cram_to_output = Fiber.sequential_map ~f:loop cram_stanzas in
388397
let command_count = !i in
389398
let metadata_file = Option.some_if (command_count > 0) metadata_file in
@@ -423,9 +432,9 @@ let make_temp_dir ~script =
423432
temp_dir
424433
;;
425434

426-
let run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout =
435+
let run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout ~setup_scripts =
427436
let open Fiber.O in
428-
let* sh_script = create_sh_script cram_stanzas ~temp_dir in
437+
let* sh_script = create_sh_script cram_stanzas ~temp_dir ~setup_scripts in
429438
let env = make_run_env env ~temp_dir ~cwd in
430439
let open Fiber.O in
431440
let sh =
@@ -493,13 +502,21 @@ let run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout =
493502
(timeout_msg @ [ timeout_set_message ])
494503
;;
495504

496-
let run_produce_correction ~conflict_markers ~src ~env ~script ~timeout lexbuf =
505+
let run_produce_correction
506+
~conflict_markers
507+
~src
508+
~env
509+
~script
510+
~timeout
511+
~setup_scripts
512+
lexbuf
513+
=
497514
let temp_dir = make_temp_dir ~script in
498515
let cram_stanzas = cram_stanzas lexbuf ~conflict_markers |> List.map ~f:snd in
499516
let cwd = Path.parent_exn script in
500517
let env = make_run_env env ~temp_dir ~cwd in
501518
let open Fiber.O in
502-
run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout
519+
run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout ~setup_scripts
503520
>>| compose_cram_output
504521
;;
505522

@@ -512,7 +529,16 @@ module Script = Persistent.Make (struct
512529
let test_example () = []
513530
end)
514531

515-
let run_and_produce_output ~conflict_markers ~src ~env ~dir:cwd ~script ~dst ~timeout =
532+
let run_and_produce_output
533+
~conflict_markers
534+
~src
535+
~env
536+
~dir:cwd
537+
~script
538+
~dst
539+
~timeout
540+
~setup_scripts
541+
=
516542
let script_contents = Io.read_file ~binary:false script in
517543
let lexbuf = Lexbuf.from_string script_contents ~fname:(Path.to_string script) in
518544
let temp_dir = make_temp_dir ~script in
@@ -522,7 +548,7 @@ let run_and_produce_output ~conflict_markers ~src ~env ~dir:cwd ~script ~dst ~ti
522548
let env = make_run_env env ~temp_dir ~cwd in
523549
let open Fiber.O in
524550
let+ commands =
525-
run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout
551+
run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout ~setup_scripts
526552
>>| List.filter_map ~f:(function
527553
| Cram_lexer.Command c -> Some c
528554
| Comment _ -> None)
@@ -540,28 +566,42 @@ module Run = struct
540566
; script : 'path
541567
; output : 'target
542568
; timeout : (Loc.t * float) option
569+
; setup_scripts : 'path list
543570
}
544571

545572
let name = "cram-run"
546-
let version = 2
547-
548-
let bimap ({ src = _; dir; script; output; timeout } as t) f g =
549-
{ t with dir = f dir; script = f script; output = g output; timeout }
573+
let version = 3
574+
575+
let bimap ({ src = _; dir; script; output; timeout; setup_scripts } as t) f g =
576+
{ t with
577+
dir = f dir
578+
; script = f script
579+
; output = g output
580+
; timeout
581+
; setup_scripts = List.map ~f setup_scripts
582+
}
550583
;;
551584

552585
let is_useful_to ~memoize:_ = true
553586

554-
let encode { src = _; dir; script; output; timeout } path target : Sexp.t =
587+
let encode { src = _; dir; script; output; timeout; setup_scripts } path target
588+
: Sexp.t
589+
=
555590
List
556591
[ path dir
557592
; path script
558593
; target output
559594
; Dune_sexp.Encoder.(option float (Option.map ~f:snd timeout))
560595
|> Dune_sexp.to_sexp
596+
; List (List.map ~f:path setup_scripts)
561597
]
562598
;;
563599

564-
let action { src; dir; script; output; timeout } ~ectx:_ ~(eenv : Action.env) =
600+
let action
601+
{ src; dir; script; output; timeout; setup_scripts }
602+
~ectx:_
603+
~(eenv : Action.env)
604+
=
565605
run_and_produce_output
566606
~conflict_markers:Ignore
567607
~src
@@ -570,14 +610,15 @@ module Run = struct
570610
~script
571611
~dst:output
572612
~timeout
613+
~setup_scripts
573614
;;
574615
end
575616

576617
include Action_ext.Make (Spec)
577618
end
578619

579-
let run ~src ~dir ~script ~output ~timeout =
580-
Run.action { src; dir; script; output; timeout }
620+
let run ~src ~dir ~script ~output ~timeout ~setup_scripts =
621+
Run.action { src; dir; script; output; timeout; setup_scripts }
581622
;;
582623

583624
module Make_script = struct
@@ -700,7 +741,8 @@ module Action = struct
700741
~src:script
701742
~env:eenv.env
702743
~script
703-
~timeout:None)
744+
~timeout:None
745+
~setup_scripts:[])
704746
;;
705747
end
706748

src/dune_rules/cram/cram_exec.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ val run
1414
-> script:Path.t
1515
-> output:Path.Build.t
1616
-> timeout:(Loc.t * float) option
17+
-> setup_scripts:Path.t list
1718
-> Action.t
1819

1920
(** Produces a diff if [src] needs to be updated *)

src/dune_rules/cram/cram_rules.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module Spec = struct
1313
; packages : Package.Name.Set.t
1414
; timeout : (Loc.t * float) option
1515
; conflict_markers : Cram_stanza.Conflict_markers.t
16+
; setup_scripts : Path.t list
1617
}
1718

1819
let make_empty ~test_name_alias =
@@ -26,6 +27,7 @@ module Spec = struct
2627
; packages = Package.Name.Set.empty
2728
; timeout = None
2829
; conflict_markers = Ignore
30+
; setup_scripts = []
2931
}
3032
;;
3133
end
@@ -61,6 +63,7 @@ let test_rule
6163
; packages = _
6264
; timeout
6365
; conflict_markers
66+
; setup_scripts
6467
} :
6568
Spec.t)
6669
(test : (Cram_test.t, error) result)
@@ -135,6 +138,7 @@ let test_rule
135138
in
136139
let+ (_ : Path.Set.t) = Action_builder.dyn_memo_deps deps in
137140
()
141+
and+ () = Action_builder.paths setup_scripts
138142
and+ locks = locks >>| Path.Set.to_list in
139143
Cram_exec.run
140144
~src:(Path.build script)
@@ -146,6 +150,7 @@ let test_rule
146150
~script:(Path.build script_sh)
147151
~output
148152
~timeout
153+
~setup_scripts
149154
|> Action.Full.make ~locks ~sandbox)
150155
|> Action_builder.with_file_targets ~file_targets:[ output ]
151156
|> Super_context.add_rule sctx ~dir ~loc
@@ -297,6 +302,14 @@ let rules ~sctx ~dir tests =
297302
let conflict_markers =
298303
Option.value ~default:acc.conflict_markers stanza.conflict_markers
299304
in
305+
let setup_scripts =
306+
List.map stanza.setup_scripts ~f:(fun (_loc, script) ->
307+
(* Handle both relative and absolute paths *)
308+
if Filename.is_relative script
309+
then Path.build (Path.Build.relative dir script)
310+
else Path.external_ (Path.External.of_string script))
311+
@ acc.setup_scripts
312+
in
300313
( runtest_alias
301314
, { acc with
302315
enabled_if
@@ -308,6 +321,7 @@ let rules ~sctx ~dir tests =
308321
; sandbox
309322
; timeout
310323
; conflict_markers
324+
; setup_scripts
311325
} ))
312326
in
313327
let extra_aliases =

src/dune_rules/cram/cram_stanza.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type t =
4545
; package : Package.t option
4646
; runtest_alias : (Loc.t * bool) option
4747
; timeout : (Loc.t * float) option
48+
; setup_scripts : (Loc.t * string) list
4849
}
4950

5051
include Stanza.Make (struct
@@ -100,6 +101,13 @@ let decode =
100101
field_o
101102
"conflict_markers"
102103
(Dune_lang.Syntax.since Stanza.syntax (3, 21) >>> Conflict_markers.decode)
104+
and+ setup_scripts =
105+
let+ scripts =
106+
field_o
107+
"setup_scripts"
108+
(Dune_lang.Syntax.since Stanza.syntax (3, 21) >>> repeat (located string))
109+
in
110+
Option.value scripts ~default:[]
103111
in
104112
{ loc
105113
; alias
@@ -111,5 +119,6 @@ let decode =
111119
; runtest_alias
112120
; timeout
113121
; conflict_markers
122+
; setup_scripts
114123
})
115124
;;

src/dune_rules/cram/cram_stanza.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type t =
2323
; package : Package.t option
2424
; runtest_alias : (Loc.t * bool) option
2525
; timeout : (Loc.t * float) option
26+
; setup_scripts : (Loc.t * string) list
2627
}
2728

2829
val decode : t Dune_lang.Decoder.t
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
Test setup_scripts feature for cram tests
2+
3+
Create a project with a helper script:
4+
5+
$ cat > dune-project << EOF
6+
> (lang dune 3.21)
7+
> EOF
8+
9+
$ cat > helpers.sh << 'EOF'
10+
> #!/bin/sh
11+
> test_helper() {
12+
> echo "Helper called: $1"
13+
> }
14+
> export MY_VAR="test_value_from_helper"
15+
> EOF
16+
17+
$ cat > dune << EOF
18+
> (cram
19+
> (setup_scripts helpers.sh))
20+
> EOF
21+
22+
$ cat > basic.t << 'EOF'
23+
> Test that setup scripts are sourced and functions are available
24+
>
25+
> $ test_helper "foo"
26+
> Helper called: foo
27+
>
28+
> Test that variables from setup scripts are available
29+
>
30+
> $ echo $MY_VAR
31+
> test_value_from_helper
32+
>
33+
> Check if setup script is visible in test directory
34+
>
35+
> $ ls *.sh 2>&1 || echo "No sh files"
36+
> No sh files
37+
> EOF
38+
39+
Run the test:
40+
41+
$ dune runtest
42+
File "basic.t", line 1, characters 0-0:
43+
Error: Files _build/default/basic.t and _build/default/basic.t.corrected
44+
differ.
45+
[1]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Test if setup scripts are visible in test directory
2+
3+
$ cat > dune-project << EOF
4+
> (lang dune 3.21)
5+
> EOF
6+
7+
$ cat > secret.sh << 'EOF'
8+
> MY_SECRET="should_not_be_visible"
9+
> EOF
10+
11+
$ cat > dune << EOF
12+
> (cram
13+
> (setup_scripts secret.sh))
14+
> EOF
15+
16+
$ cat > check.t << 'EOF'
17+
> $ ls *.sh 2>&1 || echo "No .sh files found"
18+
> No .sh files found
19+
> EOF
20+
21+
$ dune runtest
22+
File "check.t", line 1, characters 0-0:
23+
Error: Files _build/default/check.t and _build/default/check.t.corrected
24+
differ.
25+
[1]
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
Test that external (absolute path) setup scripts work and are NOT deleted
2+
3+
First, create an external script in /tmp:
4+
5+
$ EXTERNAL_SCRIPT="/tmp/dune_test_external_helper_$$.sh"
6+
$ cat > "$EXTERNAL_SCRIPT" << 'EOF'
7+
> #!/bin/sh
8+
> external_helper() {
9+
> echo "External helper called"
10+
> }
11+
> export EXTERNAL_VAR="from_external_script"
12+
> EOF
13+
$ chmod +x "$EXTERNAL_SCRIPT"
14+
15+
Create a project that uses the external script:
16+
17+
$ cat > dune-project << EOF
18+
> (lang dune 3.21)
19+
> EOF
20+
21+
$ cat > dune << EOF
22+
> (cram
23+
> (setup_scripts $EXTERNAL_SCRIPT))
24+
> EOF
25+
26+
Create a test that uses the external helper:
27+
28+
$ cat > external.t << 'EOF'
29+
> Test that external helper is available
30+
>
31+
> $ external_helper
32+
> External helper called 1
33+
>
34+
> $ echo $EXTERNAL_VAR
35+
> from_external_script 1
36+
> EOF
37+
38+
Run the test:
39+
40+
$ dune runtest
41+
File "external.t", line 1, characters 0-0:
42+
Error: Files _build/default/external.t and
43+
_build/default/external.t.corrected differ.
44+
[1]
45+
46+
Verify the external script still exists (was NOT deleted):
47+
48+
$ if [ -f "$EXTERNAL_SCRIPT" ]; then
49+
> echo "External script still exists"
50+
> else
51+
> echo "External script was deleted"
52+
> fi
53+
External script still exists

0 commit comments

Comments
 (0)