<html><head> <link rel="stylesheet" href="style.css" type="text/css"> <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type"> <link rel="Start" href="index.html"> <link title="Index of types" rel=Appendix href="index_types.html"> <link title="Index of exceptions" rel=Appendix href="index_exceptions.html"> <link title="Index of values" rel=Appendix href="index_values.html"> <link title="Index of modules" rel=Appendix href="index_modules.html"> <link title="Index of module types" rel=Appendix href="index_module_types.html"> <link title="OUnit" rel="Chapter" href="OUnit.html"> <link title="OUnit2" rel="Chapter" href="OUnit2.html"> <link title="OUnitThreads" rel="Chapter" href="OUnitThreads.html"> <link title="OUnitUtils" rel="Chapter" href="OUnitUtils.html"> <link title="OUnitPropList" rel="Chapter" href="OUnitPropList.html"> <link title="OUnitPlugin" rel="Chapter" href="OUnitPlugin.html"> <link title="OUnitChooser" rel="Chapter" href="OUnitChooser.html"> <link title="OUnitResultSummary" rel="Chapter" href="OUnitResultSummary.html"> <link title="OUnitLoggerStd" rel="Chapter" href="OUnitLoggerStd.html"> <link title="OUnitLoggerHTML" rel="Chapter" href="OUnitLoggerHTML.html"> <link title="OUnitLoggerHTMLData" rel="Chapter" href="OUnitLoggerHTMLData.html"> <link title="OUnitLoggerJUnit" rel="Chapter" href="OUnitLoggerJUnit.html"> <link title="OUnitAssert" rel="Chapter" href="OUnitAssert.html"> <link title="OUnitBracket" rel="Chapter" href="OUnitBracket.html"> <link title="OUnitTest" rel="Chapter" href="OUnitTest.html"> <link title="OUnitState" rel="Chapter" href="OUnitState.html"> <link title="OUnitRunner" rel="Chapter" href="OUnitRunner.html"> <link title="OUnitRunnerProcesses" rel="Chapter" href="OUnitRunnerProcesses.html"> <link title="OUnitCore" rel="Chapter" href="OUnitCore.html"> <link title="OUnitLogger" rel="Chapter" href="OUnitLogger.html"> <link title="OUnitConf" rel="Chapter" href="OUnitConf.html"> <link title="OUnitShared" rel="Chapter" href="OUnitShared.html"> <link title="OUnitCache" rel="Chapter" href="OUnitCache.html"> <link title="OUnitTestData" rel="Chapter" href="OUnitTestData.html"> <link title="OUnitCheckEnv" rel="Chapter" href="OUnitCheckEnv.html"> <link title="OUnitDiff" rel="Chapter" href="OUnitDiff.html"><title>OUnit user guide : OUnitRunner.GenericWorker.runner</title> </head> <body> <code class="code"><span class="keyword">let</span> runner<br> create_worker workers_waiting<br> conf logger chooser test_cases =<br> <span class="keyword">let</span> map_test_cases =<br> <span class="constructor">List</span>.fold_left<br> (<span class="keyword">fun</span> mp ((test_path, _, _) <span class="keyword">as</span> test_case) <span class="keywordsign">-></span><br> <span class="constructor">MapPath</span>.add test_path test_case mp)<br> <span class="constructor">MapPath</span>.empty<br> test_cases<br> <span class="keyword">in</span><br> <br> <span class="keyword">let</span> state = <span class="constructor">OUnitState</span>.create conf chooser test_cases <span class="keyword">in</span><br> <br> <span class="keyword">let</span> shards = max (shards conf) 1 <span class="keyword">in</span><br> <br> <span class="keyword">let</span> master_id = logger.<span class="constructor">OUnitLogger</span>.lshard <span class="keyword">in</span><br> <br> <span class="keyword">let</span> worker_idx = ref 1 <span class="keyword">in</span><br> <br> <span class="keyword">let</span> test_per_worker, incr_tests_per_worker =<br> <span class="constructor">OUnitUtils</span>.make_counter ()<br> <span class="keyword">in</span><br> <span class="keyword">let</span> health_check_per_worker, incr_health_check_per_worker =<br> <span class="constructor">OUnitUtils</span>.make_counter ()<br> <span class="keyword">in</span><br> <br> <span class="keyword">let</span> () = infof logger <span class="string">"Using %d workers maximum."</span> shards; <span class="keyword">in</span><br> <br> <span class="keyword">let</span> worker_log_file =<br> <span class="keyword">if</span> not (<span class="constructor">OUnitLoggerStd</span>.is_output_file_shard_dependent conf) <span class="keyword">then</span> <span class="keyword">begin</span><br> warningf logger<br> <span class="string">"-output-file doesn't include $(shard_id), shards won't have file log."</span>;<br> <span class="keyword">false</span><br> <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span><br> <span class="keyword">true</span><br> <span class="keyword">end</span><br> <span class="keyword">in</span><br> <br> <span class="keyword">let</span> master_shared = <span class="constructor">OUnitShared</span>.noscope_create () <span class="keyword">in</span><br> <br> <span class="comment">(* Act depending on the received message. *)</span><br> <span class="keyword">let</span> process_message worker msg state =<br> <span class="keyword">match</span> msg <span class="keyword">with</span><br> <span class="keywordsign">|</span> <span class="constructor">AckExit</span> <span class="keywordsign">-></span><br> <span class="keyword">let</span> msg_opt =<br> infof logger <span class="string">"Worker %s has ended."</span> worker.shard_id;<br> worker.close_worker ()<br> <span class="keyword">in</span><br> <span class="constructor">OUnitUtils</span>.opt<br> (errorf logger <span class="string">"Worker return status: %s"</span>)<br> msg_opt;<br> remove_idle_worker worker state<br> <br> <span class="keywordsign">|</span> <span class="constructor">Log</span> log_ev <span class="keywordsign">-></span><br> <span class="constructor">OUnitLogger</span>.report (set_shard worker.shard_id logger) log_ev;<br> state<br> <br> <span class="keywordsign">|</span> <span class="constructor">Lock</span> id <span class="keywordsign">-></span><br> worker.channel.send_data<br> (<span class="constructor">AckLock</span> (master_shared.<span class="constructor">OUnitShared</span>.try_lock id));<br> state<br> <br> <span class="keywordsign">|</span> <span class="constructor">Unlock</span> id <span class="keywordsign">-></span><br> master_shared.<span class="constructor">OUnitShared</span>.unlock id;<br> state<br> <br> <span class="keywordsign">|</span> <span class="constructor">TestDone</span> test_result <span class="keywordsign">-></span><br> <span class="constructor">OUnitState</span>.test_finished conf test_result worker state<br> <span class="keyword">in</span><br> <br> <span class="comment">(* Report a worker dead and unregister it. *)</span><br> <span class="keyword">let</span> declare_dead_worker test_path worker result state =<br> <span class="keyword">let</span> log_pos = position logger <span class="keyword">in</span><br> report logger (<span class="constructor">TestEvent</span> (test_path, <span class="constructor">EResult</span> result));<br> report logger (<span class="constructor">TestEvent</span> (test_path, <span class="constructor">EEnd</span>));<br> remove_idle_worker<br> worker<br> (test_finished conf<br> ((test_path, result, log_pos), [])<br> worker state)<br> <span class="keyword">in</span><br> <br> <span class="comment">(* Kill the worker that has timed out. *)</span><br> <span class="keyword">let</span> kill_timeout state =<br> <span class="constructor">List</span>.fold_left<br> (<span class="keyword">fun</span> state (test_path, test_length, worker) <span class="keywordsign">-></span><br> <span class="keyword">let</span> _msg : string option =<br> errorf logger <span class="string">"Worker %s, running test %s has timed out."</span><br> worker.shard_id (string_of_path test_path);<br> worker.close_worker ()<br> <span class="keyword">in</span><br> declare_dead_worker test_path worker (<span class="constructor">RTimeout</span> test_length) state)<br> state<br> (get_worker_timed_out state)<br> <span class="keyword">in</span><br> <br> <span class="comment">(* Check that worker are healthy (i.e. still running). *)</span><br> <span class="keyword">let</span> check_health state =<br> <span class="constructor">List</span>.fold_left<br> (<span class="keyword">fun</span> state (test_path, worker) <span class="keywordsign">-></span><br> incr_health_check_per_worker worker.shard_id;<br> <span class="keyword">if</span> worker.is_running () <span class="keyword">then</span> <span class="keyword">begin</span><br> update_test_activity test_path state<br> <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span><br> <span class="comment">(* Argh, a test failed badly! *)</span><br> <span class="keyword">let</span> result_msg =<br> errorf logger<br> <span class="string">"Worker %s, running test %s is not running anymore."</span><br> worker.shard_id (string_of_path test_path);<br> <span class="keyword">match</span> worker.close_worker () <span class="keyword">with</span><br> <span class="keywordsign">|</span> <span class="constructor">Some</span> msg <span class="keywordsign">-></span><br> <span class="constructor">Printf</span>.sprintf <span class="string">"Worker stops running: %s"</span> msg<br> <span class="keywordsign">|</span> <span class="constructor">None</span> <span class="keywordsign">-></span><br> <span class="string">"Worker stops running for unknown reason."</span><br> <span class="keyword">in</span><br> declare_dead_worker test_path worker<br> (<span class="constructor">RError</span> (result_msg, <span class="constructor">None</span>))<br> state<br> <span class="keyword">end</span>)<br> state<br> (get_worker_need_health_check state)<br> <span class="keyword">in</span><br> <br> <span class="comment">(* Main wait loop. *)</span><br> <span class="keyword">let</span> <span class="keyword">rec</span> wait_test_done state =<br> <span class="keyword">let</span> state = (check_health (kill_timeout state)) <span class="keyword">in</span><br> <span class="keyword">if</span> get_workers state <> [] <span class="keyword">then</span> <span class="keyword">begin</span><br> <span class="keyword">let</span> workers_waiting_lst =<br> infof logger <span class="string">"%d tests running: %s."</span><br> (count_tests_running state)<br> (<span class="constructor">String</span>.concat <span class="string">", "</span><br> (<span class="constructor">List</span>.map string_of_path (get_tests_running state)));<br> workers_waiting (get_workers state) (timeout state)<br> <span class="keyword">in</span><br> <span class="constructor">List</span>.fold_left<br> (<span class="keyword">fun</span> state worker <span class="keywordsign">-></span><br> process_message worker (worker.channel.receive_data ()) state)<br> state<br> workers_waiting_lst<br> <br> <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span><br> state<br> <span class="keyword">end</span><br> <span class="keyword">in</span><br> <br> <span class="comment">(* Wait for every worker to stop. *)</span><br> <span class="keyword">let</span> <span class="keyword">rec</span> wait_stopped state =<br> <span class="keyword">if</span> <span class="constructor">OUnitState</span>.get_workers state = [] <span class="keyword">then</span><br> state<br> <span class="keyword">else</span><br> wait_stopped (wait_test_done state)<br> <span class="keyword">in</span><br> <br> <span class="keyword">let</span> <span class="keyword">rec</span> iter state =<br> <span class="keyword">match</span> <span class="constructor">OUnitState</span>.next_test_case conf logger state <span class="keyword">with</span><br> <span class="keywordsign">|</span> <span class="constructor">Not_enough_worker</span>, state <span class="keywordsign">-></span><br> <span class="keyword">if</span> <span class="constructor">OUnitState</span>.count_worker state < shards <span class="keyword">then</span> <span class="keyword">begin</span><br> <span class="comment">(* Start a worker. *)</span><br> <span class="keyword">let</span> shard_id = <span class="constructor">OUnitUtils</span>.shardf !worker_idx <span class="keyword">in</span><br> <span class="keyword">let</span> () = infof logger <span class="string">"Starting worker number %s."</span> shard_id <span class="keyword">in</span><br> <span class="keyword">let</span> worker =<br> create_worker<br> conf map_test_cases shard_id master_id worker_log_file<br> <span class="keyword">in</span><br> <span class="keyword">let</span> () = infof logger <span class="string">"Worker %s started."</span> worker.shard_id <span class="keyword">in</span><br> <span class="keyword">let</span> state = add_worker worker state <span class="keyword">in</span><br> incr worker_idx;<br> iter state<br> <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span><br> iter (wait_test_done state)<br> <span class="keyword">end</span><br> <br> <span class="keywordsign">|</span> <span class="constructor">Try_again</span>, state <span class="keywordsign">-></span><br> iter (wait_test_done state)<br> <br> <span class="keywordsign">|</span> <span class="constructor">Next_test_case</span> (test_path, _, worker), state <span class="keywordsign">-></span><br> incr_tests_per_worker worker.shard_id;<br> worker.channel.send_data (<span class="constructor">RunTest</span> test_path);<br> iter state<br> <br> <span class="keywordsign">|</span> <span class="constructor">Finished</span>, state <span class="keywordsign">-></span><br> <span class="keyword">let</span> count_tests_running = <span class="constructor">OUnitState</span>.count_tests_running state <span class="keyword">in</span><br> <span class="keyword">if</span> count_tests_running = 0 <span class="keyword">then</span> <span class="keyword">begin</span><br> <span class="keyword">let</span> state =<br> <span class="constructor">List</span>.iter<br> (<span class="keyword">fun</span> worker <span class="keywordsign">-></span> worker.channel.send_data <span class="constructor">Exit</span>)<br> (<span class="constructor">OUnitState</span>.get_workers state);<br> wait_stopped state<br> <span class="keyword">in</span><br> infof logger <span class="string">"Used %d worker during test execution."</span><br> (!worker_idx - 1);<br> <span class="constructor">List</span>.iter<br> (<span class="keyword">fun</span> (shard_id, count) <span class="keywordsign">-></span><br> infof logger <span class="string">"Run %d tests with shard %s."</span><br> count shard_id)<br> (test_per_worker ());<br> <span class="constructor">List</span>.iter<br> (<span class="keyword">fun</span> (shard_id, count) <span class="keywordsign">-></span><br> infof logger <span class="string">"Check health of shard %s, %d times."</span><br> shard_id count)<br> (health_check_per_worker ());<br> <span class="constructor">OUnitState</span>.get_results state<br> <span class="keyword">end</span> <span class="keyword">else</span> <span class="keyword">begin</span><br> infof logger <span class="string">"Still %d tests running : %s."</span> count_tests_running<br> (<span class="constructor">String</span>.concat <span class="string">", "</span><br> (<span class="constructor">List</span>.map string_of_path<br> (get_tests_running state)));<br> iter (wait_test_done state)<br> <span class="keyword">end</span><br> <span class="keyword">in</span><br> iter state</code></body></html>