2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
13 let test_process_data =
17 finale_file
= "2758734.fin";
20 out_fds
= [("default", Unix.stdout
)];
21 last_request_handoff
= ref 0.0;
24 let test_dmesg_parser () =
27 "[3034339.262439] Out of memory: Kill process 2758734 (hh_server) score 253 or sacrifice child";
30 Sys_utils.find_oom_in_dmesg_output
31 test_process_data.ServerProcess.pid
35 let ensure_count (count
: int) : unit =
36 let deferred = Deferred_decl.get_deferments ~f
:(fun d
-> d
) in
37 Asserter.Int_asserter.assert_equals
39 (List.length
deferred)
40 "The number of deferred items should match the expected value"
42 let test_deferred_decl_add () =
43 Deferred_decl.reset ~enable
:true;
46 Deferred_decl.add
(Relative_path.create
Relative_path.Dummy
"foo");
49 Deferred_decl.add
(Relative_path.create
Relative_path.Dummy
"foo");
52 Deferred_decl.add
(Relative_path.create
Relative_path.Dummy
"bar");
55 Deferred_decl.reset ~enable
:true;
60 let ensure_threshold ~
(threshold
: int) ~
(limit
: int) ~
(expected
: int) : unit
62 Deferred_decl.reset ~enable
:true;
65 let deferred_count = ref 0 in
67 let path = Printf.sprintf
"foo-%d" i
in
68 let relative_path = Relative_path.create
Relative_path.Dummy
path in
70 Deferred_decl.should_defer
72 ~threshold_opt
:(Some threshold
)
73 with Deferred_decl.Defer d
->
74 Asserter.Bool_asserter.assert_equals
78 "We should have reached the threshold %d, i=%d"
81 Asserter.String_asserter.assert_equals
82 (Relative_path.suffix d
)
84 "The deferred path should be the last one we saw";
85 deferred_count := !deferred_count + 1
88 Asserter.Int_asserter.assert_equals
92 "Unexpected deferred count; threshold: %d; limit: %d; expected: %d"
97 let test_deferred_decl_should_defer () =
98 ensure_threshold ~threshold
:0 ~limit
:1 ~expected
:1;
99 ensure_threshold ~threshold
:1 ~limit
:2 ~expected
:1;
100 ensure_threshold ~threshold
:2 ~limit
:1 ~expected
:0;
101 ensure_threshold ~threshold
:1 ~limit
:5 ~expected
:4;
108 public
function foo
(Bar $b
): int {
109 return $b
->toString
();
117 public
function toString
() : string {
123 (* In this test, we wish to establish that we enable deferring type checking
124 for files that have undeclared dependencies, UNLESS we've already deferred
125 those files a certain number of times. *)
126 let test_process_file_deferring () =
127 Deferred_decl.reset ~enable
:true;
129 (* Set up a simple fake repo *)
130 Disk.mkdir_p
"/fake/root/";
131 Relative_path.set_path_prefix
Relative_path.Root
(Path.make
"/fake/root/");
133 (* We'll need to parse these files in order to create a naming table, which
134 will be used for look up of symbols in type checking. *)
135 Disk.write_file ~file
:"/fake/root/Foo.php" ~contents
:foo_contents;
136 Disk.write_file ~file
:"/fake/root/Bar.php" ~contents
:bar_contents;
137 let foo_path = Relative_path.create
Relative_path.Root
"/fake/root/Foo.php" in
138 let bar_path = Relative_path.create
Relative_path.Root
"/fake/root/Bar.php" in
139 (* The parsing service needs shared memory to be set up *)
144 heap_size
= 1024 * 8;
153 let (_
: SharedMem.handle
) = SharedMem.init
config ~num_workers
:0 in
154 (* Parsing produces the file infos that the naming table module can use
155 to construct the forward naming table (files-to-symbols) *)
156 let (file_infos
, _errors
, _failed_parsing
) =
159 Relative_path.Set.empty
160 ~get_next
:(MultiWorker.next None
[foo_path; bar_path])
161 ParserOptions.default
164 let naming_table = Naming_table.create file_infos
in
165 (* Construct the reverse naming table (symbols-to-files) *)
166 let fast = Naming_table.to_fast
naming_table in
167 Relative_path.Map.iter
fast ~f
:(fun name info
->
169 FileInfo.n_classes
= classes
;
170 n_record_defs
= record_defs
;
177 Naming_global.ndecl_file_fast
185 (* Construct one instance of file type check computation. Class \Foo depends
186 on class \Bar being declared, so processing \Foo once should result in
188 - a declaration of \Bar
189 - a (deferred) type check of \Foo *)
190 let dynamic_view_files = Relative_path.Set.empty
in
192 Global_naming_options.set
194 { default
with tco_defer_class_declaration_threshold
= Some
1 };
195 Global_naming_options.get
()
197 let errors = Errors.empty
in
198 let file = Typing_check_service.{ path = foo_path; deferred_count = 0 } in
199 (* Finally, this is what all the setup was for: process this file *)
200 let (_errors
, file_computations
) =
201 Typing_check_service.process_file
dynamic_view_files opts errors file
203 Asserter.Int_asserter.assert_equals
205 (List.length file_computations
)
206 "Should be two file computations";
208 (* Validate the deferred type check computation *)
210 List.exists file_computations ~f
:(fun file_computation
->
211 match file_computation
with
212 | Typing_check_service.(Check
{ path; deferred_count }) ->
213 Asserter.String_asserter.assert_equals
215 (Relative_path.suffix
path)
216 "Check path must match the expected";
217 Asserter.Int_asserter.assert_equals
220 "Check deferred count must match the expected";
224 Asserter.Bool_asserter.assert_equals
227 "Should have found the check file computation";
229 (* Validate the declare file computation *)
231 List.exists file_computations ~f
:(fun file_computation
->
232 match file_computation
with
233 | Typing_check_service.Declare
path ->
234 Asserter.String_asserter.assert_equals
236 (Relative_path.suffix
path)
237 "Declare path must match the expected";
241 Asserter.Bool_asserter.assert_equals
244 "Should have found the declare file computation";
248 let test_should_enable_deferring () =
249 Relative_path.set_path_prefix
Relative_path.Root
(Path.make
"/fake/www");
252 GlobalOptions.{ default
with tco_max_times_to_defer_type_checking
= Some
2 }
255 Typing_check_service.
257 path = Relative_path.create
Relative_path.Root
"/fake/www/Foo.php";
261 Asserter.Bool_asserter.assert_equals
263 (Typing_check_service.should_enable_deferring
opts file)
264 "File should be deferred twice - below max";
266 let file = Typing_check_service.{ file with deferred_count = 2 } in
267 Asserter.Bool_asserter.assert_equals
269 (Typing_check_service.should_enable_deferring
opts file)
270 "File should not be deferred - at max";
272 let file = Typing_check_service.{ file with deferred_count = 3 } in
273 Asserter.Bool_asserter.assert_equals
275 (Typing_check_service.should_enable_deferring
opts file)
276 "File should not be deferred - above max";
279 GlobalOptions.{ default
with tco_max_times_to_defer_type_checking
= None
}
281 Asserter.Bool_asserter.assert_equals
283 (Typing_check_service.should_enable_deferring
opts file)
284 "File should be deferred - max is not set";
290 ("test_deferred_decl_add", test_deferred_decl_add);
291 ("test_deferred_decl_should_defer", test_deferred_decl_should_defer);
292 ("test_process_file_deferring", test_process_file_deferring);
293 ("test_dmesg_parser", test_dmesg_parser);
294 ("test_should_enable_deferring", test_should_enable_deferring);
297 let () = Unit_test.run_all
tests