1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
let ( // ) = Filename.concat
let getenv name =
match Sys.getenv_opt name with Some "" | None -> None | Some v -> Some v
let executable path =
(try Sys.file_exists path && not (Sys.is_directory path)
with Sys_error _ -> false)
&&
try
Unix.access path [ Unix.X_OK ];
true
with Unix.Unix_error _ | Sys_error _ -> false
let on_path name =
let dirs =
String.split_on_char ':' (Option.value ~default:"" (getenv "PATH"))
in
List.find_map
(fun d ->
if d = "" then None
else
let p = d // name in
if executable p then Some p else None)
dirs
let rec search_tree root names depth acc =
if depth <= 0 then acc
else
match Sys.readdir root with
| exception Sys_error _ -> acc
| entries ->
Array.fold_left
(fun acc entry ->
let p = root // entry in
if try Sys.is_directory p with Sys_error _ -> false then
search_tree p names (depth - 1) acc
else if List.mem entry names && executable p then p :: acc
else acc)
acc entries
let chrome_binary () =
match getenv "CHROME" with
| Some c when executable c -> Some c
| Some _ | None -> (
let names =
[
"chromium";
"chromium-browser";
"google-chrome";
"google-chrome-stable";
]
in
match List.find_map on_path names with
| Some c -> Some c
| None -> (
let home = Option.value ~default:"" (getenv "HOME") in
let caches =
[
home // ".cache" // "puppeteer";
home // "Library" // "Caches" // "ms-playwright";
home // ".cache" // "ms-playwright";
]
in
let binaries =
[
"chrome-headless-shell";
"headless_shell";
"Chromium";
"Google Chrome for Testing";
]
in
let found =
List.concat_map (fun c -> search_tree c binaries 6 []) caches
in
match List.sort compare found with
| [] ->
let app =
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
in
if executable app then Some app else None
| l -> Some (List.nth l (List.length l - 1))))
let node_binary () =
match getenv "NODE" with
| Some n when executable n -> Some n
| Some _ | None -> on_path "node"
let chrome_version chrome =
let read_lines ic =
let rec loop acc =
match input_line ic with
| line -> loop (line :: acc)
| exception End_of_file -> List.rev acc
in
loop []
in
let ic =
Unix.open_process_in
(String.concat " " [ Filename.quote chrome; "--version"; "2>/dev/null" ])
in
let lines = read_lines ic in
ignore (Unix.close_process_in ic);
let leading_int s =
let n = String.length s in
let rec upto i =
if i < n && s.[i] >= '0' && s.[i] <= '9' then upto (i + 1) else i
in
let stop = upto 0 in
if stop = 0 then None else int_of_string_opt (String.sub s 0 stop)
in
let of_word w =
match String.split_on_char '.' w with
| major :: minor :: _ -> (
match (leading_int major, leading_int minor) with
| Some a, Some b -> Some (a, b)
| _ -> None)
| _ -> None
in
List.fold_left
(fun found line ->
match found with
| Some _ -> found
| None ->
List.fold_left
(fun found word ->
match found with Some _ -> found | None -> of_word word)
None
(String.split_on_char ' ' line))
None lines
let skip harness reason =
print_endline (String.concat "" [ "SKIP: "; harness; " ("; reason; ")" ]);
exit 0
let acknowledged = "unchecked"
let suppressed harness =
match getenv "CASCADE_NO_BROWSER" with
| None -> ()
| Some v when String.equal v acknowledged ->
print_endline
(String.concat ""
[
"SKIP: ";
harness;
" (CASCADE_NO_BROWSER=";
acknowledged;
", so this run checks nothing)";
]);
exit 0
| Some v ->
prerr_endline
(String.concat ""
[
"FAIL: ";
harness;
" is suppressed by CASCADE_NO_BROWSER=";
v;
"; a gate that did not run is not a pass. Set CASCADE_NO_BROWSER=";
acknowledged;
" to exit 0 and say so.";
]);
exit 1