[tests] Run .apk unit tests and collect TestResults.xml (#305)
What do we want? Execution of unit tests! When do we want it? Uh...4 months ago? The `Xamarin.Android.NUnitLite` assembly allows writing NUnit-based unit tests that execute on-device, and the `Mono.Android-Tests.csproj` project contains a number of such unit tests. The problem is that these unit tests aren't executed as part of the Jenkins build process, so there's no way to know if a given commit actually breaks anything. In short, the existence of those unit tests is meaningless. The task, then, is to fix the `make run-all-tests` target so that it runs on-device unit tests...on an Android device. Which raises all manner of problems. :-) (Hence 4+ months!) For starters, our internal tooling is a horrible mish-mash of make(1), ruby(1), bash(1), which creates an emulator, launches it, installs the test .apk onto the emulator, and runs the tests. I don't want all of that "cruft" in this repo, which means it needs to be rewritten in a form more amenable to this repo: MSBuild tasks....and some make(1). :-) Add a new `build-tools/scripts/UnitTestApks.targets` file, which will process an `@(UnitTestApk)` Item Group to permit deploying, running, and undeploying test .apks from an attached Android device. Add a slew of MSBuild tasks to support `@(UnitTestApk)`. Update the default `$(AndroidSupportedTargetJitAbis)` value to be `armeabi-v7a:x86`. The created Android emulator is x86.
This commit is contained in:
Родитель
908f56d6fb
Коммит
48e3fc2672
|
@ -8,3 +8,4 @@ packages
|
|||
.DS_Store
|
||||
.nuget
|
||||
TestResult.xml
|
||||
TestResult-*.xml
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<AndroidSdkDirectory>$(AndroidToolchainDirectory)\sdk</AndroidSdkDirectory>
|
||||
<AndroidNdkDirectory>$(AndroidToolchainDirectory)\ndk</AndroidNdkDirectory>
|
||||
<AndroidSupportedHostJitAbis Condition=" '$(AndroidSupportedHostJitAbis)' == '' ">$(HostOS)</AndroidSupportedHostJitAbis>
|
||||
<AndroidSupportedTargetJitAbis Condition=" '$(AndroidSupportedTargetJitAbis)' == '' ">armeabi-v7a</AndroidSupportedTargetJitAbis>
|
||||
<AndroidSupportedTargetJitAbis Condition=" '$(AndroidSupportedTargetJitAbis)' == '' ">armeabi-v7a:x86</AndroidSupportedTargetJitAbis>
|
||||
<JavaInteropSourceDirectory Condition=" '$(JavaInteropSourceDirectory)' == '' ">$(MSBuildThisFileDirectory)external\Java.Interop</JavaInteropSourceDirectory>
|
||||
<LlvmSourceDirectory Condition=" '$(LlvmSourceDirectory)' == '' ">$(MSBuildThisFileDirectory)external\llvm</LlvmSourceDirectory>
|
||||
<MonoSourceDirectory>$(MSBuildThisFileDirectory)external\mono</MonoSourceDirectory>
|
||||
|
@ -70,6 +70,14 @@
|
|||
<LibZipSourceFullPath>$([System.IO.Path]::GetFullPath ('$(LibZipSourceDirectory)'))</LibZipSourceFullPath>
|
||||
<LibZipSharpSourceFullPath>$([System.IO.Path]::GetFullPath ('$(LibZipSharpSourceDirectory)'))</LibZipSharpSourceFullPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AdbToolPath Condition=" '$(AdbToolPath)' == '' ">$(AndroidSdkFullPath)\platform-tools</AdbToolPath>
|
||||
<AdbToolExe Condition=" '$(AdbToolExe)' == '' ">adb</AdbToolExe>
|
||||
<AndroidToolPath Condition=" '$(AndroidToolPath)' == '' ">$(AndroidSdkFullPath)\tools</AndroidToolPath>
|
||||
<AndroidToolExe Condition=" '$(AndroidToolExe)' == '' ">android</AndroidToolExe>
|
||||
<EmulatorToolPath Condition=" '$(EmulatorToolPath)' == '' ">$(AndroidSdkFullPath)\tools</EmulatorToolPath>
|
||||
<EmulatorToolExe Condition=" '$(EmulatorToolExe)' == '' ">emulator</EmulatorToolExe>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
"Fixup" $(AndroidSupportedHostJitAbis) so that Condition attributes elsewhere
|
||||
can use `:ABI-NAME:`, to avoid substring mismatches.
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# Development Tips
|
||||
|
||||
Tips and tricks while developing Xamarin.Android.
|
||||
|
||||
# How do I rebuild the Mono Runtime and Native Binaries?
|
||||
|
||||
The various Mono runtimes -- over *20* of them (!) -- all store object code
|
||||
within `build-tools/mono-runtimes/obj/$(Configuration)/TARGET`.
|
||||
|
||||
If you change sources within `external/mono`, a top-level `make`/`xbuild`
|
||||
invocation may not rebuild those mono native binaries. To explicitly rebuild
|
||||
*all* Mono runtimes, use the `ForceBuild` target:
|
||||
|
||||
# Build and install all runtimes
|
||||
$ xbuild /t:ForceBuild build-tools/mono-runtimes/mono-runtimes.mdproj
|
||||
|
||||
To build Mono for a specific target, run `make` from the relevant directory
|
||||
and invoke the `_InstallRuntimes` target. For example, to rebuild
|
||||
Mono for armeabi-v7a:
|
||||
|
||||
$ cd build-tools/mono-runtimes
|
||||
$ make -C obj/Debug/armeabi-v7a
|
||||
|
||||
# This updates bin/$(Configuration)/lib/xbuild/Xamarin/Android/lib/armeabi-v7a/libmonosgen-2.0.so
|
||||
$ xbuild /t:_InstallRuntimes
|
||||
|
||||
# How do I rebuild BCL assemblies?
|
||||
|
||||
The Xamarin.Android Base Class Library assemblies, such as `mscorlib.dll`,
|
||||
are built within `external/mono`, using Mono's normal build system:
|
||||
|
||||
# This updates external/mono/mcs/class/lib/monodroid/ASSEMBLY.dll
|
||||
$ make -C external/mono/mcs/class/ASSEMBLY PROFILE=monodroid
|
||||
|
||||
Alternatively, if you want to rebuild *all* the assemblies, the "host"
|
||||
Mono needs to be rebuilt. Note that the name of the "host" directory
|
||||
varies based on the operating system you're building from:
|
||||
|
||||
$ make -C build-tools/mono-runtimes/obj/Debug/host-Darwin
|
||||
|
||||
Once the assemblies have been rebuilt, they can be copied into the appropriate
|
||||
Xamarin.Android SDK directory by using the `_InstallBcl` target:
|
||||
|
||||
# This updates bin/$(Configuration)/lib/xbuild-frameworks/MonoAndroid/v1.0/ASSEMBLY.dll
|
||||
$ xbuild build-tools/mono-runtimes/mono-runtimes.mdproj /t:_InstallBcl
|
||||
|
||||
# Testing Updated Assemblies
|
||||
|
||||
The `xamarin-android` repo does not support [fast deployment][fastdep],
|
||||
which means that, *normally*, if you wanted to e.g. test a fix within
|
||||
`Mono.Android.dll` you would need to:
|
||||
|
||||
[fastdev]: https://developer.xamarin.com/guides/android/under_the_hood/build_process/#Fast_Deployment
|
||||
|
||||
1. Build `src/Mono.Android/Mono.Android.csproj`
|
||||
2. Rebuild your test project, e.g.
|
||||
`src/Mono.Android/Test/Mono.Android-Tests.csproj`
|
||||
3. Reinstall the test project
|
||||
4. Re-run the test project.
|
||||
|
||||
The resulting `.apk`s can be quite big, e.g.
|
||||
`bin/TestDebug/Mono.Android_Tests-Signed.apk` is 59MB, so steps
|
||||
(2) through (4) can be annoyingly time consuming.
|
||||
|
||||
Fortunately, a key part of fast deployment *is* part of the `xamarin-android`:
|
||||
an "update directory" is created by `libmono-android*.so` during process
|
||||
startup, in *non*-`RELEASE` builds. This directory is printed to `adb logcat`:
|
||||
|
||||
W/monodroid( 2796): Creating public update directory: `/data/data/Mono.Android_Tests/files/.__override__`
|
||||
|
||||
Assemblies located within the "update directory" are used *in preference to*
|
||||
assemblies located within the executing `.apk`. Assemblies can be `adb push`ed
|
||||
into the update directory:
|
||||
|
||||
adb push bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.1/Mono.Android.dll /data/data/Mono.Android_Tests/files/.__override__
|
||||
|
||||
When the process restarts the new assembly will be used.
|
24
Makefile
24
Makefile
|
@ -25,7 +25,7 @@ all::
|
|||
$(MSBUILD) $(MSBUILD_FLAGS) $(SOLUTION)
|
||||
|
||||
all-tests::
|
||||
tools/scripts/xabuild $(MSBUILD_FLAGS) Xamarin.Android-Tests.sln
|
||||
MSBUILD="$(MSBUILD)" tools/scripts/xabuild $(MSBUILD_FLAGS) Xamarin.Android-Tests.sln
|
||||
|
||||
prepare:: prepare-external prepare-props
|
||||
|
||||
|
@ -142,27 +142,25 @@ define RUN_NUNIT_TEST
|
|||
$(RUNTIME) --runtime=v4.0.0 \
|
||||
$(NUNIT_CONSOLE) $(NUNIT_EXTRA) $(1) \
|
||||
$(if $(RUN),-run:$(RUN)) \
|
||||
--result=TestResult-$(basename $(notdir $(1))).xml \
|
||||
-output=bin/Test$(CONFIGURATION)/TestOutput-$(basename $(notdir $(1))).txt ;
|
||||
endef
|
||||
|
||||
run-nunit-tests: $(NUNIT_TESTS)
|
||||
$(foreach t,$(NUNIT_TESTS), $(call RUN_NUNIT_TEST,$(t),1))
|
||||
|
||||
# Test .apk projects must satisfy the following requirements:
|
||||
# 1. They must have a UnDeploy target
|
||||
# 2. They must have a Deploy target
|
||||
# 3. They must have a RunTests target
|
||||
# .apk files to test on-device need to:
|
||||
# (1) Have their .csproj files listed here
|
||||
# (2) Add a `@(UnitTestApk)` entry to `tests/RunApkTests.targets`
|
||||
TEST_APK_PROJECTS = \
|
||||
src/Mono.Android/Test/Mono.Android-Tests.csproj
|
||||
|
||||
# Syntax: $(call RUN_TEST_APK,path/to/project.csproj)
|
||||
define RUN_TEST_APK
|
||||
# Syntax: $(call BUILD_TEST_APK,path/to/project.csproj)
|
||||
define BUILD_TEST_APK
|
||||
# Must use xabuild to ensure correct assemblies are resolved
|
||||
tools/scripts/xabuild /t:SignAndroidPackage $(1) && \
|
||||
$(MSBUILD) $(MSBUILD_FLAGS) /t:UnDeploy $(1) && \
|
||||
$(MSBUILD) $(MSBUILD_FLAGS) /t:Deploy $(1) && \
|
||||
$(MSBUILD) $(MSBUILD_FLAGS) /t:RunTests $(1) $(if $(ADB_TARGET),"/p:AdbTarget=$(ADB_TARGET)",)
|
||||
endef
|
||||
MSBUILD="$(MSBUILD)" tools/scripts/xabuild /t:SignAndroidPackage $(1)
|
||||
endef # BUILD_TEST_APK
|
||||
|
||||
run-apk-tests:
|
||||
$(foreach p, $(TEST_APK_PROJECTS), $(call RUN_TEST_APK, $(p)))
|
||||
$(foreach p, $(TEST_APK_PROJECTS), $(call BUILD_TEST_APK, $(p)))
|
||||
$(MSBUILD) $(MSBUILD_FLAGS) tests/RunApkTests.targets
|
||||
|
|
42
README.md
42
README.md
|
@ -290,44 +290,4 @@ We use [Bugzilla](https://bugzilla.xamarin.com/enter_bug.cgi?product=Android) to
|
|||
|
||||
# Maintainer FAQ
|
||||
|
||||
## How do I rebuild the Mono Runtime and Native Binaries?
|
||||
|
||||
The various Mono runtimes -- over *20* of them (!) -- all store object code
|
||||
within `build-tools/mono-runtimes/obj/$(Configuration)/TARGET`.
|
||||
|
||||
If you change sources within `external/mono`, a top-level `make`/`xbuild`
|
||||
invocation may not rebuild those mono native binaries. To explicitly rebuild
|
||||
*all* Mono runtimes, use the `ForceBuild` target:
|
||||
|
||||
# Build and install all runtimes
|
||||
$ xbuild /t:ForceBuild build-tools/mono-runtimes/mono-runtimes.mdproj
|
||||
|
||||
To build Mono for a specific target, run `make` from the relevant directory
|
||||
and invoke the `_InstallRuntimes` target. For example, to rebuild
|
||||
Mono for armeabi-v7a:
|
||||
|
||||
$ cd build-tools/mono-runtimes
|
||||
$ make -C obj/Debug/armeabi-v7a
|
||||
|
||||
# This updates bin/$(Configuration)/lib/xbuild/Xamarin/Android/lib/armeabi-v7a/libmonosgen-2.0.so
|
||||
$ xbuild /t:_InstallRuntimes
|
||||
|
||||
## How do I rebuild BCL assemblies?
|
||||
|
||||
The Xamarin.Android Base Class Library assemblies, such as `mscorlib.dll`,
|
||||
are built within `external/mono`, using Mono's normal build system:
|
||||
|
||||
# This updates external/mono/mcs/class/lib/monodroid/ASSEMBLY.dll
|
||||
$ make -C external/mono/mcs/class/ASSEMBLY PROFILE=monodroid
|
||||
|
||||
Alternatively, if you want to rebuild *all* the assemblies, the "host"
|
||||
Mono needs to be rebuilt. Note that the name of the "host" directory
|
||||
varies based on the operating system you're building from:
|
||||
|
||||
$ make -C build-tools/mono-runtimes/obj/Debug/host-Darwin
|
||||
|
||||
Once the assemblies have been rebuilt, they can be copied into the appropriate
|
||||
Xamarin.Android SDK directory by using the `_InstallBcl` target:
|
||||
|
||||
# This updates bin/$(Configuration)/lib/xbuild-frameworks/MonoAndroid/v1.0/ASSEMBLY.dll
|
||||
$ xbuild build-tools/mono-runtimes/mono-runtimes.mdproj /t:_InstallBcl
|
||||
See [DevelopmentTips.md](Documentation/DevelopmentTips.md).
|
||||
|
|
|
@ -86,6 +86,11 @@
|
|||
<HostOS></HostOS>
|
||||
<DestDir>extras\android\m2repository</DestDir>
|
||||
</AndroidSdkItem>
|
||||
<AndroidSdkItem Include="sysimg_x86-21_r03.zip">
|
||||
<HostOS></HostOS>
|
||||
<RelUrl>sys-img/android/</RelUrl>
|
||||
<DestDir>system-images\android-21\x86</DestDir>
|
||||
</AndroidSdkItem>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<_NdkToolchain Include="arm-linux-androideabi-clang" Condition="$(AndroidSupportedTargetJitAbisForConditionalChecks.Contains(':armeabi:')) Or $(AndroidSupportedTargetJitAbisForConditionalChecks.Contains(':armeabi-v7a:')) Or $(AndroidSupportedTargetAotAbisForConditionalChecks.Contains (':win-armeabi:'))">
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
Outputs="@(_PlatformAndroidSdkItem->'$(AndroidToolchainCacheDirectory)\%(Identity)');@(_PlatformAndroidNdkItem->'$(AndroidToolchainCacheDirectory)\%(Identity)')">
|
||||
<MakeDir Directories="$(AndroidToolchainCacheDirectory)" />
|
||||
<DownloadUri
|
||||
SourceUris="@(_PlatformAndroidSdkItem->'$(AndroidUri)/%(Identity)');@(_PlatformAndroidNdkItem->'$(AndroidUri)/%(Identity)')"
|
||||
SourceUris="@(_PlatformAndroidSdkItem->'$(AndroidUri)/%(RelUrl)%(Identity)');@(_PlatformAndroidNdkItem->'$(AndroidUri)/%(RelUrl)%(Identity)')"
|
||||
DestinationFiles="@(_PlatformAndroidSdkItem->'$(AndroidToolchainCacheDirectory)\%(Identity)');@(_PlatformAndroidNdkItem->'$(AndroidToolchainCacheDirectory)\%(Identity)')"
|
||||
/>
|
||||
</Target>
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.Adb" />
|
||||
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.CheckAdbTarget" />
|
||||
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.CreateAndroidEmulator" />
|
||||
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.RunInstrumentationTests" />
|
||||
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Xamarin.Android.Tools.BootstrapTasks.dll" TaskName="Xamarin.Android.Tools.BootstrapTasks.StartAndroidEmulator" />
|
||||
|
||||
<PropertyGroup>
|
||||
<_TestImageName>XamarinAndroidUnitTestRunner</_TestImageName>
|
||||
<_AdbEmulatorPort>5600</_AdbEmulatorPort>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="AcquireAndroidTarget">
|
||||
<CheckAdbTarget
|
||||
Condition=" '$(RequireNewEmulator)' != 'True' "
|
||||
AdbTarget="$(AdbTarget)"
|
||||
ToolPath="$(AdbToolPath)">
|
||||
<Output TaskParameter="AdbTarget" PropertyName="_AdbTarget" />
|
||||
<Output TaskParameter="IsValidTarget" PropertyName="_ValidAdbTarget" />
|
||||
</CheckAdbTarget>
|
||||
<CreateAndroidEmulator
|
||||
Condition=" '$(_ValidAdbTarget)' != 'True' "
|
||||
AndroidAbi="x86"
|
||||
AndroidSdkHome="$(AndroidSdkDirectory)"
|
||||
SdkVersion="21"
|
||||
ImageName="$(_TestImageName)"
|
||||
ToolExe="$(AndroidToolExe)"
|
||||
ToolPath="$(AndroidToolPath)"
|
||||
/>
|
||||
<StartAndroidEmulator
|
||||
Condition=" '$(_ValidAdbTarget)' != 'True' "
|
||||
AndroidSdkHome="$(AndroidSdkDirectory)"
|
||||
ImageName="$(_TestImageName)"
|
||||
Port="$(_AdbEmulatorPort)"
|
||||
ToolExe="$(EmulatorToolExe)"
|
||||
ToolPath="$(EmulatorToolPath)">
|
||||
<Output TaskParameter="AdbTarget" PropertyName="_AdbTarget" />
|
||||
<Output TaskParameter="AdbTarget" PropertyName="_EmuTarget" />
|
||||
<Output TaskParameter="AdbProcess" PropertyName="_EmuProcess" />
|
||||
</StartAndroidEmulator>
|
||||
<Adb
|
||||
Condition=" '$(_ValidAdbTarget)' != 'True' "
|
||||
Arguments="$(_AdbTarget) wait-for-device"
|
||||
/>
|
||||
<Message
|
||||
Condition=" '$(_EmuTarget)' != '' "
|
||||
Text="Launched Android emulator; `adb` target: '$(_AdbTarget)'"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<Target Name="ReleaseAndroidTarget">
|
||||
<Adb
|
||||
Condition=" '$(_EmuTarget)' != '' "
|
||||
Arguments="$(_EmuTarget) emu kill"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
<ItemGroup>
|
||||
<UnitTestApk Include="ApkFile">
|
||||
<Package></Package>
|
||||
<InstrumentationType></InstrumentationType>
|
||||
<ResultsPath></ResultsPath>
|
||||
</UnitTestApk>
|
||||
</ItemGroup>
|
||||
-->
|
||||
|
||||
<Target Name="DeployUnitTestApks"
|
||||
Condition=" '@(UnitTestApk)' != '' ">
|
||||
<Adb
|
||||
Arguments="$(_AdbTarget) $(AdbOptions) install -r "%(UnitTestApk.Identity)""
|
||||
ToolExe="$(AdbToolExe)"
|
||||
ToolPath="$(AdbToolPath)"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<Target Name="UndeployUnitTestApks"
|
||||
Condition=" '@(UnitTestApk)' != '' ">
|
||||
<Adb
|
||||
Arguments="$(_AdbTarget) $(AdbOptions) uninstall "%(UnitTestApk.Package)""
|
||||
ToolExe="$(AdbToolExe)"
|
||||
ToolPath="$(AdbToolPath)"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<Target Name="RunUnitTestApks"
|
||||
Condition=" '@(UnitTestApk)' != '' ">
|
||||
<RunInstrumentationTests
|
||||
AdbTarget="$(_AdbTarget)"
|
||||
AdbOptions="$(AdbOptions)"
|
||||
Component="%(UnitTestApk.Package)/%(UnitTestApk.InstrumentationType)"
|
||||
NUnit2TestResultsFile="%(UnitTestApk.ResultsPath)"
|
||||
ToolExe="$(AdbToolExe)"
|
||||
ToolPath="$(AdbToolPath)">
|
||||
<Output TaskParameter="NUnit2TestResultsFile" PropertyName="_ResultsFile "/>
|
||||
</RunInstrumentationTests>
|
||||
</Target>
|
||||
</Project>
|
|
@ -12,7 +12,7 @@ using IOFile = System.IO.File;
|
|||
|
||||
namespace Xamarin.Android.BuildTools.PrepTasks
|
||||
{
|
||||
public class Git : ToolTask
|
||||
public class Git : PathToolTask
|
||||
{
|
||||
[Required]
|
||||
public ITaskItem WorkingDirectory { get; set; }
|
||||
|
@ -26,10 +26,8 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
protected override string ToolName {
|
||||
get {
|
||||
return "git" + (Path.DirectorySeparatorChar == '\\' ? ".exe" : "");
|
||||
}
|
||||
protected override string ToolBaseName {
|
||||
get { return "git"; }
|
||||
}
|
||||
|
||||
List<string> lines;
|
||||
|
@ -57,23 +55,6 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
protected override string GenerateFullPathToTool ()
|
||||
{
|
||||
var app = string.IsNullOrEmpty (ToolExe) ? ToolName: ToolExe;
|
||||
var path = !string.IsNullOrEmpty (ToolPath) ? ToolPath : GetDirectoryFromPath (app);
|
||||
return Path.Combine (path, app);
|
||||
}
|
||||
|
||||
string GetDirectoryFromPath (string app)
|
||||
{
|
||||
foreach (var p in Environment.GetEnvironmentVariable ("PATH").Split (new [] { Path.PathSeparator.ToString () }, StringSplitOptions.RemoveEmptyEntries)) {
|
||||
if (File.Exists (Path.Combine (p, app))) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
return Arguments;
|
||||
|
@ -86,6 +67,7 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
|
||||
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
|
||||
{
|
||||
base.LogEventsFromTextOutput (singleLine, messageImportance);
|
||||
Lines.Add (singleLine);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace Xamarin.Android.BuildTools.PrepTasks
|
||||
{
|
||||
public abstract class PathToolTask : ToolTask
|
||||
{
|
||||
protected abstract string ToolBaseName { get; }
|
||||
|
||||
protected override string ToolName {
|
||||
get {
|
||||
var dirs = string.IsNullOrEmpty (ToolPath)
|
||||
? null
|
||||
: new [] { ToolPath };
|
||||
string filename;
|
||||
Which.GetProgramLocation (ToolBaseName, out filename, dirs);
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string GenerateFullPathToTool ()
|
||||
{
|
||||
var dirs = string.IsNullOrEmpty (ToolPath)
|
||||
? null
|
||||
: new [] { ToolPath };
|
||||
string filename;
|
||||
var path = Which.GetProgramLocation (ToolBaseName, out filename, dirs);
|
||||
return path;
|
||||
}
|
||||
|
||||
protected void AddEnvironmentVariables (string[] variables)
|
||||
{
|
||||
if (EnvironmentVariables == null) {
|
||||
EnvironmentVariables = variables;
|
||||
return;
|
||||
}
|
||||
if (variables == null)
|
||||
return;
|
||||
var newVariables = new string [checked(EnvironmentVariables.Length + variables.Length)];
|
||||
Array.Copy (EnvironmentVariables, newVariables, EnvironmentVariables.Length);
|
||||
Array.Copy (variables, 0, newVariables, EnvironmentVariables.Length, variables.Length);
|
||||
EnvironmentVariables = newVariables;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,11 +32,42 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
}
|
||||
}
|
||||
|
||||
public static string GetProgramLocation (string programBasename, out string filename, string[] directories = null)
|
||||
{
|
||||
directories = directories ?? GetPathDirectories ();
|
||||
foreach (var d in directories) {
|
||||
var p = GetProgramLocation (programBasename, d, out filename);
|
||||
if (p != null)
|
||||
return p;
|
||||
}
|
||||
filename = programBasename;
|
||||
return null;
|
||||
}
|
||||
|
||||
static string GetProgramLocation (string programBasename, string directory, out string filename)
|
||||
{
|
||||
foreach (var ext in FileExtensions) {
|
||||
filename = Path.ChangeExtension (programBasename, ext);
|
||||
var p = Path.Combine (directory, filename);
|
||||
if (File.Exists (p)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
filename = programBasename;
|
||||
return null;
|
||||
}
|
||||
|
||||
static string[] GetPathDirectories ()
|
||||
{
|
||||
return Environment.GetEnvironmentVariable ("PATH")
|
||||
.Split (Path.PathSeparator);
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
string[] paths = Directories?.Select (d => d.ItemSpec).ToArray ();
|
||||
if (paths == null || paths.Length == 0) {
|
||||
paths = Environment.GetEnvironmentVariable ("PATH").Split (Path.PathSeparator);
|
||||
paths = GetPathDirectories ();
|
||||
}
|
||||
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (Which)}");
|
||||
|
@ -47,17 +78,10 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
}
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (Required)}: {Required}");
|
||||
|
||||
foreach (var path in paths) {
|
||||
var p = Path.Combine (path, Program.ItemSpec);
|
||||
foreach (var ext in FileExtensions) {
|
||||
var e = Path.ChangeExtension (p, ext);
|
||||
if (File.Exists (e)) {
|
||||
Location = new TaskItem (e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Location != null)
|
||||
break;
|
||||
string _;
|
||||
var e = GetProgramLocation (Program.ItemSpec, out _, paths);
|
||||
if (e != null) {
|
||||
Location = new TaskItem (e);
|
||||
}
|
||||
|
||||
if (Location == null && Required) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Xamarin.Android.BuildTools.PrepTasks</RootNamespace>
|
||||
<AssemblyName>xa-prep-tasks</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\Configuration.props" />
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
|
@ -41,6 +41,7 @@
|
|||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\Git.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\GitBranch.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\GitCommitHash.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\PathToolTask.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\SystemUnzip.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\Which.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\GitBlame.cs" />
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
<AndroidNativeLibrary Include="libs\x86\libreuse-threads.so" />
|
||||
<AndroidNativeLibrary Include="libs\x86_64\libreuse-threads.so" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<UnitTestApk Include="$(OutputPath)Mono.Android_Tests-Signed.apk">
|
||||
<Package>Mono.Android_Tests</Package>
|
||||
<InstrumentationType>xamarin.android.runtimetests.TestInstrumentation</InstrumentationType>
|
||||
<ResultsPath>..\..\..\TestResult-Mono.Android_Tests.xml</ResultsPath>
|
||||
</UnitTestApk>
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\..\build-tools\scripts\UnitTestApks.targets" />
|
||||
<Target Name="BuildNativeLibs"
|
||||
BeforeTargets="Build"
|
||||
DependsOnTargets="_ResolveMonoAndroidSdks"
|
||||
|
@ -15,19 +23,4 @@
|
|||
<Error Text="Could not locate Android NDK." Condition="!Exists ('$(AndroidNdkDirectory)\ndk-build')" />
|
||||
<Exec Command=""$(AndroidNdkDirectory)\ndk-build"" />
|
||||
</Target>
|
||||
<Target Name="UnDeploy"
|
||||
DependsOnTargets="_ValidateAndroidPackageProperties">
|
||||
<Exec Command=""$(AndroidSdkDirectory)\platform-tools\adb" $(AdbTarget) $(AdbOptions) uninstall $(_AndroidPackage)" />
|
||||
</Target>
|
||||
<Target Name="Deploy">
|
||||
<Exec Command=""$(AndroidSdkDirectory)\platform-tools\adb" $(AdbTarget) $(AdbOptions) install $(OutputPath)\Mono.Android_Tests-Signed.apk" />
|
||||
</Target>
|
||||
<Target Name="RunTests"
|
||||
DependsOnTargets="_ValidateAndroidPackageProperties">
|
||||
<Exec Command=""$(AndroidSdkDirectory)\platform-tools\adb" $(AdbTarget) $(AdbOptions) shell am instrument -w $(_AndroidPackage)/xamarin.android.runtimetests.TestInstrumentation" />
|
||||
</Target>
|
||||
<Target Name="RunSdbTests"
|
||||
DependsOnTargets="_ValidateAndroidPackageProperties">
|
||||
<Exec Command=""$(AndroidSdkDirectory)\platform-tools\adb" $(AdbTarget) $(AdbOptions) shell am start -n $(_AndroidPackage)/xamarin.android.runtimetests.MainActivity" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="Mono.Android_Tests">
|
||||
<uses-sdk android:minSdkVersion="4" />
|
||||
<uses-sdk android:minSdkVersion="10" />
|
||||
<application android:label="Xamarin.Android.RuntimeTests" android:name="android.apptests.App">
|
||||
<activity
|
||||
android:name="xamarin.android.runtimetests.RenamedActivity"
|
||||
|
|
|
@ -93,10 +93,11 @@ namespace Xamarin.Android.NUnitLite {
|
|||
|
||||
string GetResultsPath ()
|
||||
{
|
||||
var docsDir = Context.GetExternalFilesDir (global::Android.OS.Environment.DirectoryDocuments);
|
||||
if (docsDir == null)
|
||||
return null;
|
||||
return Path.Combine (docsDir.AbsolutePath, "TestResults.xml");
|
||||
var resultsPathFile = Context.GetExternalFilesDir (global::Android.OS.Environment.DirectoryDocuments);
|
||||
var resultsPath = resultsPathFile != null && resultsPathFile.Exists ()
|
||||
? resultsPathFile.AbsolutePath
|
||||
: Path.Combine (Context.FilesDir.AbsolutePath, ".__override__");
|
||||
return Path.Combine (resultsPath, "TestResults.xml");
|
||||
}
|
||||
|
||||
// On some Android targets, the external storage directory is "emulated",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
|
@ -8,7 +8,6 @@
|
|||
<RootNamespace>Xamarin.Android.Tools.BootstrapTasks</RootNamespace>
|
||||
<AssemblyName>Xamarin.Android.Tools.BootstrapTasks</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\Configuration.props" />
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
|
@ -39,9 +38,16 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\UnzipDirectoryChildren.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\Adb.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\Android.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\CheckAdbTarget.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\CreateAndroidEmulator.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\Emulator.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\GenerateProfile.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\GetNugetPackageBasePath.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\RunInstrumentationTests.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\StartAndroidEmulator.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\UnzipDirectoryChildren.cs" />
|
||||
<Compile Include="Xamarin.Android.Tools.BootstrapTasks\Zip.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -58,6 +64,10 @@
|
|||
<Project>{900A0F71-BAAD-417A-8D1A-8D330297CDD0}</Project>
|
||||
<Name>libzip</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\build-tools\xa-prep-tasks\xa-prep-tasks.csproj">
|
||||
<Project>{7CE69551-BD73-4726-ACAA-AAF89C84BAF8}</Project>
|
||||
<Name>xa-prep-tasks</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
using Xamarin.Android.BuildTools.PrepTasks;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class Adb : PathToolTask
|
||||
{
|
||||
public string Arguments { get; set; }
|
||||
|
||||
[Output]
|
||||
public string[] Output { get; set; }
|
||||
|
||||
protected virtual bool LogTaskMessages {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected override string ToolBaseName {
|
||||
get { return "adb"; }
|
||||
}
|
||||
|
||||
List<string> lines;
|
||||
List<string> Lines {
|
||||
get { return lines ?? (lines = new List<string> ()); }
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
if (LogTaskMessages) {
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (Adb)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (Arguments)}: {Arguments}");
|
||||
}
|
||||
|
||||
base.Execute ();
|
||||
|
||||
Output = lines?.ToArray ();
|
||||
|
||||
if (LogTaskMessages) {
|
||||
Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (Output)}:");
|
||||
foreach (var line in (Output ?? new string [0]))
|
||||
Log.LogMessage (MessageImportance.Low, $" {line}");
|
||||
}
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
return Arguments;
|
||||
}
|
||||
|
||||
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
|
||||
{
|
||||
base.LogEventsFromTextOutput (singleLine, messageImportance);
|
||||
Lines.Add (singleLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
using Xamarin.Android.BuildTools.PrepTasks;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class Android : PathToolTask
|
||||
{
|
||||
public string Arguments { get; set; }
|
||||
|
||||
[Output]
|
||||
public string[] Output { get; set; }
|
||||
|
||||
protected virtual bool LogTaskMessages {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected override string ToolBaseName {
|
||||
get { return "android"; }
|
||||
}
|
||||
|
||||
List<string> lines;
|
||||
List<string> Lines {
|
||||
get { return lines ?? (lines = new List<string> ()); }
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
if (LogTaskMessages) {
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (Android)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (Arguments)}: {Arguments}");
|
||||
}
|
||||
|
||||
base.Execute ();
|
||||
|
||||
Output = lines?.ToArray ();
|
||||
|
||||
if (LogTaskMessages) {
|
||||
Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (Output)}:");
|
||||
foreach (var line in (Output ?? new string [0]))
|
||||
Log.LogMessage (MessageImportance.Low, $" {line}");
|
||||
}
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
return Arguments;
|
||||
}
|
||||
|
||||
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
|
||||
{
|
||||
base.LogEventsFromTextOutput (singleLine, messageImportance);
|
||||
Lines.Add (singleLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
using Xamarin.Android.BuildTools.PrepTasks;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class CheckAdbTarget : Adb
|
||||
{
|
||||
public string SdkVersion {get; set;}
|
||||
|
||||
[Output]
|
||||
public string AdbTarget {get; set;}
|
||||
|
||||
[Output]
|
||||
public bool IsValidTarget {get; set;}
|
||||
|
||||
protected override bool LogTaskMessages {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (CheckAdbTarget)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (AdbTarget)}: {AdbTarget}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (SdkVersion)}: {SdkVersion}");
|
||||
|
||||
base.Execute ();
|
||||
|
||||
Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (AdbTarget)}: {AdbTarget}");
|
||||
Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (IsValidTarget)}: {IsValidTarget}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool HandleTaskExecutionErrors ()
|
||||
{
|
||||
// We ignore all generated errors
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
return $"{AdbTarget} shell getprop ro.build.version.sdk";
|
||||
}
|
||||
|
||||
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
|
||||
{
|
||||
base.LogEventsFromTextOutput (singleLine, messageImportance);
|
||||
// Log.LogMessage ($"# jonp: messageImportance={messageImportance}; line='{singleLine}'");
|
||||
if (string.IsNullOrEmpty (singleLine))
|
||||
return;
|
||||
if (singleLine.Equals ("List of devices attached", StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
if (messageImportance == MessageImportance.High)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty (SdkVersion)) {
|
||||
IsValidTarget = true;
|
||||
return;
|
||||
}
|
||||
if (string.Equals (SdkVersion, singleLine, StringComparison.OrdinalIgnoreCase)) {
|
||||
IsValidTarget = true;
|
||||
return;
|
||||
}
|
||||
int required, target;
|
||||
if (int.TryParse (SdkVersion, out required) &&
|
||||
int.TryParse (singleLine, out target) &&
|
||||
target >= required) {
|
||||
IsValidTarget = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
using Xamarin.Android.BuildTools.PrepTasks;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class CreateAndroidEmulator : Task
|
||||
{
|
||||
public string SdkVersion {get; set;}
|
||||
public string AndroidAbi {get; set;}
|
||||
public string AndroidSdkHome {get; set;}
|
||||
|
||||
public string ToolPath {get; set;}
|
||||
public string ToolExe {get; set;}
|
||||
|
||||
public string TargetId {get; set;}
|
||||
|
||||
public string ImageName {get; set;} = "XamarinAndroidUnitTestRunner";
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
if (string.IsNullOrEmpty (TargetId) && !string.IsNullOrEmpty (SdkVersion)) {
|
||||
TargetId = "android-" + SdkVersion;
|
||||
}
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (CreateAndroidEmulator)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidAbi)}: {AndroidAbi}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidSdkHome)}: {AndroidSdkHome}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (ImageName)}: {ImageName}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (SdkVersion)}: {SdkVersion}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (TargetId)}: {TargetId}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (ToolExe)}: {ToolExe}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (ToolPath)}: {ToolPath}");
|
||||
|
||||
Run (GetAndroidPath ());
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
string GetAndroidPath ()
|
||||
{
|
||||
if (string.IsNullOrEmpty (ToolExe))
|
||||
ToolExe = "android";
|
||||
|
||||
var dirs = string.IsNullOrEmpty (ToolPath)
|
||||
? null
|
||||
: new [] { ToolPath };
|
||||
string filename;
|
||||
var path = Which.GetProgramLocation (ToolExe, out filename, dirs);
|
||||
if (path == null) {
|
||||
Log.LogError ($"Could not find `android`. Please set the `{nameof (CreateAndroidEmulator)}.{nameof (ToolPath)}` property appropriately.");
|
||||
return null;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void Run (string android)
|
||||
{
|
||||
if (android == null)
|
||||
return;
|
||||
|
||||
var arguments = $"create avd --abi \"{AndroidAbi}\" -f -n \"{ImageName}\" -t \"{TargetId}\"";
|
||||
foreach (var line in Exec (android, arguments)) {
|
||||
stdin.WriteLine ("no");
|
||||
Log.LogMessage (MessageImportance.Low, line);
|
||||
}
|
||||
}
|
||||
|
||||
StreamWriter stdin;
|
||||
|
||||
IEnumerable<string> Exec (string android, string arguments, DataReceivedEventHandler stderr = null)
|
||||
{
|
||||
Log.LogMessage (MessageImportance.Low, $"Tool {android} execution started with arguments: {arguments}");
|
||||
var psi = new ProcessStartInfo () {
|
||||
FileName = android,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
};
|
||||
Log.LogMessage (MessageImportance.Low, $"Environment variables being passed to the tool:");
|
||||
if (!string.IsNullOrEmpty (AndroidSdkHome)) {
|
||||
psi.EnvironmentVariables ["ANDROID_SDK_HOME"] = AndroidSdkHome;
|
||||
Log.LogMessage (MessageImportance.Low, $"\tANDROID_SDK_HOME=\"{AndroidSdkHome}\"");
|
||||
}
|
||||
var p = new Process () {
|
||||
StartInfo = psi,
|
||||
};
|
||||
stderr = stderr ?? DefaultErrorHandler;
|
||||
p.ErrorDataReceived += stderr;
|
||||
|
||||
using (p) {
|
||||
p.StartInfo = psi;
|
||||
p.Start ();
|
||||
p.BeginErrorReadLine ();
|
||||
|
||||
stdin = p.StandardInput;
|
||||
|
||||
string line;
|
||||
while ((line = p.StandardOutput.ReadLine ()) != null) {
|
||||
yield return line;
|
||||
}
|
||||
|
||||
p.WaitForExit ();
|
||||
if (p.ExitCode != 0) {
|
||||
Log.LogError ($"Process `{android}` exited with value {p.ExitCode}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultErrorHandler (object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrEmpty (e.Data))
|
||||
return;
|
||||
Log.LogError ($"{e.Data}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
using Xamarin.Android.BuildTools.PrepTasks;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class Emulator : PathToolTask
|
||||
{
|
||||
public string Arguments { get; set; }
|
||||
|
||||
[Output]
|
||||
public string[] Output { get; set; }
|
||||
|
||||
protected virtual bool LogTaskMessages {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected override string ToolBaseName {
|
||||
get { return "emulator"; }
|
||||
}
|
||||
|
||||
List<string> lines;
|
||||
List<string> Lines {
|
||||
get { return lines ?? (lines = new List<string> ()); }
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
if (LogTaskMessages) {
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (Emulator)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (Arguments)}: {Arguments}");
|
||||
}
|
||||
|
||||
base.Execute ();
|
||||
|
||||
Output = lines?.ToArray ();
|
||||
|
||||
if (LogTaskMessages) {
|
||||
Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (Output)}:");
|
||||
foreach (var line in (Output ?? new string [0]))
|
||||
Log.LogMessage (MessageImportance.Low, $" {line}");
|
||||
}
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
return Arguments;
|
||||
}
|
||||
|
||||
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
|
||||
{
|
||||
base.LogEventsFromTextOutput (singleLine, messageImportance);
|
||||
Lines.Add (singleLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class RunInstrumentationTests : Adb
|
||||
{
|
||||
public string AdbTarget { get; set; }
|
||||
public string AdbOptions { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Component { get; set; }
|
||||
|
||||
public string[] InstrumentationArguments { get; set; }
|
||||
|
||||
[Output]
|
||||
public string NUnit2TestResultsFile { get; set; }
|
||||
|
||||
protected override bool LogTaskMessages {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
enum ExecuteState {
|
||||
RunInstrumentation,
|
||||
PullFiles,
|
||||
}
|
||||
|
||||
ExecuteState executionState;
|
||||
string targetTestResultsPath;
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
InstrumentationArguments = InstrumentationArguments ?? new string [0];
|
||||
if (string.IsNullOrEmpty (NUnit2TestResultsFile)) {
|
||||
var n = new StringBuilder ("TestResult-").Append (Component);
|
||||
foreach (var c in Path.GetInvalidFileNameChars ()) {
|
||||
n.Replace (c, '_');
|
||||
}
|
||||
n.Append (".xml");
|
||||
NUnit2TestResultsFile = n.ToString ();
|
||||
}
|
||||
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (RunInstrumentationTests)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (AdbTarget)}: {AdbTarget}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (AdbOptions)}: {AdbOptions}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (Component)}: {Component}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (InstrumentationArguments)}:");
|
||||
foreach (var a in InstrumentationArguments) {
|
||||
Log.LogMessage (MessageImportance.Low, $" {a}:");
|
||||
}
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (NUnit2TestResultsFile)}: {NUnit2TestResultsFile}");
|
||||
|
||||
executionState = ExecuteState.RunInstrumentation;
|
||||
base.Execute ();
|
||||
|
||||
if (string.IsNullOrEmpty (targetTestResultsPath)) {
|
||||
Log.LogError ("No `nunit2-results-path` bundle value found in command output! Cannot find NUnit2 XML output!");
|
||||
return false;
|
||||
}
|
||||
|
||||
executionState = ExecuteState.PullFiles;
|
||||
base.Execute ();
|
||||
|
||||
Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (NUnit2TestResultsFile)}: {NUnit2TestResultsFile}");
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
switch (executionState) {
|
||||
case ExecuteState.RunInstrumentation:
|
||||
var args = new StringBuilder ();
|
||||
foreach (var a in InstrumentationArguments) {
|
||||
var kvp = a.Split (new [] { '=' }, 2);
|
||||
args.Append (" -e \"").Append (kvp [0]).Append ("\" \"");
|
||||
args.Append (kvp.Length > 1 ? kvp [1] : "");
|
||||
args.Append ("\"");
|
||||
}
|
||||
return $"{AdbTarget} {AdbOptions} shell am instrument {args.ToString ()} -w \"{Component}\"";
|
||||
case ExecuteState.PullFiles:
|
||||
return $"{AdbTarget} {AdbOptions} pull \"{targetTestResultsPath}\" \"{NUnit2TestResultsFile}\"";
|
||||
}
|
||||
throw new InvalidOperationException ($"Invalid state `{executionState}`!");
|
||||
}
|
||||
|
||||
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
|
||||
{
|
||||
const string TestResultsPathResult = "INSTRUMENTATION_RESULT: nunit2-results-path=";
|
||||
|
||||
base.LogEventsFromTextOutput (singleLine, messageImportance);
|
||||
|
||||
if (string.IsNullOrEmpty (singleLine))
|
||||
return;
|
||||
if (!singleLine.Contains (TestResultsPathResult))
|
||||
return;
|
||||
var i = singleLine.IndexOf (TestResultsPathResult);
|
||||
targetTestResultsPath = singleLine.Substring (i + TestResultsPathResult.Length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
using Xamarin.Android.BuildTools.PrepTasks;
|
||||
|
||||
namespace Xamarin.Android.Tools.BootstrapTasks
|
||||
{
|
||||
public class StartAndroidEmulator : Task
|
||||
{
|
||||
[Output]
|
||||
public string AdbTarget {get; set;}
|
||||
|
||||
[Output]
|
||||
public Process AdbProcess {get; set;}
|
||||
|
||||
public string AndroidSdkHome {get; set;}
|
||||
public string Port {get; set;}
|
||||
public string ImageName {get; set;} = "XamarinAndroidUnitTestRunner";
|
||||
public string ToolPath {get; set;}
|
||||
public string ToolExe {get; set;}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
Log.LogMessage (MessageImportance.Low, $"Task {nameof (StartAndroidEmulator)}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidSdkHome)}: {AndroidSdkHome}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (ImageName)}: {ImageName}");
|
||||
Log.LogMessage (MessageImportance.Low, $" {nameof (Port)}: {Port}");
|
||||
|
||||
Run (GetEmulatorPath ());
|
||||
|
||||
if (!string.IsNullOrEmpty (Port)) {
|
||||
AdbTarget = $"-s emulator-{Port}";
|
||||
}
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
string GetEmulatorPath ()
|
||||
{
|
||||
if (string.IsNullOrEmpty (ToolExe))
|
||||
ToolExe = "emulator";
|
||||
|
||||
var dirs = string.IsNullOrEmpty (ToolPath)
|
||||
? null
|
||||
: new [] { ToolPath };
|
||||
string filename;
|
||||
var path = Which.GetProgramLocation (ToolExe, out filename, dirs);
|
||||
if (path == null) {
|
||||
Log.LogError ($"Could not find `emulator`. Please set the `{nameof (StartAndroidEmulator)}.{nameof (ToolExe)}` property appropriately.");
|
||||
return null;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void Run (string emulator)
|
||||
{
|
||||
if (emulator == null)
|
||||
return;
|
||||
|
||||
var port = string.IsNullOrEmpty (Port) ? "" : $" -port \"{Port}\"";
|
||||
var arguments = $"-avd \"{ImageName}\"{port}";
|
||||
Log.LogMessage (MessageImportance.Low, $"Tool {emulator} execution started with arguments: {arguments}");
|
||||
var psi = new ProcessStartInfo () {
|
||||
FileName = emulator,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
};
|
||||
Log.LogMessage (MessageImportance.Low, $"Environment variables being passed to the tool:");
|
||||
if (!string.IsNullOrEmpty (AndroidSdkHome)) {
|
||||
psi.EnvironmentVariables ["ANDROID_SDK_HOME"] = AndroidSdkHome;
|
||||
Log.LogMessage (MessageImportance.Low, $"\tANDROID_SDK_HOME=\"{AndroidSdkHome}\"");
|
||||
}
|
||||
var p = new Process () {
|
||||
StartInfo = psi,
|
||||
};
|
||||
p.Start ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -417,6 +417,7 @@ create_update_dir (char *override_dir)
|
|||
|
||||
override_dirs [0] = override_dir;
|
||||
create_public_directory (override_dir);
|
||||
log_warn (LOG_DEFAULT, "Creating public update directory: `%s`", override_dir);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<Project DefaultTargets="RunApkTests" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Condition)' == '' ">Debug</Configuration>
|
||||
<OutputPath>$(MSBuildThisFileDirectory)..\bin\Test$(Configuration)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\Configuration.props" />
|
||||
<!--
|
||||
Note that the `.csproj` for each `@(UnitTestApk)` entry *must* be added to
|
||||
`$(TEST_APK_PROJECTS)` in the toplevel Makefile so that the `.apk` is built.
|
||||
-->
|
||||
<ItemGroup>
|
||||
<UnitTestApk Include="$(OutputPath)Mono.Android_Tests-Signed.apk">
|
||||
<Package>Mono.Android_Tests</Package>
|
||||
<InstrumentationType>xamarin.android.runtimetests.TestInstrumentation</InstrumentationType>
|
||||
<ResultsPath>..\TestResult-Mono.Android_Tests.xml</ResultsPath>
|
||||
</UnitTestApk>
|
||||
</ItemGroup>
|
||||
<Import Project="..\build-tools\scripts\UnitTestApks.targets" />
|
||||
<PropertyGroup>
|
||||
<RunApkTestsDependsOn>
|
||||
AcquireAndroidTarget;
|
||||
DeployUnitTestApks;
|
||||
RunUnitTestApks;
|
||||
ReleaseAndroidTarget
|
||||
</RunApkTestsDependsOn>
|
||||
</PropertyGroup>
|
||||
<Target Name="RunApkTests"
|
||||
DependsOnTargets="$(RunApkTestsDependsOn)">
|
||||
</Target>
|
||||
</Project>
|
Загрузка…
Ссылка в новой задаче