Skip to content

Commit

Permalink
Libraries testing (dotnet#178)
Browse files Browse the repository at this point in the history
* Add Libraries Testing framework package as inline

The existing package Microsoft.DotNet.CoreFxTesting lived in Arcade
because of no infrastructure being available to compile local tasks in
the repository. As the runtime repository now offers that we can inline
the testing framework.

* Hardcode configuration for installer.tasks

* Update ReportGenerator global tool version

* Add vstest support

* Update binary serialization blobs
  • Loading branch information
ViktorHofer committed Nov 21, 2019
1 parent 5e5a0d4 commit 1d5de15
Show file tree
Hide file tree
Showing 43 changed files with 1,228 additions and 125 deletions.
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
]
},
"dotnet-reportgenerator-globaltool": {
"version": "4.3.0",
"version": "4.3.6",
"commands": [
"reportgenerator"
]
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ cross/android-rootfs/
#NUNIT
*.VisualState.xml
TestResult.xml
testResults.xml

# Build Results of an ATL Project
[Dd]ebugPS/
Expand Down
15 changes: 10 additions & 5 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,23 @@
<Import Project="Sdk.props" Sdk="Microsoft.DotNet.Arcade.Sdk" Condition="'$(SkipImportArcadeSdkFromRoot)' != 'true'" />

<!-- Common paths -->
<PropertyGroup>
<!-- Set these properties early enough for libraries as they import the Arcade SDK not early enough. -->

<!-- Set these properties early enough for libraries as they import the Arcade SDK not early enough. -->
<PropertyGroup Condition="'$(SkipImportArcadeSdkFromRoot)' == 'true'">
<RepoRoot>$(MSBuildThisFileDirectory)</RepoRoot>
<RepositoryEngineeringDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'eng'))</RepositoryEngineeringDir>
<ArtifactsDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts'))</ArtifactsDir>
<ArtifactsBinDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'bin'))</ArtifactsBinDir>
</PropertyGroup>

<PropertyGroup>
<RepoToolsLocalDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'tools-local'))</RepoToolsLocalDir>
<RepoTasksDir>$([MSBuild]::NormalizeDirectory('$(RepoToolsLocalDir)', 'tasks'))</RepoTasksDir>

<!-- Installer specific, required during restore. -->
<InstallerTasksOutputPath>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'installer.tasks', '$(Configuration)'))</InstallerTasksOutputPath>
<InstallerTasksAssemblyPath Condition="'$(MSBuildRuntimeType)' == 'Core'">$([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'netstandard2.0', 'installer.tasks.dll'))</InstallerTasksAssemblyPath>
<InstallerTasksAssemblyPath Condition="'$(MSBuildRuntimeType)' != 'Core'">$([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'net46', 'installer.tasks.dll'))</InstallerTasksAssemblyPath>
<InstallerTasksOutputPath>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'installer.tasks'))</InstallerTasksOutputPath>
<InstallerTasksAssemblyPath Condition="'$(MSBuildRuntimeType)' == 'Core'">$([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'Debug', 'netstandard2.0', 'installer.tasks.dll'))</InstallerTasksAssemblyPath>
<InstallerTasksAssemblyPath Condition="'$(MSBuildRuntimeType)' != 'Core'">$([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'Debug', 'net46', 'installer.tasks.dll'))</InstallerTasksAssemblyPath>
<HostMachineInfoProps>$(ArtifactsObjDir)HostMachineInfo.props</HostMachineInfoProps>

<LibrariesProjectRoot>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'libraries'))</LibrariesProjectRoot>
Expand Down
1 change: 1 addition & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
-->
<!-- TEST_RESTORE_SOURCES_INSERTION_LINE -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-tools" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-tools/nuget/v3/index.json" />
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
<add key="dotnet5-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json" />
<add key="dotnet-core" value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" />
Expand Down
2 changes: 1 addition & 1 deletion docs/libraries/building/code-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The results for this one library will then show up in the aforementioned index.h

And then once the run completes:

$(TestPath)\report\index.htm
$(OutDir)\report\index.htm

