[TIZEN] Add unsupportedTests.GCStress.riscv64.txt
[platform/upstream/dotnet/runtime.git] / runtest_clr.sh
1 #!/usr/bin/env bash
2
3 function print_usage {
4     echo ''
5     echo 'CoreCLR test runner script.'
6     echo 'Script uses next files if they exist:'
7     echo '    unsupportedTests.txt'
8     echo '    unsupportedCrossgenLibs.txt'
9     echo '    unsupportedCrossgenTests.txt'
10     echo '    unsupportedGCStressTests.txt'
11     echo ''
12     echo 'Typical Tizen command:'
13     echo '    coreclr/tests/runtest.sh'
14     echo '    --arch=armel'
15     echo '    --testRootDir="/opt/usr/coreclr-tc"'
16     echo '    --coreOverlayDir="/opt/usr/coreclr-tc/coreroot"'
17     echo '    --netcoreDir="/usr/share/dotnet.tizen/netcoreapp"'
18     echo '    --copy-netcore-to-coreroot'
19     echo '    --xunitOutputPath="/opt/usr/coreclr-tc/results/coreclrtests.xml"'
20     echo '    --testsPassOutputPath="/opt/usr/coreclr-tc/results/coreclrtests.pass.txt"'
21     echo '    --testsSkipOutputPath="/opt/usr/coreclr-tc/results/coreclrtests.skip.txt"'
22     echo '    --testsFailOutputPath="/opt/usr/coreclr-tc/results/coreclrtests.fail.txt"'
23     echo '    --libsCrossgenPassOutputPath="/opt/usr/coreclr-tc/results/crossgenlibs.pass.txt"'
24     echo '    --libsCrossgenSkipOutputPath="/opt/usr/coreclr-tc/results/crossgenlibs.skip.txt"'
25     echo '    --libsCrossgenFailOutputPath="/opt/usr/coreclr-tc/results/crossgenlibs.fail.txt"'
26     echo '    --crossgen2options="--jitpath /opt/usr/coreclr-tc/coreroot/libclrjit.so --targetarch armel --parallelism 4 -O"'
27     echo ''
28     echo 'Required arguments:'
29     echo '  --arch=<arch>                    : Target arch (for TW targets "armel" should be passed instead of "arm64", for TM use "armel"; allowed values: "arm", "armel", "arm64", "x64", "x86", "riscv64").'
30     echo '  --testRootDir=<path>             : Root directory of the test build (default: /opt/usr/coreclr-tc).'
31     echo '  --coreOverlayDir=<path>          : Directory containing CLR and FX (default: /opt/usr/coreclr-tc/coreroot).'
32     echo ''
33     echo 'Optional arguments:'
34     echo '  --netcoreDir=<path>              : Netcore (CLR and FX) system dir (default: /usr/share/dotnet.tizen/netcoreapp).'
35     echo '  --copy-netcore-to-coreroot       : Copy netcore (CLR and FX) from netcore system dir to coreroot.'
36     echo '  --testDir=<path>                 : Run tests only in the specified directory. The path is relative to the directory'
37     echo '                                     specified by --testRootDir. Multiple of this switch may be specified.'
38     echo '  --testDirFile=<path>             : Run tests only in the directories specified by the file at <path>. Paths are listed'
39     echo '                                     one line, relative to the directory specified by --testRootDir.'
40     echo '  --num-procs=<N>                  : Run N test processes at the same time (default is 1).'
41     echo '  -v, --verbose                    : Show output from each test.'
42     echo '  -h, --help                       : Show usage information.'
43     echo '  --xunitOutputPath=<path>         : Create xUnit XML report at the specifed path (default: <test root dir>/coreclrtests.xml)'
44     echo '  --testsPassOutputPath=<path>     : Create pass report at the specifed path (default: <test root dir>/coreclrtests.pass.txt)'
45     echo '  --testsSkipOutputPath=<path>     : Create skip report at the specifed path (default: <test root dir>/coreclrtests.skip.txt)'
46     echo '  --testsFailOutputPath=<path>     : Create fail report at the specifed path (default: <test root dir>/coreclrtests.fail.txt)'
47     echo '  --test-env                       : Script to set environment variables for tests.'
48     echo ''
49     echo 'Optional arguments with "export COMPlus_..." meaning:'
50     echo '  --jitstress=<n>                  : Runs the tests with COMPlus_JitStress=n'
51     echo '  --jitstressregs=<n>              : Runs the tests with COMPlus_JitStressRegs=n'
52     echo '  --gcstresslevel=<n>              : Runs the tests with COMPlus_GCStress=n'
53     echo ''
54     echo 'MulticoreJit:'
55     echo '  --mcj                            : Runs the tests with COMPlus_MultiCoreJitProfile=<some_tmp_path> COMPlus_MultiCoreJitMinNumCpus=1 (each test is launched 2 times: first launch to gather profile, second launch to use profile)'
56     echo '  --mcj-no-profile-gather          : Runs the tests with COMPlus_MultiCoreJitNoProfileGather=1 on the second mcj launch'
57     echo ''
58     echo 'Crossgen:'
59     echo '  --crossgen-libs                  : Precompiles system libs.'
60     echo '  --crossgen-tests                 : Precompiles tests.'
61     echo '  --crossgenoptions                : Options passed to crossgen.'
62     echo '  --allow-crossgen-fails           : Allow crossgen to ignore compilation fails.'
63     echo '  --crossgen-lib=<path>            : Precompile only specified lib. The path is absolute.'
64     echo '  --libsCrossgenPassOutputPath=<path>  : Create crossgen pass report at the specifed path (default: <test root dir>/crossgenlibs.pass.txt)'
65     echo '  --libsCrossgenSkipOutputPath=<path>  : Create crossgen skip report at the specifed path (default: <test root dir>/crossgenlibs.skip.txt)'
66     echo '  --libsCrossgenFailOutputPath=<path>  : Create crossgen fail report at the specifed path (default: <test root dir>/crossgenlibs.fail.txt)'
67     echo ''
68     echo 'Temporary:'
69     echo '  --crossgen2options               : Options passed to crossgen2 (default: --jitpath /opt/usr/coreclr-tc/coreroot/libclrjit.so --targetarch armel)'
70     echo '  --crossgen2-libs                 : Use crossgen2 for compilation of system libs.'
71     echo '  --crossgen2-tests                : Use crossgen2 for compilation of tests.'
72     echo '  --crossgen-spc-first             : Crossgen System.Private.CoreLib.dll before other dlls.'
73 }
74
75 function print_results {
76     echo ""
77     echo "======================="
78     echo "     Test Results"
79     echo "======================="
80     echo "# Overlay          : $coreOverlayDir"
81     echo "# Tests Discovered : $countTotalTests"
82     echo "# Passed           : $countPassedTests"
83     echo "# Failed           : $countFailedTests"
84     echo "# Skipped          : $countSkippedTests"
85     echo "======================="
86 }
87
88 # Initialize counters for bookkeeping.
89 countTotalTests=0
90 countPassedTests=0
91 countFailedTests=0
92 countSkippedTests=0
93
94 # Variables for xUnit-style XML output. XML format: https://xunit.github.io/docs/format-xml-v2.html
95 xunitOutputPath=
96 xunitTestOutputPath=
97
98 # Variables for text file output. These can be passed back to runtest.sh using the "--playlist" argument
99 # to rerun specific tests.
100 testsPassOutputPath=
101 testsFailOutputPath=
102 testsSkipOutputPath=
103 libsCrossgenPassOutputPath=
104 libsCrossgenFailOutputPath=
105 libsCrossgenSkipOutputPath=
106
107 function xunit_output_begin {
108     if [ -z "$xunitOutputPath" ]; then
109         xunitOutputPath=$testRootDir/coreclrtests.xml
110     fi
111     xunitTestOutputPath=${xunitOutputPath}.test
112     if [ -f "$xunitOutputPath" ]; then
113         rm -f -r "$xunitOutputPath"
114     fi
115     if [ -f "$xunitTestOutputPath" ]; then
116         rm -f -r "$xunitTestOutputPath"
117     fi
118 }
119
120 function xunit_output_add_test {
121     # <assemblies>
122     #   <assembly>
123     #     <collection>
124     #       <test .../> <!-- Write this element here -->
125
126     local scriptFilePath=$1
127     local outputFilePath=$2
128     local testResult=$3 # Pass, Fail, or Skip
129     local testScriptExitCode=$4
130     local testRunningTime=$5
131
132     local testPath=${scriptFilePath%.sh} # Remove trailing ".sh"
133     local testDir=$(dirname "$testPath")
134     local testName=$(basename "$testPath")
135
136     # Replace '/' with '.'
137     testPath=$(echo "$testPath" | tr / .)
138     testDir=$(echo "$testDir" | tr / .)
139
140     local line
141
142     line="      "
143     line="${line}<test"
144     line="${line} name=\"${testPath}\""
145     line="${line} type=\"${testDir}\""
146     line="${line} method=\"${testName}\""
147     line="${line} result=\"${testResult}\""
148     if [ -n "$testRunningTime" ] && [ "$testResult" != "Skip" ]; then
149         line="${line} time=\"${testRunningTime}\""
150     fi
151
152     if [ "$testResult" == "Pass" ]; then
153         line="${line}/>"
154         echo "$line" >>"$xunitTestOutputPath"
155         return
156     fi
157
158     line="${line}>"
159     echo "$line" >>"$xunitTestOutputPath"
160
161     line="        "
162     if [ "$testResult" == "Skip" ]; then
163         line="${line}<reason><![CDATA[$(cat "$outputFilePath")]]></reason>"
164         echo "$line" >>"$xunitTestOutputPath"
165     else
166         line="${line}<failure exception-type=\"Exit code: ${testScriptExitCode}\">"
167         echo "$line" >>"$xunitTestOutputPath"
168
169         line="          "
170         line="${line}<message>"
171         echo "$line" >>"$xunitTestOutputPath"
172         line="            "
173         line="${line}<![CDATA["
174         echo "$line" >>"$xunitTestOutputPath"
175         cat "$outputFilePath" >>"$xunitTestOutputPath"
176         line="            "
177         line="${line}]]>"
178         echo "$line" >>"$xunitTestOutputPath"
179         line="          "
180         line="${line}</message>"
181         echo "$line" >>"$xunitTestOutputPath"
182
183         line="        "
184         line="${line}</failure>"
185         echo "$line" >>"$xunitTestOutputPath"
186     fi
187
188     line="      "
189     line="${line}</test>"
190     echo "$line" >>"$xunitTestOutputPath"
191 }
192
193 function xunit_output_end {
194     local errorSource=$1
195     local errorMessage=$2
196
197     local errorCount
198     if [ -z "$errorSource" ]; then
199         ((errorCount = 0))
200     else
201         ((errorCount = 1))
202     fi
203
204     echo '<?xml version="1.0" encoding="utf-8"?>' >>"$xunitOutputPath"
205     echo '<assemblies>' >>"$xunitOutputPath"
206
207     local line
208
209     # <assembly ...>
210     line="  "
211     line="${line}<assembly"
212     line="${line} name=\"CoreClrTestAssembly\""
213     line="${line} total=\"${countTotalTests}\""
214     line="${line} passed=\"${countPassedTests}\""
215     line="${line} failed=\"${countFailedTests}\""
216     line="${line} skipped=\"${countSkippedTests}\""
217     line="${line} errors=\"${errorCount}\""
218     line="${line}>"
219     echo "$line" >>"$xunitOutputPath"
220
221     # <collection ...>
222     line="    "
223     line="${line}<collection"
224     line="${line} name=\"CoreClrTestCollection\""
225     line="${line} total=\"${countTotalTests}\""
226     line="${line} passed=\"${countPassedTests}\""
227     line="${line} failed=\"${countFailedTests}\""
228     line="${line} skipped=\"${countSkippedTests}\""
229     line="${line}>"
230     echo "$line" >>"$xunitOutputPath"
231
232     # <test .../> <test .../> ...
233     if [ -f "$xunitTestOutputPath" ]; then
234         cat "$xunitTestOutputPath" >>"$xunitOutputPath"
235         rm -f "$xunitTestOutputPath"
236     fi
237
238     # </collection>
239     line="    "
240     line="${line}</collection>"
241     echo "$line" >>"$xunitOutputPath"
242
243     if [ -n "$errorSource" ]; then
244         # <errors>
245         line="    "
246         line="${line}<errors>"
247         echo "$line" >>"$xunitOutputPath"
248
249         # <error ...>
250         line="      "
251         line="${line}<error"
252         line="${line} type=\"TestHarnessError\""
253         line="${line} name=\"${errorSource}\""
254         line="${line}>"
255         echo "$line" >>"$xunitOutputPath"
256
257         # <failure .../>
258         line="        "
259         line="${line}<failure>${errorMessage}</failure>"
260         echo "$line" >>"$xunitOutputPath"
261
262         # </error>
263         line="      "
264         line="${line}</error>"
265         echo "$line" >>"$xunitOutputPath"
266
267         # </errors>
268         line="    "
269         line="${line}</errors>"
270         echo "$line" >>"$xunitOutputPath"
271     fi
272
273     # </assembly>
274     line="  "
275     line="${line}</assembly>"
276     echo "$line" >>"$xunitOutputPath"
277
278     # </assemblies>
279     echo '</assemblies>' >>"$xunitOutputPath"
280 }
281
282 function text_file_output_begin {
283     if [ -z "$testsPassOutputPath" ]; then
284         testsPassOutputPath=$testRootDir/coreclrtests.pass.txt
285     fi
286     if [ -f "$testsPassOutputPath" ]; then
287         rm -f "$testsPassOutputPath"
288     fi
289     if [ -z "$testsFailOutputPath" ]; then
290         testsFailOutputPath=$testRootDir/coreclrtests.fail.txt
291     fi
292     if [ -f "$testsFailOutputPath" ]; then
293         rm -f "$testsFailOutputPath"
294     fi
295     if [ -z "$testsSkipOutputPath" ]; then
296         testsSkipOutputPath=$testRootDir/coreclrtests.skip.txt
297     fi
298     if [ -f "$testsSkipOutputPath" ]; then
299         rm -f "$testsSkipOutputPath"
300     fi
301
302     if [ -z "$libsCrossgenPassOutputPath" ]; then
303         libsCrossgenPassOutputPath=$testRootDir/crossgenlibs.pass.txt
304     fi
305     if [ -f "$libsCrossgenPassOutputPath" ]; then
306         rm -f "$libsCrossgenPassOutputPath"
307     fi
308     if [ -z "$libsCrossgenFailOutputPath" ]; then
309         libsCrossgenFailOutputPath=$testRootDir/crossgenlibs.fail.txt
310     fi
311     if [ -f "$libsCrossgenFailOutputPath" ]; then
312         rm -f "$libsCrossgenFailOutputPath"
313     fi
314     if [ -z "$libsCrossgenSkipOutputPath" ]; then
315         libsCrossgenSkipOutputPath=$testRootDir/crossgenlibs.skip.txt
316     fi
317     if [ -f "$libsCrossgenSkipOutputPath" ]; then
318         rm -f "$libsCrossgenSkipOutputPath"
319     fi
320 }
321
322 function text_file_output_add_test {
323     local scriptFilePath=$1
324     local testResult=$2 # Pass, Fail, or Skip
325
326     if [ "$testResult" == "Pass" ]; then
327         echo "$scriptFilePath" >>"$testsPassOutputPath"
328     elif [ "$testResult" == "Skip" ]; then
329         echo "$scriptFilePath" >>"$testsSkipOutputPath"
330     else
331         echo "$scriptFilePath" >>"$testsFailOutputPath"
332     fi
333 }
334
335 function exit_with_error {
336     local errorSource=$1
337     local errorMessage=$2
338     local printUsage=$3
339
340     if [ -z "$printUsage" ]; then
341         ((printUsage = 0))
342     fi
343
344     echo "$errorMessage"
345     xunit_output_end "$errorSource" "$errorMessage"
346     if ((printUsage != 0)); then
347         print_usage
348     fi
349     exit $EXIT_CODE_EXCEPTION
350 }
351
352 # Handle Ctrl-C. We will stop execution and print the results that
353 # we gathered so far.
354 function handle_ctrl_c {
355     local errorSource='handle_ctrl_c'
356
357     echo ""
358     echo "*** Stopping... ***"
359     print_results
360     exit_with_error "$errorSource" "Test run aborted by Ctrl+C."
361 }
362
363 # Register the Ctrl-C handler
364 trap handle_ctrl_c INT
365
366 # Variables for unsupported and failing tests
367 declare -a unsupportedCrossGenLibs
368 declare -a unsupportedCrossGenTests
369 declare -a unsupportedTests
370 declare -a unsupportedGCStressTests
371
372 # Get an array of items by reading the specified file line by line.
373 function read_array {
374     local theArray=()
375
376     if [ ! -f "$1" ]; then
377         return
378     fi
379
380     # bash in Mac OS X doesn't support 'readarray', so using alternate way instead.
381     # readarray -t theArray < "$1"
382     # Any line that starts with '#' is ignored.
383     while IFS='' read -r line || [ -n "$line" ]; do
384         if [[ $line != "#"* ]]; then
385             theArray[${#theArray[@]}]=$line
386         fi
387     done < "$1"
388     echo ${theArray[@]}
389 }
390
391 function load_unsupported_tests {
392     # Load the list of tests that are not supported on this platform
393     unsupportedTests=($(read_array "$(dirname "$0")/unsupportedTests.txt"))
394     # Load the list of libs that are not supported for crossgen on this platform
395     unsupportedCrossGenLibs=($(read_array "$(dirname "$0")/unsupportedCrossgenLibs.txt"))
396     # Load the list of test that are not supported for crossgen on this platform
397     unsupportedCrossGenTests=($(read_array "$(dirname "$0")/unsupportedCrossgenTests.txt"))
398     # Load the list of tests that are not supported on this platform in GCStress mode
399     unsupportedGCStressTests=($(read_array "$(dirname "$0")/unsupportedGCStressTests.txt"))
400 }
401
402 function is_unsupported_crossgen_lib {
403     for unsupported in "${unsupportedCrossGenLibs[@]}"; do
404         if [ "$1" == "$unsupported" ]; then
405             return 0
406         fi
407     done
408     return 1
409 }
410
411 function is_unsupported_test {
412     for unsupported in "${unsupportedTests[@]}"; do
413         if [ "$1" == "$unsupported" ]; then
414             return 0
415         fi
416     done
417
418     if [ $doCrossgenTests == 1 ] || [ $doCrossgen2Tests == 1 ]; then
419         for unsupported in "${unsupportedCrossGenTests[@]}"; do
420             if [ "$1" == "$unsupported" ]; then
421                 return 0
422             fi
423         done
424     fi
425
426     if [[ ! -z "$COMPlus_GCStress" ]] && [[ "$COMPlus_GCStress" -ne "0" ]]; then
427         for unsupported in "${unsupportedGCStressTests[@]}"; do
428             if [ "$1" == "$unsupported" ]; then
429                 return 0
430             fi
431         done
432     fi
433
434     return 1
435 }
436
437 function crossgen_file {
438     local overlayDir=$1
439     local dll_path=$2
440     local name=$3
441
442     # ni.dll are created as ni.dll.tmp in order to not interfere
443     # with crossgen2 at first, then moved to ni.dll all at once at the end
444     # (logic is similar to https://github.com/dotnet/runtime/pull/57341/)
445     local tmp_ni_path=$(echo $dll_path | sed 's/.dll$/.ni.dll.tmp/')
446
447     echo "Precompiling $dll_path to $tmp_ni_path"
448
449     if [ $doCrossgenLibs == 1 ]; then
450         ${overlayDir}/crossgen /in $dll_path /out $tmp_ni_path $CrossGenOptions /p ${overlayDir}:${overlayDir}/crossgen2 &>$dll_path.out
451     elif [ $doCrossgen2Libs == 1 ]; then
452         ${overlayDir}/corerun ${overlayDir}/crossgen2/crossgen2.dll $CrossGen2Options -o:$tmp_ni_path $dll_path -r:${overlayDir}/*.dll -r:${overlayDir}/crossgen2/*.dll &>$dll_path.out
453     fi
454
455     local exitCode=$?
456     if [[ $exitCode != 0 ]]; then
457         echo Crossgen fail for $dll_path.
458         echo "$dll_path" >> "$libsCrossgenFailOutputPath"
459
460         cat $dll_path.out
461
462         if [ $CrossGenAllowFail == 0 ]; then
463             exit $exitCode
464         fi
465     else
466         echo Crossgen success $dll_path.
467         echo "$dll_path" >> "$libsCrossgenPassOutputPath"
468
469         if [[ "${name}" == "System.Private.CoreLib.dll" ]]; then
470             # SPC.ni.dll can be used directly without ni.dll.tmp
471             # (because SPC doesn't use any dependencies)
472             mv $dll_path $dll_path.bak
473             mv $tmp_ni_path $dll_path
474         fi
475     fi
476
477     rm $dll_path.out
478 }
479
480 function precompile_overlay_assemblies {
481     local overlayDir=$CORE_ROOT
482
483     if [ $doCopyNetcoreToCoreroot == 1 ]; then
484         echo "Copying netcore ($netcoreDir) to coreroot ($overlayDir)"
485         cp -r $netcoreDir/* $overlayDir
486     fi
487
488     echo Cleanup old ni.dll
489     for file in `find $testRootDir -name "*.ni.*"`; do
490         rm $file
491     done
492
493     test -f $overlayDir/System.Private.CoreLib.dll.Backup && mv $overlayDir/System.Private.CoreLib.dll.Backup $overlayDir/System.Private.CoreLib.dll
494     test -f $overlayDir/System.Private.CoreLib.dll.bak && mv $overlayDir/System.Private.CoreLib.dll.bak $overlayDir/System.Private.CoreLib.dll
495
496     if [ $doCrossgenLibs == 0 ] && [ $doCrossgen2Libs == 0 ]; then
497         echo Skipping crossgen of libs.
498         return 0
499     else
500         echo Precompiling libs
501     fi
502
503     if [ $doCrossgenSPCFirst == 1 ]; then
504         local dll_path=$overlayDir/System.Private.CoreLib.dll
505         local name=$(basename $dll_path)
506         crossgen_file $overlayDir $dll_path $name
507     fi
508
509     if [ -z "$crossgenLibs" ]; then
510         # No libs to crossgen were specified, so crossgen everything in the overlay
511         filesToPrecompile=$(find -L $overlayDir -iname \*.dll -not -iname \*.ni.dll -type f)
512     else
513         # Otherwise, compile only specified libs
514         filesToPrecompile=$(echo "${crossgenLibs[@]}")
515     fi
516
517     for fileToPrecompile in ${filesToPrecompile}
518     do
519         local dll_path=${fileToPrecompile}
520         local name=$(basename $dll_path)
521
522         if [[ "$name" == "System.Private.CoreLib.dll" && "$doCrossgenSPCFirst" == "1" ]]; then
523             continue
524         fi
525
526         if is_unsupported_crossgen_lib "${name}"; then
527             echo Skipping crossgen for $dll_path.
528             echo "$dll_path" >> "$libsCrossgenSkipOutputPath"
529             continue
530         fi
531
532         crossgen_file $overlayDir $dll_path $name
533     done
534
535     # Copy ni.dll all at once
536     for tmp_ni_path in `find $overlayDir -name "*.ni.dll.tmp"`; do
537         local ni_dll_path=$(echo $tmp_ni_path | sed 's/.ni.dll.tmp$/.ni.dll/')
538
539         echo "Moving $tmp_ni_path to $ni_dll_path"
540         mv $tmp_ni_path $ni_dll_path
541     done
542 }
543
544 function skip_unsupported_test {
545     # This function runs in a background process. It should not echo anything, and should not use global variables. This
546     # function is analogous to run_test, and causes the test to be skipped with the message below.
547
548     local scriptFilePath=$1
549     local outputFilePath=$2
550
551     echo "Not supported on this platform or in this mode." >"$outputFilePath"
552     return 2 # skip the test
553 }
554
555 function run_test {
556     # This function runs in a background process. It should not echo anything, and should not use global variables.
557
558     local scriptFilePath=$1
559     local outputFilePath=$2
560
561     # Switch to directory where the script is
562     cd "$(dirname "$scriptFilePath")"
563
564     local scriptFileName=$(basename "$scriptFilePath")
565     local outputFileName=$(basename "$outputFilePath")
566
567     echo "" > "$outputFileName" 2>&1
568
569     if [ $useMulticoreJit == 1 ]; then
570       export COMPlus_MultiCoreJitProfile="`pwd`/mcj_profile.dat"
571       export COMPlus_MultiCoreJitMinNumCpus="1"
572       echo "MULTICOREJIT: 1st launch" >> "$outputFileName" 2>&1
573
574       "./$scriptFileName" >> "$outputFileName" 2>&1
575       local testScriptExitCode=$?
576
577       if [ $testScriptExitCode == 0 ]; then
578         if [ $useMulticoreJitNoProfileGather == 1 ]; then
579           export COMPlus_MultiCoreJitNoProfileGather="1"
580         fi
581
582         echo "" >> "$outputFileName" 2>&1
583         echo "MULTICOREJIT: 2nd launch" >> "$outputFileName" 2>&1
584       else
585         return $testScriptExitCode
586       fi
587     fi
588
589     if [ $doCrossgenTests == 1 ]; then
590       export RunCrossGen=1
591     fi
592
593     if [ $doCrossgen2Tests == 1 ]; then
594       export RunCrossGen2=1
595     fi
596
597     "./$scriptFileName" >> "$outputFileName" 2>&1
598     local testScriptExitCode=$?
599
600     return $testScriptExitCode
601 }
602
603 # Variables for running tests in the background
604 ((maxProcesses = 1)) # long tests delay process creation, use a few more processors
605
606 ((processCount = 0))
607 declare -a scriptFilePaths
608 declare -a outputFilePaths
609 declare -a processIds
610 declare -a testStartTimes
611 waitProcessIndex=
612 pidNone=0
613
614 function waitany {
615     local pid
616     local exitcode
617     while true; do
618         for (( i=0; i<$maxProcesses; i++ )); do
619             pid=${processIds[$i]}
620             if [ -z "$pid" ] || [ "$pid" == "$pidNone" ]; then
621                 continue
622             fi
623             if ! kill -0 $pid 2>/dev/null; then
624                 wait $pid
625                 exitcode=$?
626                 waitProcessIndex=$i
627                 processIds[$i]=$pidNone
628                 return $exitcode
629             fi
630         done
631         sleep 0.1
632     done
633 }
634
635 function get_available_process_index {
636     local pid
637     local i=0
638     for (( i=0; i<$maxProcesses; i++ )); do
639         pid=${processIds[$i]}
640         if [ -z "$pid" ] || [ "$pid" == "$pidNone" ]; then
641             break
642         fi
643     done
644     echo $i
645 }
646
647 function finish_test {
648     waitany
649     local testScriptExitCode=$?
650     local finishedProcessIndex=$waitProcessIndex
651     ((--processCount))
652
653     local scriptFilePath=${scriptFilePaths[$finishedProcessIndex]}
654     local outputFilePath=${outputFilePaths[$finishedProcessIndex]}
655     local scriptFileName=$(basename "$scriptFilePath")
656
657     local testEndTime=
658     local testRunningTime=
659     local header=
660
661     if ((verbose == 1)); then
662         header=$(printf "[%4d]" $countTotalTests)
663     fi
664
665     testEndTime=$(date +%s)
666     testRunningTime=$(( $testEndTime - ${testStartTimes[$finishedProcessIndex]} ))
667     header=$header$(printf "[%4ds]" $testRunningTime)
668
669     if [ $useMulticoreJit == 1 ]; then
670       header="$header[mcj]"
671     fi
672
673     local testResult
674     case $testScriptExitCode in
675         0)
676             let countPassedTests++
677             testResult='Pass'
678             if ((verbose == 1)); then
679                 echo "PASSED   - ${header}${scriptFilePath}"
680             else
681                 echo "         - ${header}${scriptFilePath}"
682             fi
683             ;;
684         2)
685             let countSkippedTests++
686             testResult='Skip'
687             echo "SKIPPED  - ${header}${scriptFilePath}"
688             ;;
689         *)
690             let countFailedTests++
691             testResult='Fail'
692             echo "FAILED   - ${header}${scriptFilePath}"
693             ;;
694     esac
695     let countTotalTests++
696
697     if ((verbose == 1 || testScriptExitCode != 0)); then
698         while IFS='' read -r line || [ -n "$line" ]; do
699             echo "               $line"
700         done <"$outputFilePath"
701     fi
702
703     xunit_output_add_test "$scriptFilePath" "$outputFilePath" "$testResult" "$testScriptExitCode" "$testRunningTime"
704     text_file_output_add_test "$scriptFilePath" "$testResult"
705 }
706
707 function finish_remaining_tests {
708     # Finish the remaining tests in the order in which they were started
709     while ((processCount > 0)); do
710         finish_test
711     done
712 }
713
714 function prep_test {
715     local scriptFilePath=$1
716     local scriptFileDir=$(dirname "$scriptFilePath")
717
718     test "$verbose" == 1 && echo "Preparing $scriptFilePath"
719
720     # Add executable file mode bit if needed
721     chmod +x "$scriptFilePath"
722
723     # remove any Locks
724     rm -rf $scriptFileDir/lock
725
726     # remove mcj profiles
727     rm -rf $scriptFileDir/mcj_profile.dat*
728 }
729
730 function start_test {
731     local nextProcessIndex=$(get_available_process_index)
732     local scriptFilePath=$1
733
734     if ((nextProcessIndex == maxProcesses)); then
735         finish_test
736         nextProcessIndex=$(get_available_process_index)
737     fi
738
739     scriptFilePaths[$nextProcessIndex]=$scriptFilePath
740     local scriptFileName=$(basename "$scriptFilePath")
741     local outputFilePath=$(dirname "$scriptFilePath")/${scriptFileName}.out
742     outputFilePaths[$nextProcessIndex]=$outputFilePath
743
744     testStartTimes[$nextProcessIndex]=$(date +%s)
745
746     test "$verbose" == 1 && echo "Starting $scriptFilePath"
747     if is_unsupported_test "$scriptFilePath"; then
748         skip_unsupported_test "$scriptFilePath" "$outputFilePath" &
749     else
750         run_test "$scriptFilePath" "$outputFilePath" &
751     fi
752     processIds[$nextProcessIndex]=$!
753
754     ((++processCount))
755 }
756
757 # Get a list of directories in which to scan for tests by reading the
758 # specified file line by line.
759 function set_test_directories {
760     local errorSource='set_test_directories'
761
762     local listFileName=$1
763
764     if [ ! -f "$listFileName" ]
765     then
766         exit_with_error "$errorSource" "Test directories file not found at $listFileName"
767     fi
768     testDirectories=($(read_array "$listFileName"))
769 }
770
771 function run_tests_in_directory {
772     local testDir=$1
773     local skipScriptsInDir=$2
774
775     local minDepth="1"
776
777     # Need to skip scripts in testDir since they are not tests
778     if [[ "$skipScriptsInDir" == "1" ]]; then
779         minDepth="2"
780     fi
781
782     # Recursively search through directories for .sh files to prepare them.
783     # Note: This needs to occur before any test runs as some of the .sh files
784     # depend on other .sh files
785     echo "Preparing tests..."
786     for scriptFilePath in $(find "$testDir" -mindepth ${minDepth} -type f -iname '*.sh' | sort)
787     do
788         prep_test "${scriptFilePath:2}"
789     done
790     echo "The tests have been prepared"
791     # Recursively search through directories for .sh files to run.
792     for scriptFilePath in $(find "$testDir" -mindepth ${minDepth} -type f -iname '*.sh' | sort)
793     do
794         start_test "${scriptFilePath:2}"
795     done
796 }
797
798 # Exit code constants
799 readonly EXIT_CODE_SUCCESS=0       # Script ran normally.
800 readonly EXIT_CODE_EXCEPTION=1     # Script exited because something exceptional happened (e.g. bad arguments, Ctrl-C interrupt).
801 readonly EXIT_CODE_TEST_FAILURE=2  # Script completed successfully, but one or more tests failed.
802
803 # Argument variables
804 testRootDir="/opt/usr/coreclr-tc/"
805 coreOverlayDir="/opt/usr/coreclr-tc/coreroot/"
806 doCopyNetcoreToCoreroot=0
807 netcoreDir="/usr/share/dotnet.tizen/netcoreapp"
808 testEnv=
809
810 # Handle arguments
811 verbose=0
812 doCrossgenLibs=0
813 doCrossgen2Libs=0
814 CrossGenAllowFail=0
815 doCrossgenTests=0
816 doCrossgen2Tests=0
817 doCrossgenSPCFirst=0
818
819 useMulticoreJit=0
820 useMulticoreJitNoProfileGather=0
821
822 crossgenOpts=""
823 crossgen2Opts=""
824
825 export COMPlus_MultiCoreJitProfile=
826 export COMPlus_MultiCoreJitMinNumCpus=
827 export COMPlus_MultiCoreJitNoProfileGather=
828 export RunCrossGen=
829 export RunCrossGen2=
830 export COMPlus_JitStress=
831 export COMPlus_JitStressRegs=
832 export COMPlus_GCStress=
833
834 for i in "$@"
835 do
836     case $i in
837         -h|--help)
838             print_usage
839             exit $EXIT_CODE_SUCCESS
840             ;;
841         -v|--verbose)
842             verbose=1
843             ;;
844         --arch=*)
845             ARCH=${i#*=}
846             ;;
847         --crossgen-libs)
848             doCrossgenLibs=1
849             ;;
850         --crossgen2-libs)
851             doCrossgen2Libs=1
852             ;;
853         --crossgen-tests)
854             doCrossgenTests=1
855             ;;
856         --crossgen2-tests)
857             doCrossgen2Tests=1
858             ;;
859         --crossgen-spc-first)
860             doCrossgenSPCFirst=1
861             ;;
862         --crossgenoptions=*)
863             crossgenOpts="$crossgenOpts ${i#*=}"
864             ;;
865         --crossgen2options=*)
866             crossgen2Opts="$crossgen2Opts ${i#*=}"
867             ;;
868         --allow-crossgen-fails)
869             CrossGenAllowFail=1
870             ;;
871         --crossgen-lib=*)
872             crossgenLibs[${#crossgenLibs[@]}]=${i#*=}
873             ;;
874         --jitstress=*)
875             export COMPlus_JitStress=${i#*=}
876             ;;
877         --jitstressregs=*)
878             export COMPlus_JitStressRegs=${i#*=}
879             ;;
880         --mcj)
881             useMulticoreJit=1
882             ;;
883         --mcj-no-profile-gather)
884             useMulticoreJitNoProfileGather=1
885             ;;
886         --testRootDir=*)
887             testRootDir=${i#*=}
888             ;;
889         --coreOverlayDir=*)
890             coreOverlayDir=${i#*=}
891             ;;
892         --netcoreDir=*)
893             netcoreDir=${i#*=}
894             ;;
895         --copy-netcore-to-coreroot)
896             doCopyNetcoreToCoreroot=1
897             ;;
898         --testDir=*)
899             testDirectories[${#testDirectories[@]}]=${i#*=}
900             ;;
901         --testDirFile=*)
902             set_test_directories "${i#*=}"
903             ;;
904         --num-procs=*)
905             ((maxProcesses = ${i#*=}))
906             ;;
907         --test-env=*)
908             testEnv=${i#*=}
909             ;;
910         --gcstresslevel=*)
911             export COMPlus_GCStress=${i#*=}
912             ;;
913         --xunitOutputPath=*)
914             xunitOutputPath=${i#*=}
915             ;;
916         --testsPassOutputPath=*)
917             testsPassOutputPath=${i#*=}
918             ;;
919         --testsSkipOutputPath=*)
920             testsSkipOutputPath=${i#*=}
921             ;;
922         --testsFailOutputPath=*)
923             testsFailOutputPath=${i#*=}
924             ;;
925         --libsCrossgenPassOutputPath=*)
926             libsCrossgenPassOutputPath=${i#*=}
927             ;;
928         --libsCrossgenSkipOutputPath=*)
929             libsCrossgenSkipOutputPath=${i#*=}
930             ;;
931         --libsCrossgenFailOutputPath=*)
932             libsCrossgenFailOutputPath=${i#*=}
933             ;;
934         *)
935             echo "Unknown switch: $i"
936             print_usage
937             exit $EXIT_CODE_SUCCESS
938             ;;
939     esac
940 done
941
942 if [ -z "$ARCH" ]; then
943     echo "--arch is required."
944     print_usage
945     exit $EXIT_CODE_EXCEPTION
946 fi
947 if [ "$ARCH" != "arm" ] && [ "$ARCH" != "armel" ] && [ "$ARCH" != "arm64" ] && [ "$ARCH" != "x64" ] && [ "$ARCH" != "x86" ] && [ "$ARCH" != "riscv64" ]; then
948     echo "Unsupported value for --arch: $ARCH"
949     print_usage
950     exit $EXIT_CODE_EXCEPTION
951 fi
952
953 if [ -z "$testRootDir" ]; then
954     echo "--testRootDir is required."
955     print_usage
956     exit $EXIT_CODE_EXCEPTION
957 fi
958 if [ ! -d "$testRootDir" ]; then
959     echo "Directory specified by --testRootDir does not exist: $testRootDir"
960     exit $EXIT_CODE_EXCEPTION
961 fi
962
963 if [ -z "$coreOverlayDir" ]; then
964     echo "--coreOverlayDir is required."
965     print_usage
966     exit $EXIT_CODE_EXCEPTION
967 fi
968 if [ ! -d "$coreOverlayDir" ]; then
969     echo "Directory specified by --coreOverlayDir does not exist: $coreOverlayDir"
970     exit $EXIT_CODE_EXCEPTION
971 fi
972
973 export CORE_ROOT="$coreOverlayDir"
974
975 # Default values for crossgen2 options
976 if [ "$crossgen2Opts" == "" ]; then
977     crossgen2Opts="--jitpath $coreOverlayDir/libclrjit.so --targetarch $ARCH"
978 fi
979
980 export CrossGenOptions="$crossgenOpts"
981 export CrossGen2Options="$crossgen2Opts"
982 export CrossGen2OptionsR2RTest="--crossgen2-jitpath $coreOverlayDir/libclrjit.so --target-arch $ARCH"
983
984 echo "! Make sure CLR/FX are copied to $coreOverlayDir !"
985
986 echo "Running on CPU-$ARCH"
987
988 xunit_output_begin
989 text_file_output_begin
990 load_unsupported_tests
991 precompile_overlay_assemblies
992
993 export __TestEnv=$testEnv
994 cd "$testRootDir"
995
996 time_start=$(date +"%s")
997 if [ -z "$testDirectories" ]
998 then
999     # No test directories were specified, so run everything in the current
1000     # directory and its subdirectories.
1001     run_tests_in_directory "." 1
1002 else
1003     # Otherwise, run all the tests in each specified test directory.
1004     for testDir in "${testDirectories[@]}"
1005     do
1006         if [ ! -d "$testDir" ]; then
1007             echo "Test directory does not exist: $testDir"
1008         else
1009             run_tests_in_directory "./$testDir" 0
1010         fi
1011     done
1012 fi
1013
1014 finish_remaining_tests
1015 print_results
1016
1017 time_end=$(date +"%s")
1018 time_diff=$(($time_end-$time_start))
1019 echo "$(($time_diff / 60)) minutes and $(($time_diff % 60)) seconds taken to run CoreCLR tests."
1020
1021 xunit_output_end
1022
1023 if ((countFailedTests > 0)); then
1024     exit $EXIT_CODE_TEST_FAILURE
1025 fi
1026
1027 exit $EXIT_CODE_SUCCESS