5 echo 'CoreCLR test runner script.'
7 echo 'Typical command line:'
9 echo 'coreclr/tests/runtest.sh'
10 echo ' --testRootDir="temp/Windows_NT.x64.Debug"'
11 echo ' --testNativeBinDir="coreclr/bin/obj/Linux.x64.Debug/tests"'
12 echo ' --coreClrBinDir="coreclr/bin/Product/Linux.x64.Debug"'
13 echo ' --mscorlibDir="windows/coreclr/bin/Product/Linux.x64.Debug"'
14 echo ' --coreFxBinDir="corefx/bin/Linux.AnyCPU.Debug"'
15 echo ' --coreFxNativeBinDir="corefx/bin/Linux.x64.Debug"'
17 echo 'Required arguments:'
18 echo ' --testRootDir=<path> : Root directory of the test build (e.g. coreclr/bin/tests/Windows_NT.x64.Debug).'
19 echo ' --testNativeBinDir=<path> : Directory of the native CoreCLR test build (e.g. coreclr/bin/obj/Linux.x64.Debug/tests).'
20 echo ' (Also required: Either --coreOverlayDir, or all of the switches --coreOverlayDir overrides)'
22 echo 'Optional arguments:'
23 echo ' --coreOverlayDir=<path> : Directory containing core binaries and test dependencies. If not specified, the'
24 echo ' default is testRootDir/Tests/coreoverlay. This switch overrides --coreClrBinDir,'
25 echo ' --mscorlibDir, --coreFxBinDir, and --coreFxNativeBinDir.'
26 echo ' --coreClrBinDir=<path> : Directory of the CoreCLR build (e.g. coreclr/bin/Product/Linux.x64.Debug).'
27 echo ' --mscorlibDir=<path> : Directory containing the built mscorlib.dll. If not specified, it is expected to be'
28 echo ' in the directory specified by --coreClrBinDir.'
29 echo ' --coreFxBinDir="<path>[;<path>]" : List of one or more directories with CoreFX build outputs (semicolon-delimited)'
30 echo ' (e.g. "corefx/bin/Linux.AnyCPU.Debug;corefx/bin/Unix.AnyCPU.Debug;corefx/bin/AnyOS.AnyCPU.Debug").'
31 echo ' If files with the same name are present in multiple directories, the first one wins.'
32 echo ' --coreFxNativeBinDir=<path> : Directory of the CoreFX native build (e.g. corefx/bin/Linux.x64.Debug).'
33 echo ' --testDir=<path> : Run tests only in the specified directory. The path is relative to the directory'
34 echo ' specified by --testRootDir. Multiple of this switch may be specified.'
35 echo ' --testDirFile=<path> : Run tests only in the directories specified by the file at <path>. Paths are listed'
36 echo ' one line, relative to the directory specified by --testRootDir.'
37 echo ' --runFailingTestsOnly : Run only the tests that are disabled on this platform due to unexpected failures.'
38 echo ' Failing tests are listed in coreclr/tests/failingTestsOutsideWindows.txt, one per'
39 echo ' line, as paths to .sh files relative to the directory specified by --testRootDir.'
40 echo ' --disableEventLogging : Disable the events logged by both VM and Managed Code'
41 echo ' --sequential : Run tests sequentially (default is to run in parallel).'
42 echo ' --playlist=<path> : Run only the tests that are specified in the file at <path>, in the same format as'
43 echo ' runFailingTestsOnly'
44 echo ' -v, --verbose : Show output from each test.'
45 echo ' -h|--help : Show usage information.'
46 echo ' --useServerGC : Enable server GC for this test run'
47 echo ' --test-en : Script to set environment variables for tests'
49 echo 'Runtime Code Coverage options:'
50 echo ' --coreclr-coverage : Optional argument to get coreclr code coverage reports'
51 echo ' --coreclr-objs=<path> : Location of root of the object directory'
52 echo ' containing the linux/mac coreclr build'
53 echo ' --coreclr-src=<path> : Location of root of the directory'
54 echo ' containing the coreclr source files'
55 echo ' --coverage-output-dir=<path> : Directory where coverage output will be written to'
59 function print_results {
61 echo "======================="
63 echo "======================="
64 echo "# Tests Discovered : $countTotalTests"
65 echo "# Passed : $countPassedTests"
66 echo "# Failed : $countFailedTests"
67 echo "# Skipped : $countSkippedTests"
68 echo "======================="
71 # Initialize counters for bookkeeping.
77 # Variables for xUnit-style XML output. XML format: https://xunit.github.io/docs/format-xml-v2.html
81 # libExtension determines extension for dynamic library files
98 echo "Unsupported OS $OSName detected, configuring as if for Linux"
104 function xunit_output_begin {
105 xunitOutputPath=$testRootDir/coreclrtests.xml
106 xunitTestOutputPath=${xunitOutputPath}.test
107 if [ -e "$xunitOutputPath" ]; then
108 rm -f -r "$xunitOutputPath"
110 if [ -e "$xunitTestOutputPath" ]; then
111 rm -f -r "$xunitTestOutputPath"
115 function xunit_output_add_test {
119 # <test .../> <!-- Write this element here -->
121 local scriptFilePath=$1
122 local outputFilePath=$2
123 local testResult=$3 # Pass, Fail, or Skip
124 local testScriptExitCode=$4
126 local testPath=${scriptFilePath%.sh} # Remove trailing ".sh"
127 local testDir=$(dirname "$testPath")
128 local testName=$(basename "$testPath")
130 # Replace '/' with '.'
131 testPath=$(echo "$testPath" | tr / .)
132 testDir=$(echo "$testDir" | tr / .)
138 line="${line} name=\"${testPath}\""
139 line="${line} type=\"${testDir}\""
140 line="${line} method=\"${testName}\""
141 line="${line} result=\"${testResult}\""
143 if [ "$testResult" == "Pass" ]; then
145 echo "$line" >>"$xunitTestOutputPath"
150 echo "$line" >>"$xunitTestOutputPath"
153 if [ "$testResult" == "Skip" ]; then
154 line="${line}<reason><![CDATA[$(cat "$outputFilePath")]]></reason>"
155 echo "$line" >>"$xunitTestOutputPath"
157 line="${line}<failure exception-type=\"Exit code: ${testScriptExitCode}\">"
158 echo "$line" >>"$xunitTestOutputPath"
161 line="${line}<message>"
162 echo "$line" >>"$xunitTestOutputPath"
164 line="${line}<![CDATA["
165 echo "$line" >>"$xunitTestOutputPath"
166 cat "$outputFilePath" >>"$xunitTestOutputPath"
169 echo "$line" >>"$xunitTestOutputPath"
171 line="${line}</message>"
172 echo "$line" >>"$xunitTestOutputPath"
175 line="${line}</failure>"
176 echo "$line" >>"$xunitTestOutputPath"
180 line="${line}</test>"
181 echo "$line" >>"$xunitTestOutputPath"
184 function xunit_output_end {
186 local errorMessage=$2
189 if [ -z "$errorSource" ]; then
195 echo '<?xml version="1.0" encoding="utf-8"?>' >>"$xunitOutputPath"
196 echo '<assemblies>' >>"$xunitOutputPath"
202 line="${line}<assembly"
203 line="${line} name=\"CoreClrTestAssembly\""
204 line="${line} total=\"${countTotalTests}\""
205 line="${line} passed=\"${countPassedTests}\""
206 line="${line} failed=\"${countFailedTests}\""
207 line="${line} skipped=\"${countSkippedTests}\""
208 line="${line} errors=\"${errorCount}\""
210 echo "$line" >>"$xunitOutputPath"
214 line="${line}<collection"
215 line="${line} name=\"CoreClrTestCollection\""
216 line="${line} total=\"${countTotalTests}\""
217 line="${line} passed=\"${countPassedTests}\""
218 line="${line} failed=\"${countFailedTests}\""
219 line="${line} skipped=\"${countSkippedTests}\""
221 echo "$line" >>"$xunitOutputPath"
223 # <test .../> <test .../> ...
224 if [ -f "$xunitTestOutputPath" ]; then
225 cat "$xunitTestOutputPath" >>"$xunitOutputPath"
226 rm -f "$xunitTestOutputPath"
231 line="${line}</collection>"
232 echo "$line" >>"$xunitOutputPath"
234 if [ -n "$errorSource" ]; then
237 line="${line}<errors>"
238 echo "$line" >>"$xunitOutputPath"
243 line="${line} type=\"TestHarnessError\""
244 line="${line} name=\"${errorSource}\""
246 echo "$line" >>"$xunitOutputPath"
250 line="${line}<failure>${errorMessage}</failure>"
251 echo "$line" >>"$xunitOutputPath"
255 line="${line}</error>"
256 echo "$line" >>"$xunitOutputPath"
260 line="${line}</errors>"
261 echo "$line" >>"$xunitOutputPath"
266 line="${line}</assembly>"
267 echo "$line" >>"$xunitOutputPath"
270 echo '</assemblies>' >>"$xunitOutputPath"
273 function exit_with_error {
275 local errorMessage=$2
278 if [ -z "$printUsage" ]; then
283 xunit_output_end "$errorSource" "$errorMessage"
284 if ((printUsage != 0)); then
287 exit $EXIT_CODE_EXCEPTION
290 # Handle Ctrl-C. We will stop execution and print the results that
291 # we gathered so far.
292 function handle_ctrl_c {
293 local errorSource='handle_ctrl_c'
296 echo "*** Stopping... ***"
298 exit_with_error "$errorSource" "Test run aborted by Ctrl+C."
301 # Register the Ctrl-C handler
302 trap handle_ctrl_c INT
304 function create_core_overlay {
305 local errorSource='create_core_overlay'
308 if [ -n "$coreOverlayDir" ]; then
309 export CORE_ROOT="$coreOverlayDir"
313 # Check inputs to make sure we have enough information to create the core layout. $testRootDir/Tests/Core_Root should
314 # already exist and contain test dependencies that are not built.
315 local testDependenciesDir=$testRootDir/Tests/Core_Root
316 if [ ! -d "$testDependenciesDir" ]; then
317 exit_with_error "$errorSource" "Did not find the test dependencies directory: $testDependenciesDir"
319 if [ -z "$coreClrBinDir" ]; then
320 exit_with_error "$errorSource" "One of --coreOverlayDir or --coreClrBinDir must be specified." "$printUsage"
322 if [ ! -d "$coreClrBinDir" ]; then
323 exit_with_error "$errorSource" "Directory specified by --coreClrBinDir does not exist: $coreClrBinDir"
325 if [ ! -f "$mscorlibDir/mscorlib.dll" ]; then
326 exit_with_error "$errorSource" "mscorlib.dll was not found in: $mscorlibDir"
328 if [ -z "$coreFxBinDir" ]; then
329 exit_with_error "$errorSource" "One of --coreOverlayDir or --coreFxBinDir must be specified." "$printUsage"
331 if [ -z "$coreFxNativeBinDir" ]; then
332 exit_with_error "$errorSource" "One of --coreOverlayDir or --coreFxBinDir must be specified." "$printUsage"
334 if [ ! -d "$coreFxNativeBinDir/Native" ]; then
335 exit_with_error "$errorSource" "Directory specified by --coreFxBinDir does not exist: $coreFxNativeBinDir/Native"
339 coreOverlayDir=$testRootDir/Tests/coreoverlay
340 export CORE_ROOT="$coreOverlayDir"
341 if [ -e "$coreOverlayDir" ]; then
342 rm -f -r "$coreOverlayDir"
344 mkdir "$coreOverlayDir"
346 while IFS=';' read -ra coreFxBinDirectories; do
347 for currDir in "${coreFxBinDirectories[@]}"; do
348 if [ ! -d "$currDir" ]; then
349 exit_with_error "$errorSource" "Directory specified in --coreFxBinDir does not exist: $currDir"
352 (cd $currDir && find . -iname '*.dll' \! -iwholename '*test*' \! -iwholename '*/ToolRuntime/*' \! -iwholename '*/RemoteExecutorConsoleApp/*' \! -iwholename '*/net*' \! -iwholename '*aot*' -exec cp -n '{}' "$coreOverlayDir/" \;)
354 done <<< $coreFxBinDir
356 cp -f "$coreFxNativeBinDir/Native/"*."$libExtension" "$coreOverlayDir/" 2>/dev/null
358 cp -f "$coreClrBinDir/"* "$coreOverlayDir/" 2>/dev/null
359 cp -f "$mscorlibDir/mscorlib.dll" "$coreOverlayDir/"
360 cp -n "$testDependenciesDir"/* "$coreOverlayDir/" 2>/dev/null
361 if [ -f "$coreOverlayDir/mscorlib.ni.dll" ]; then
362 # Test dependencies come from a Windows build, and mscorlib.ni.dll would be the one from Windows
363 rm -f "$coreOverlayDir/mscorlib.ni.dll"
367 function precompile_overlay_assemblies {
369 if [ $doCrossgen == 1 ]; then
371 local overlayDir=$CORE_ROOT
373 filesToPrecompile=$(ls -trh $overlayDir/*.dll)
374 for fileToPrecompile in ${filesToPrecompile}
376 local filename=${fileToPrecompile}
377 # Precompile any assembly except mscorlib since we already have its NI image available.
378 if [[ "$filename" != *"mscorlib.dll"* ]]; then
379 if [[ "$filename" != *"mscorlib.ni.dll"* ]]; then
380 echo Precompiling $filename
381 $overlayDir/crossgen /Platform_Assemblies_Paths $overlayDir $filename 2>/dev/null
383 if [ $exitCode == -2146230517 ]; then
384 echo $filename is not a managed assembly.
385 elif [ $exitCode != 0 ]; then
386 echo Unable to precompile $filename.
388 echo Successfully precompiled $filename
394 echo Skipping crossgen of FX assemblies.
398 function copy_test_native_bin_to_test_root {
399 local errorSource='copy_test_native_bin_to_test_root'
401 if [ -z "$testNativeBinDir" ]; then
402 exit_with_error "$errorSource" "--testNativeBinDir is required."
404 testNativeBinDir=$testNativeBinDir/src
405 if [ ! -d "$testNativeBinDir" ]; then
406 exit_with_error "$errorSource" "Directory specified by --testNativeBinDir does not exist: $testNativeBinDir"
409 # Copy native test components from the native test build into the respective test directory in the test root directory
410 find "$testNativeBinDir" -type f -iname '*.$libExtension' |
411 while IFS='' read -r filePath || [ -n "$filePath" ]; do
412 local dirPath=$(dirname "$filePath")
413 local destinationDirPath=${testRootDir}${dirPath:${#testNativeBinDir}}
414 if [ ! -d "$destinationDirPath" ]; then
415 exit_with_error "$errorSource" "Cannot copy native test bin '$filePath' to '$destinationDirPath/', as the destination directory does not exist."
417 cp -f "$filePath" "$destinationDirPath/"
421 # Variables for unsupported and failing tests
422 declare -a unsupportedTests
423 declare -a failingTests
424 declare -a playlistTests
425 ((runFailingTestsOnly = 0))
427 # Get an array of items by reading the specified file line by line.
428 function read_array {
431 # bash in Mac OS X doesn't support 'readarray', so using alternate way instead.
432 # readarray -t theArray < "$1"
433 while IFS='' read -r line || [ -n "$line" ]; do
434 theArray[${#theArray[@]}]=$line
439 function load_unsupported_tests {
440 # Load the list of tests that are not supported on this platform. These tests are disabled (skipped) permanently.
441 unsupportedTests=($(read_array "$(dirname "$0")/testsUnsupportedOutsideWindows.txt"))
444 function load_failing_tests {
445 # Load the list of tests that fail on this platform. These tests are disabled (skipped) temporarily, pending investigation.
446 failingTests=($(read_array "$(dirname "$0")/testsFailingOutsideWindows.txt"))
449 function load_playlist_tests {
450 # Load the list of tests that are enabled as a part of this test playlist.
451 playlistTests=($(read_array "${playlistFile}"))
454 function is_unsupported_test {
455 for unsupportedTest in "${unsupportedTests[@]}"; do
456 if [ "$1" == "$unsupportedTest" ]; then
463 function is_failing_test {
464 for failingTest in "${failingTests[@]}"; do
465 if [ "$1" == "$failingTest" ]; then
472 function is_playlist_test {
473 for playlistTest in "${playlistTests[@]}"; do
474 if [ "$1" == "$playlistTest" ]; then
481 function skip_unsupported_test {
482 # This function runs in a background process. It should not echo anything, and should not use global variables. This
483 # function is analogous to run_test, and causes the test to be skipped with the message below.
485 local scriptFilePath=$1
486 local outputFilePath=$2
488 echo "Not supported on this platform." >"$outputFilePath"
489 return 2 # skip the test
492 function skip_failing_test {
493 # This function runs in a background process. It should not echo anything, and should not use global variables. This
494 # function is analogous to run_test, and causes the test to be skipped with the message below.
496 local scriptFilePath=$1
497 local outputFilePath=$2
499 echo "Temporarily disabled on this platform due to unexpected failures." >"$outputFilePath"
500 return 2 # skip the test
503 function skip_non_playlist_test {
504 # This function runs in a background process. It should not echo anything, and should not use global variables. This
505 # function is analogous to run_test, and causes the test to be skipped with the message below.
507 local scriptFilePath=$1
508 local outputFilePath=$2
510 echo "Test is not included in the running playlist." >"$outputFilePath"
511 return 2 # skip the test
515 # This function runs in a background process. It should not echo anything, and should not use global variables.
517 local scriptFilePath=$1
518 local outputFilePath=$2
520 # Switch to directory where the script is
521 cd "$(dirname "$scriptFilePath")"
523 local scriptFileName=$(basename "$scriptFilePath")
524 local outputFileName=$(basename "$outputFilePath")
526 # Convert DOS line endings to Unix if needed
527 perl -pi -e 's/\r\n|\n|\r/\n/g' "$scriptFileName"
529 # Add executable file mode bit if needed
530 chmod +x "$scriptFileName"
532 "./$scriptFileName" >"$outputFileName" 2>&1
536 # Variables for running tests in the background
537 if [ `uname` = "NetBSD" ]; then
538 NumProc=$(getconf NPROCESSORS_ONLN)
540 NumProc=$(getconf _NPROCESSORS_ONLN)
542 ((maxProcesses = $NumProc * 3 / 2)) # long tests delay process creation, use a few more processors
544 ((nextProcessIndex = 0))
546 declare -a scriptFilePaths
547 declare -a outputFilePaths
548 declare -a processIds
550 function finish_test {
551 wait ${processIds[$nextProcessIndex]}
552 local testScriptExitCode=$?
555 local scriptFilePath=${scriptFilePaths[$nextProcessIndex]}
556 local outputFilePath=${outputFilePaths[$nextProcessIndex]}
557 local scriptFileName=$(basename "$scriptFilePath")
559 local xunitTestResult
560 case $testScriptExitCode in
562 let countPassedTests++
563 xunitTestResult='Pass'
564 if ((verbose == 1 || runFailingTestsOnly == 1)); then
565 echo "PASSED - $scriptFilePath"
567 echo " - $scriptFilePath"
571 let countSkippedTests++
572 xunitTestResult='Skip'
573 echo "SKIPPED - $scriptFilePath"
576 let countFailedTests++
577 xunitTestResult='Fail'
578 echo "FAILED - $scriptFilePath"
581 let countTotalTests++
583 if ((verbose == 1 || testScriptExitCode != 0)); then
584 while IFS='' read -r line || [ -n "$line" ]; do
586 done <"$outputFilePath"
589 xunit_output_add_test "$scriptFilePath" "$outputFilePath" "$xunitTestResult" "$testScriptExitCode"
592 function finish_remaining_tests {
593 # Finish the remaining tests in the order in which they were started
594 if ((nextProcessIndex >= processCount)); then
595 ((nextProcessIndex = 0))
597 while ((processCount > 0)); do
599 ((nextProcessIndex = (nextProcessIndex + 1) % maxProcesses))
601 ((nextProcessIndex = 0))
605 local scriptFilePath=$1
607 test "$verbose" == 1 && echo "Preparing $scriptFilePath"
609 # Convert DOS line endings to Unix if needed
610 perl -pi -e 's/\r\n|\n|\r/\n/g' "$scriptFilePath"
612 # Add executable file mode bit if needed
613 chmod +x "$scriptFilePath"
617 function start_test {
618 local scriptFilePath=$1
619 if ((runFailingTestsOnly == 1)) && ! is_failing_test "$scriptFilePath"; then
623 # Skip any test that's not in the current playlist, if a playlist was
625 if [ -n "$playlistFile" ] && ! is_playlist_test "$scriptFilePath"; then
629 if ((nextProcessIndex < processCount)); then
633 scriptFilePaths[$nextProcessIndex]=$scriptFilePath
634 local scriptFileName=$(basename "$scriptFilePath")
635 local outputFilePath=$(dirname "$scriptFilePath")/${scriptFileName}.out
636 outputFilePaths[$nextProcessIndex]=$outputFilePath
638 test "$verbose" == 1 && echo "Starting $scriptFilePath"
639 if is_unsupported_test "$scriptFilePath"; then
640 skip_unsupported_test "$scriptFilePath" "$outputFilePath" &
641 elif ((runFailingTestsOnly == 0)) && is_failing_test "$scriptFilePath"; then
642 skip_failing_test "$scriptFilePath" "$outputFilePath" &
644 run_test "$scriptFilePath" "$outputFilePath" &
646 processIds[$nextProcessIndex]=$!
648 ((nextProcessIndex = (nextProcessIndex + 1) % maxProcesses))
652 # Get a list of directories in which to scan for tests by reading the
653 # specified file line by line.
654 function set_test_directories {
655 local errorSource='set_test_directories'
657 local listFileName=$1
659 if [ ! -f "$listFileName" ]
661 exit_with_error "$errorSource" "Test directories file not found at $listFileName"
663 testDirectories=($(read_array "$listFileName"))
666 function run_tests_in_directory {
669 # Recursively search through directories for .sh files to prepare them.
670 for scriptFilePath in $(find "$testDir" -type f -iname '*.sh' | sort)
672 prep_test "${scriptFilePath:2}"
674 echo "The tests have been prepared"
675 # Recursively search through directories for .sh files to run.
676 for scriptFilePath in $(find "$testDir" -type f -iname '*.sh' | sort)
678 start_test "${scriptFilePath:2}"
682 function coreclr_code_coverage()
685 local coverageDir="$coverageOutputDir/Coverage"
686 local toolsDir="$coverageOutputDir/Coverage/tools"
687 local reportsDir="$coverageOutputDir/Coverage/reports"
688 local packageName="unix-code-coverage-tools.1.0.0.nupkg"
690 mkdir -p $coverageDir
693 pushd $toolsDir > /dev/null
695 echo "Pulling down code coverage tools"
696 wget -q https://www.myget.org/F/dotnet-buildtools/api/v2/package/unix-code-coverage-tools/1.0.0 -O $packageName
697 echo "Unzipping to $toolsDir"
698 unzip -q -o $packageName
702 chmod a+rwx ./$OSName/llvm-cov
705 echo "Generating coreclr code coverage reports at $reportsDir/coreclr.html"
706 echo "./gcovr $coreClrObjs --gcov-executable=$toolsDir/$OS/llvm-cov -r $coreClrSrc --html --html-details -o $reportsDir/coreclr.html"
708 ./gcovr $coreClrObjs --gcov-executable=$toolsDir/$OSName/llvm-cov -r $coreClrSrc --html --html-details -o $reportsDir/coreclr.html
714 # Exit code constants
715 readonly EXIT_CODE_SUCCESS=0 # Script ran normally.
716 readonly EXIT_CODE_EXCEPTION=1 # Script exited because something exceptional happened (e.g. bad arguments, Ctrl-C interrupt).
717 readonly EXIT_CODE_TEST_FAILURE=2 # Script completed successfully, but one or more tests failed.
733 ((disableEventLogging = 0))
745 exit $EXIT_CODE_SUCCESS
756 --testNativeBinDir=*)
757 testNativeBinDir=${i#*=}
760 coreOverlayDir=${i#*=}
763 coreClrBinDir=${i#*=}
771 --coreFxNativeBinDir=*)
772 coreFxNativeBinDir=${i#*=}
775 testDirectories[${#testDirectories[@]}]=${i#*=}
778 set_test_directories "${i#*=}"
780 --runFailingTestsOnly)
781 ((runFailingTestsOnly = 1))
783 --disableEventLogging)
784 ((disableEventLogging = 1))
804 --coverage-output-dir=*)
805 coverageOutputDir=${i#*=}
811 echo "Unknown switch: $i"
813 exit $EXIT_CODE_SUCCESS
818 if ((disableEventLogging == 0)); then
819 export COMPlus_EnableEventLog=1
822 export CORECLR_SERVER_GC="$serverGC"
824 if [ -z "$testRootDir" ]; then
825 echo "--testRootDir is required."
827 exit $EXIT_CODE_EXCEPTION
829 if [ ! -d "$testRootDir" ]; then
830 echo "Directory specified by --testRootDir does not exist: $testRootDir"
831 exit $EXIT_CODE_EXCEPTION
834 # Copy native interop test libraries over to the mscorlib path in
835 # order for interop tests to run on linux.
836 if [ -z "$mscorlibDir" ]; then
837 mscorlibDir=$coreClrBinDir
839 if [ -d $mscorlibDir/bin ]; then
840 cp $mscorlibDir/bin/* $mscorlibDir
843 # If this is a coverage run, make sure the appropriate args have been passed
844 if [ "$CoreClrCoverage" == "ON" ]
846 echo "Code coverage is enabled for this run"
848 if [ ! "$OSName" == "Darwin" ] && [ ! "$OSName" == "Linux" ]
850 echo "Code Coverage not supported on $OS"
854 if [ -z "$coreClrObjs" ]
856 echo "Coreclr obj files are required to generate code coverage reports"
857 echo "Coreclr obj files root path can be passed using '--coreclr-obj' argument"
861 if [ -z "$coreClrSrc" ]
863 echo "Coreclr src files are required to generate code coverage reports"
864 echo "Coreclr src files root path can be passed using '--coreclr-src' argument"
868 if [ -z "$coverageOutputDir" ]
870 echo "Output directory for coverage results must be specified"
871 echo "Output path can be specified '--coverage-output-dir' argument"
878 precompile_overlay_assemblies
879 copy_test_native_bin_to_test_root
881 if [ -n "$playlistFile" ]
883 # Use a playlist file exclusively, if it was provided
884 echo "Executing playlist $playlistFile"
887 load_unsupported_tests
891 scriptPath=$(dirname $0)
892 ${scriptPath}/setup-runtime-dependencies.sh --outputDir=$coreOverlayDir
895 if [ -z "$testDirectories" ]
897 # No test directories were specified, so run everything in the current
898 # directory and its subdirectories.
899 run_tests_in_directory "."
901 # Otherwise, run all the tests in each specified test directory.
902 for testDir in "${testDirectories[@]}"
904 if [ ! -d "$testDir" ]; then
905 echo "Test directory does not exist: $testDir"
907 run_tests_in_directory "./$testDir"
911 finish_remaining_tests
916 if [ "$CoreClrCoverage" == "ON" ]
918 coreclr_code_coverage
921 if ((countFailedTests > 0)); then
922 exit $EXIT_CODE_TEST_FAILURE
925 exit $EXIT_CODE_SUCCESS