**Note:** If you only want to measure the coverage of your local changes (that haven't been pushed to git), run:

Expand Down
2 changes: 1 addition & 1 deletion docs/libraries/project-docs/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ cd src\System.Collections.Immutable\tests
dotnet msbuild /t:BuildAndTest /p:Coverage=true
```
If coverage succeeds, the individual report can be found at `$(TestPath)\report\index.htm`.
If coverage succeeds, the individual report can be found at `$(OutDir)\report\index.htm`.
Code coverage reports from the continuous integration system are available from the links on the front page of the corefx repo.
Expand Down
3 changes: 2 additions & 1 deletion eng/Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
</ItemGroup>

<MSBuild Projects="@(RepoTaskProjects)"
Properties="Configuration=Debug"
Targets="Restore;Build"/>

<WriteLinesToFile File="$(RepoTasksOutputFile)"
Expand All @@ -89,7 +90,7 @@
<Target Name="GetRepoTasksSrc">
<PropertyGroup>
<RepoTasksDir>$(RepoTasksDir)</RepoTasksDir>
<RepoTasksOutputFile>$(ArtifactsObjDir)runtime.tasks\$(Configuration)\build-semaphore.txt</RepoTasksOutputFile>
<RepoTasksOutputFile>$(ArtifactsObjDir)runtime.tasks\Debug\build-semaphore.txt</RepoTasksOutputFile>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 4 additions & 0 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,9 @@
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>d0bb63d2ec7060714e63ee4082fac48f2e57f3e2</Sha>
</Dependency>
<Dependency Name="Microsoft.NET.Test.Sdk" Version="16.4.0">
<Uri>https://github.com/Microsoft/vstest</Uri>
<Sha>ca987de449d17284f8c9806df36f42276f13962a</Sha>
</Dependency>
</ToolsetDependencies>
</Dependencies>
6 changes: 3 additions & 3 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@
<RefOnlyNugetPackagingVersion>4.9.4</RefOnlyNugetPackagingVersion>
<!-- sni -->
<RuntimeWinX64RuntimeNativeSystemDataSqlClientSniVersion>4.4.0</RuntimeWinX64RuntimeNativeSystemDataSqlClientSniVersion>
<RuntimeNativeSystemDataSqlClientSniVersion>4.4.0</RuntimeNativeSystemDataSqlClientSniVersion>
<!-- Testing -->
<MicrosoftNETTestSdkVersion>16.3.0</MicrosoftNETTestSdkVersion>
<MicrosoftNETTestSdkVersion>16.4.0</MicrosoftNETTestSdkVersion>
<XUnitVersion>2.4.1</XUnitVersion>
<TraceEventVersion>2.0.5</TraceEventVersion>
<NewtonsoftJsonVersion>12.0.1</NewtonsoftJsonVersion>
<NewtonsoftJsonVersion>12.0.3</NewtonsoftJsonVersion>
<XUnitXmlTestLoggerVersion>2.1.26</XUnitXmlTestLoggerVersion>
<!-- Test data -->
<SystemIOCompressionTestDataVersion>1.0.16</SystemIOCompressionTestDataVersion>
<SystemIOPackagingTestDataVersion>1.0.4</SystemIOPackagingTestDataVersion>
Expand Down
2 changes: 1 addition & 1 deletion eng/pipelines/libraries/corefx-base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
- _msbuildCommonParameters: /p:OfficialBuildId=$(Build.BuildNumber)

- ${{ if eq(job.submitToHelix, 'true') }}:
- _archiveTestsParameter: /p:ArchiveTests=Tests
- _archiveTestsParameter: /p:ArchiveTests=true
- ${{ if eq(parameters.isOfficialBuild, 'true') }}:
- group: DotNet-HelixApi-Access

Expand Down
2 changes: 1 addition & 1 deletion eng/pipelines/libraries/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ stages:
-allconfigurations
-arch $(_architecture)
/p:RuntimeOS=win10
/p:ArchiveTests=Packages
/p:ArchiveTests=true
$(_msbuildCommonParameters)
displayName: Build Packages and Tests

Expand Down
30 changes: 29 additions & 1 deletion eng/references.targets
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
<IncludeDefaultReferences Condition="'$(MSBuildProjectExtension)' == '.csproj'">true</IncludeDefaultReferences>
<IncludeDefaultReferences Condition="'$(MSBuildProjectExtension)' == '.vbproj'">true</IncludeDefaultReferences>
</PropertyGroup>

<Target Name="SetupDefaultReferences">
<ItemGroup Condition="'$(IncludeDefaultReferences)' =='true'">
<ItemGroup Condition="'$(IncludeDefaultReferences)' == 'true'">
<!-- netstandard is a default reference whenever building for NETStandard or building an implementation assembly -->
<DefaultReference Condition="('$(TargetsNetStandard)' == 'true' or '$(IsReferenceAssembly)' != 'true') and Exists('$(RefPath)netstandard.dll')" Include="netstandard" />
</ItemGroup>
Expand All @@ -35,5 +36,32 @@
</ItemGroup>
</Target>

<Target Name="AddDefaultTestReferences" BeforeTargets="SetupDefaultReferences" Condition="'$(IsTestProject)' == 'true'">
<ItemGroup>
<DefaultReferenceExclusions Include="@(ReferenceFromRuntime)"/>

<!-- Reference everything in the targeting pack directory -->
<DefaultReferenceDirs Include="$(RefPath)" />
<DefaultReferenceItems Include="%(DefaultReferenceDirs.Identity)/*.dll" />

<DefaultReferenceExclusions>
<RefDir>%(DefaultReferenceDirs.Identity)</RefDir>
</DefaultReferenceExclusions>
<_defaultReferenceExclusionsFullPath Include="%(DefaultReferenceExclusions.RefDir)%(DefaultReferenceExclusions.Identity).dll" />

<!-- Ensure conflict resolution can see these references. -->
<Reference Include="%(DefaultReferenceItems.FullPath)" Private="false" />
</ItemGroup>
</Target>

<Target Name="RemoveConflictResolutionAssetsForTests"
AfterTargets="_HandlePackageFileConflicts"
DependsOnTargets="AddDefaultTestReferences"
Condition="'@(_defaultReferenceExclusionsFullPath)' != ''">
<ItemGroup>
<Reference Remove="@(_defaultReferenceExclusionsFullPath)" />
</ItemGroup>
</Target>

<Target Name="AddReferencesDynamically" BeforeTargets="PrepareForBuild" />
</Project>
200 changes: 200 additions & 0 deletions eng/testing/RunnerTemplate.Unix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#!/usr/bin/env bash

usage()
{
echo "Usage: RunTests.sh {-r|--runtime-path} <runtime-path> [{--rsp-file} <rsp-file>]"
echo ""
echo "Parameters:"
echo "--runtime-path (Mandatory) Testhost containing the test runtime used during test execution (short: -r)"
echo "--rsp-file RSP file to pass in additional arguments"
echo "--help Print help and exit (short: -h)"
}

EXECUTION_DIR=$(dirname "$0")
RUNTIME_PATH=''
RSP_FILE=''

while [[ $# > 0 ]]; do
opt="$(echo "${1}" | awk '{print tolower($0)}')"
case "$opt" in
--help|-h)
usage
exit 0
;;
--runtime-path|-r)
RUNTIME_PATH=$2
shift
;;
--rsp-file)
RSP_FILE=\@$2
shift
;;
*)
echo "Invalid argument: $1"
usage
exit -1
;;
esac

shift
done

if [ "$RUNTIME_PATH" == "" ]; then
echo "error: -r|--runtime-path argument is required."
usage
exit -1
fi

# Don't use a globally installed SDK.
export DOTNET_MULTILEVEL_LOOKUP=0

exitcode_list[0]="Exited Successfully"
exitcode_list[130]="SIGINT Ctrl-C occurred. Likely tests timed out."
exitcode_list[131]="SIGQUIT Ctrl-\ occurred. Core dumped."
exitcode_list[132]="SIGILL Illegal Instruction. Core dumped. Likely codegen issue."
exitcode_list[133]="SIGTRAP Breakpoint hit. Core dumped."
exitcode_list[134]="SIGABRT Abort. Managed or native assert, or runtime check such as heap corruption, caused call to abort(). Core dumped."
exitcode_list[135]="IGBUS Unaligned memory access. Core dumped."
exitcode_list[136]="SIGFPE Bad floating point arguments. Core dumped."
exitcode_list[137]="SIGKILL Killed eg by kill"
exitcode_list[139]="SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped."
exitcode_list[143]="SIGTERM Terminated. Usually before SIGKILL."
exitcode_list[159]="SIGSYS Bad System Call."

function print_info_from_core_file_using_lldb {
local core_file_name=$1
local executable_name=$2
local plugin_path_name="$RUNTIME_PATH/shared/Microsoft.NETCore.App/9.9.9/libsosplugin.so"

# check for existence of lldb on the path
hash lldb 2>/dev/null || { echo >&2 "lldb was not found. Unable to print core file."; return; }

# pe, clrstack, and dumpasync are defined in libsosplugin.so
if [ ! -f $plugin_path_name ]; then
echo $plugin_path_name cannot be found.
return
fi

echo ----- start =============== lldb Output =====================================================
echo Printing managed exceptions, managed call stacks, and async state machines.
lldb -O "settings set target.exec-search-paths $RUNTIME_PATH" -o "plugin load $plugin_path_name" -o "clrthreads -managedexception" -o "pe -nested" -o "clrstack -all -a -f" -o "dumpasync -fields -stacks -roots" -o "quit" --core $core_file_name $executable_name
echo ----- end =============== lldb Output =======================================================
}

function print_info_from_core_file_using_gdb {
local core_file_name=$1
local executable_name=$2

# Check for the existence of GDB on the path
hash gdb 2>/dev/null || { echo >&2 "GDB was not found. Unable to print core file."; return; }

echo ----- start =============== GDB Output =====================================================
# Open the dump in GDB and print the stack from each thread. We can add more
# commands here if desired.
echo printing native stack.
gdb --batch -ex "thread apply all bt full" -ex "quit" $executable_name $core_file_name
echo ----- end =============== GDB Output =======================================================
}

function print_info_from_core_file {
local core_file_name=$1
local executable_name=$RUNTIME_PATH/$2

if ! [ -e $executable_name ]; then
echo "Unable to find executable $executable_name"
return
elif ! [ -e $core_file_name ]; then
echo "Unable to find core file $core_file_name"
return
fi
echo "Printing info from core file $core_file_name"
print_info_from_core_file_using_gdb $core_file_name $executable_name
print_info_from_core_file_using_lldb $core_file_name $executable_name
}

function copy_core_file_to_temp_location {
local core_file_name=$1

local storage_location="/tmp/coredumps"

# Create the directory (this shouldn't fail even if it already exists).
mkdir -p $storage_location

local new_location=$storage_location/core.$RANDOM

echo "Copying core file $core_file_name to $new_location in case you need it."
cp $core_file_name $new_location
}

# ========================= BEGIN Core File Setup ============================
if [ "$(uname -s)" == "Darwin" ]; then
# On OS X, we will enable core dump generation only if there are no core
# files already in /cores/ at this point. This is being done to prevent
# inadvertently flooding the CI machines with dumps.
if [[ ! -d "/cores" || ! "$(ls -A /cores)" ]]; then
ulimit -c unlimited
fi
elif [ "$(uname -s)" == "Linux" ]; then
# On Linux, we'll enable core file generation unconditionally, and if a dump
# is generated, we will print some useful information from it and delete the
# dump immediately.

if [ -e /proc/self/coredump_filter ]; then
# Include memory in private and shared file-backed mappings in the dump.
# This ensures that we can see disassembly from our shared libraries when
# inspecting the contents of the dump. See 'man core' for details.
echo -n 0x3F > /proc/self/coredump_filter
fi

ulimit -c unlimited
fi
# ========================= END Core File Setup ==============================

# ========================= BEGIN Test Execution =============================
echo ----- start $(date) =============== To repro directly: =====================================================
echo pushd $EXECUTION_DIR
[[RunCommandsEcho]]
echo popd
echo ===========================================================================================================
pushd $EXECUTION_DIR
[[RunCommands]]
test_exitcode=$?
popd
echo ----- end $(date) ----- exit code $test_exitcode ----------------------------------------------------------

if [ "${exitcode_list[$test_exitcode]}" != "" ]; then
echo exit code $test_exitcode means ${exitcode_list[$test_exitcode]}
fi
# ========================= END Test Execution ===============================

# ======================= BEGIN Core File Inspection =========================
pushd $EXECUTION_DIR >/dev/null
if [[ "$(uname -s)" == "Linux" && $test_exitcode -ne 0 ]]; then
echo Looking around for any Linux dump...
# Depending on distro/configuration, the core files may either be named "core"
# or "core.<PID>" by default. We read /proc/sys/kernel/core_uses_pid to
# determine which it is.
core_name_uses_pid=0
if [ -e /proc/sys/kernel/core_uses_pid ] && [ "1" == $(cat /proc/sys/kernel/core_uses_pid) ]; then
core_name_uses_pid=1
fi

if [ $core_name_uses_pid == "1" ]; then
# We don't know what the PID of the process was, so let's look at all core
# files whose name matches core.NUMBER
echo Looking for files matching core.* ...
for f in core.*; do
[[ $f =~ core.[0-9]+ ]] && print_info_from_core_file "$f" "dotnet" && copy_core_file_to_temp_location "$f" && rm "$f"
done
elif [ -f core ]; then
echo found a dump named core in $EXECUTION_DIR !
print_info_from_core_file "core" "dotnet"
copy_core_file_to_temp_location "core"
rm "core"
else
echo ... found no dump in $PWD
fi
fi
popd >/dev/null
# ======================== END Core File Inspection ==========================
exit $test_exitcode
Loading

0 comments on commit 1d5de15

Please sign in to comment.