Skip to content

Instantly share code, notes, and snippets.

@roubachof
Last active June 28, 2016 11:41
Show Gist options
  • Save roubachof/47b974d576d722dc0c01 to your computer and use it in GitHub Desktop.
Save roubachof/47b974d576d722dc0c01 to your computer and use it in GitHub Desktop.
Continuous Integration with Xamarin: launch emulator, copy apk, launch activity, retrieve test results as xml.
#
# Notes:
#
# - 10/06/16
# - the script attempts to connect to the first active Android emulator
# found in the list returned by the "adb devices" command, and launches it, if this list is empty.
# In this case, the AVD launched is the first .ini file found in the directory.
#
# paramètres (exemple):
# .\launch-emulator.ps1
# -tcpListenerPath .\Stago.Mhp.Instr.Pocm.UnitTests.Droid.Server.exe
# -tcpListenerIp 127.0.0.1
# -tcpListenerPort 13000
# -packageName Stago.Mhp.Instr.Pocm.UnitTests.Droid
# -activityName stago.mhp.instr.pocm.unitTests.droid.mainActivity
# [option] -avdName Nexus-S-API22-ARM
# [option] -outXmlReportPath ..\..\artifacts\DroidTestResults.xml
# [option] -logServerTimeoutInSeconds 1200​
# [option] -apkName xxxx-Signed.pak
# powershell.exe -noprofile -executionpolicy bypass -file .\launch-emulator.ps1 -tcpListenerPath .\Stago.Mhp.Instr.Pocm.UnitTests.Droid.Server.exe -tcpListenerIp 127.0.0.1 -tcpListenerPort 13000 -packageName Stago.Mhp.Instr.Pocm.UnitTests.Droid -activityName stago.mhp.instr.pocm.unitTests.droid.mainActivity -outXmlReportPath ..\..\artifacts\DroidTestResults.xml -logServerTimeoutInSeconds 1200
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$tcpListenerPath,
[Parameter(Mandatory=$True)]
[string]$tcpListenerIp,
[Parameter(Mandatory=$True)]
[int]$tcpListenerPort,
[Parameter(Mandatory=$True)]
[string]$packageName,
[Parameter(Mandatory=$True)]
[string]$activityName,
[string]$avdName,
[string]$apkName,
[string]$outXmlReportPath,
[int]$logServerTimeoutInSeconds
)
try
{
#region --- try
Write-Host "Version=1.0.503"
Write-Host ""
#
# IMPORTANT: cleanup des process 'adb', 'emulator', ...
#
Write-Host "Get-Process emulator*, adb*(0)"
Get-Process emulator*, adb*
Write-Host "-------------------------------"
Get-Process emulator*, adb* | Stop-Process
Write-Host "Get-Process emulator*, adb*(1)"
Get-Process emulator*, adb*
Write-Host "-------------------------------"
#region --- Prepare environment
# Add needed pathes
Write-Host "Adding the needed paths to the process environment path"
$VerifiedPathsToAdd = $Null
$PathToAdd = @(
"C:\Users\AgentTeamcity\AppData\Local\Android\android-sdk\platform-tools",
"C:\Users\AgentTeamcity\AppData\Local\Android\android-sdk\tools")
Foreach ($Path in $PathToAdd)
{
if ($env:Path -like "*$Path*")
{
Write-Host "$Path already exists in Path statement"
}
else
{
$VerifiedPathsToAdd += ";$Path"
Write-Host "`$Path will be added to the environment path"
}
}
if($VerifiedPathsToAdd -ne $null)
{
Write-Host "Adding $VerifiedPathsToAdd to Path statement now..."
[Environment]::SetEnvironmentVariable("Path",$env:Path + $VerifiedPathsToAdd,"Process") # replace 'Process' with [EnvironmentVariableTarget]::Machine, if you want to make this persistent
}
Write-Host "--------------------------------------------------------------------"
#endregion
#region --- Find or starts an emulator
# Find the emulator name is one is already running
Write-Host "adb devices"
adb devices
Write-Host "-------------------------------"
$aDevice = adb devices
foreach ($device in $aDevice)
{
$position0 = $device.IndexOf("emulator")
if ($position0 -lt 0)
{
continue
}
$emulator = $device.Substring($position0)
$position1 = $emulator.IndexOf(0x09)
if ($position1 -gt 0)
{
$emulator = $emulator.Substring(0, $position1);
}
break
}
Write-Host "emulator='"$emulator"'"
# A running emulator wasn't found lookup in .ini file
if (!$emulator)
{
#region --- Choose the AVD from .ini file
$avdDir = "C:\Users\AgentTeamcity\.android\avd"
Write-Host "Value of the avdName parameter="$avdName
Write-Host "----------------------------------------"
if (!$avdName)
{
Write-Host "Looking for the first .ini file in the avdDir="$avdDir" directory"
Write-Host "--------------------------------------------------------------------"
$List = get-childitem $avdDir | where {$_.extension -eq ".ini"}
if (!$List)
{
throw "EXIT: NO .ini file was found in the directory avdDir=" + $avdDir
}
foreach ($item in $List)
{
$avdName = $item.BaseName
break
}
}
if (!$avdName)
{
throw "EXIT: No AVD was found"
}
Write-Host "Effective value of the avdName="$avdName
Write-Host "----------------------------------------"
#endregion
#region --- Starts the emulator
Try
{
Write-Host "Start-Process(-) -PassThru -FilePath emulator.exe -ArgumentList -no-boot-anim -no-window -avd="$avdName
$process_emulator = Start-Process -PassThru -FilePath emulator.exe -ArgumentList "-no-boot-anim -no-window -avd $avdName"
Write-Host "Start-Process(+) process_emulator="$process_emulator
}
Catch
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
Write-Host "Start-Process(EXCEPTION) ErrorMessage="$ErrorMessage
}
if (!$process_emulator)
{
throw "EXIT: no emulator could be launched."
}
#endregion
Write-Host "adb wait-for-device"
adb wait-for-device
Write-Host "--------------------------------------"
#region --- wait for end of boot
Write-Host "Waiting for the end of the boot sequence"
$timeout = 400
for ($attempts = 0; $attempts -lt $timeout; $attempts++)
{
$result = adb shell getprop sys.boot_completed
Write-Host "adb shell getprop sys.boot_completed -> " $result
if ($result -match "invalid|error|fail")
{
throw "EXIT: failed to communicate with the emulator: $result"
}
Sleep 1
if ($result -like "1*")
{
"Boot sequence ended"
break;
}
}
Write-Host "--------------------------------"
if ($attempts -ge $timeout)
{
throw "Timeout reached while waiting for the end of the boot sequence ($attempts attempts with a 1 second delay)"
}
#endregion
#region --- Get emulator name
Write-Host "adb devices"
adb devices
Write-Host "-------------------------------"
$aDevice = adb devices
foreach ($device in $aDevice)
{
$position0 = $device.IndexOf("emulator")
if ($position0 -lt 0)
{
continue
}
$emulator = $device.Substring($position0)
$position1 = $emulator.IndexOf(0x09)
if ($position1 -gt 0)
{
$emulator = $emulator.Substring(0, $position1);
}
break
}
Write-Host "emulator=<<"$emulator">>"
#endregion
#endregion
}
#endregion
#region --- Launch log server
# $tcpListenerPath_name <- $tcpListenerPath, 'nettoyage'
$tcpListenerPath_name=$tcpListenerPath.ToUpper()
while ($true)
{
if ($tcpListenerPath_name.StartsWith("."))
{
$tcpListenerPath_name = $tcpListenerPath_name.Substring(1)
continue
}
if ($tcpListenerPath_name.StartsWith("\"))
{
$tcpListenerPath_name = $tcpListenerPath_name.Substring(1)
continue
}
break
}
if ($tcpListenerPath_name.EndsWith(".EXE"))
{
$tcpListenerPath_name = $tcpListenerPath_name.Substring(0, $tcpListenerPath_name.Length - 4)
}
Write-Host "tcpListenerPath_name="$tcpListenerPath_name
# kill old server log process
$aProcess = Get-Process
foreach ($process in $aProcess)
{
$processName = $process.Name.ToUpper()
if ($processName.Equals($tcpListenerPath_name))
{
Write-Host "process.Kill()="$process
$process.Kill()
}
}
Write-Host "-------------------------------"
Try
{
Write-Host "Start-Process(-) -PassThru -FilePath tcpListenerPath="$tcpListenerPath
$process_tcpListenerPath = Start-Process -PassThru -FilePath $tcpListenerPath -ArgumentList "-hostname=$tcpListenerIp -port=$tcpListenerPort -output=$outXmlReportPath"
Write-Host "Start-Process(+) process_tcpListenerPath="$process_tcpListenerPath
}
Catch
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
Write-Host "Start-Process(EXCEPTION) ErrorMessage="$ErrorMessage
}
if (!$process_tcpListenerPath)
{
throw "EXIT: process_tcpListenerPath='" + $process_tcpListenerPath + "' could not be launched"
}
#endregion
#region --- Starting the APK
Write-Host "apkName(-)="$apkName
if (-Not $apkName)
{
$apkName = "$packageName-Signed.apk"
}
Write-Host "apkName(+)="$apkName
Write-Host "-------------------------"
Write-Host "Unlocking the emulator screen"
Write-Host "adb -s $emulator shell input keyevent 82"
adb -s $emulator shell input keyevent 82
Write-Host "-------------------------"
Write-Host "Trying to uninstall the package previous version"
Write-Host "adb -s $emulator uninstall $packageName"
adb -s $emulator uninstall $packageName
Write-Host "-------------------------"
Write-Host "Installing the APK"
Write-Host "adb -s $emulator install -r $apkName"
$result = adb -s $emulator install -r "$apkName"
if ($result -match "invalid|error|fail")
{
throw "APK installation failed: $result"
}
Write-Host "-------------------------"
Write-Host "Removing the existing xml results"
Write-Host "adb -s $emulator shell run-as $packageName rm -fr files/NUnitTestsOutput"
adb -s $emulator shell run-as $packageName rm -fr files/NUnitTestsOutput
Write-Host "-------------------------"
Write-Host "Launching the test Activity"
"adb -s $emulator shell am start $packageName/$activityName"
Sleep 5
$result = adb -s $emulator shell am start "$packageName/$activityName"
if ($result -match "invalid|error|fail")
{
throw "Error while launching main activity: $result"
}
Write-Host "-------------------------"
$logServerTimeoutInSeconds = if ($logServerTimeoutInSeconds -eq 0) { 5 * 60 } else { $logServerTimeoutInSeconds }
Write-Host "Waiting for process $logServerProcess with timeout of $logServerTimeoutInSeconds seconds"
if (-Not $process_tcpListenerPath -Or -Not $process_tcpListenerPath.WaitForExit($logServerTimeoutInSeconds * 1000))
{
throw "The log server hasn't received any log in $logServerTimeoutInSeconds seconds: a timeout is detected"
}
Write-Host "-------------------------"
#endregion
#endregion
}
finally
{
#
# IMPORTANT: cleanup processes 'adb', 'emulator', ...
#
Write-Host "Get-Process emulator*, adb*(0)"
Get-Process emulator*, adb*
Write-Host "-------------------------------"
Get-Process emulator*, adb* | Stop-Process
Write-Host "Get-Process emulator*, adb*(1)"
Get-Process emulator*, adb*
Write-Host "-------------------------------"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment