2019-05-11 13:03:38 +03:00
using System ;
2016-05-26 16:06:52 +03:00
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Text ;
using System.Threading ;
2016-06-06 13:48:53 +03:00
using System.Threading.Tasks ;
2020-03-06 17:11:33 +03:00
using Xharness.Execution ;
2020-03-25 17:59:29 +03:00
using Xharness.Execution.Mlaunch ;
using Xharness.Hardware ;
2020-03-06 14:00:34 +03:00
using Xharness.Jenkins.TestTasks ;
2020-03-05 14:41:52 +03:00
using Xharness.Listeners ;
2020-03-03 21:59:44 +03:00
using Xharness.Logging ;
2020-03-10 15:12:33 +03:00
using Xharness.Utilities ;
2016-05-26 16:06:52 +03:00
2020-03-17 21:42:21 +03:00
namespace Xharness {
2020-03-29 19:02:03 +03:00
class AppRunner {
readonly IProcessManager processManager ;
2020-03-16 16:26:46 +03:00
readonly ISimulatorsLoaderFactory simulatorsLoaderFactory ;
readonly ISimpleListenerFactory listenerFactory ;
readonly IDeviceLoaderFactory devicesLoaderFactory ;
2020-03-20 13:42:43 +03:00
readonly ICrashSnapshotReporterFactory snapshotReporterFactory ;
2020-03-19 01:39:10 +03:00
readonly ICaptureLogFactory captureLogFactory ;
2020-03-19 20:38:35 +03:00
readonly IDeviceLogCapturerFactory deviceLogCapturerFactory ;
2020-03-25 09:44:47 +03:00
readonly ITestReporterFactory testReporterFactory ;
2020-03-29 19:02:03 +03:00
readonly RunMode runMode ;
2020-03-16 16:26:46 +03:00
readonly bool isSimulator ;
2020-03-24 12:02:22 +03:00
readonly TestTarget target ;
2020-03-16 16:26:46 +03:00
readonly IHarness harness ;
readonly double timeoutMultiplier ;
2020-03-29 19:02:03 +03:00
readonly BuildToolTask buildTask ;
2020-03-16 16:26:46 +03:00
string deviceName ;
string companionDeviceName ;
ISimulatorDevice [ ] simulators ;
ISimulatorDevice simulator = > simulators [ 0 ] ;
2016-05-26 16:06:52 +03:00
2020-03-16 16:26:46 +03:00
bool ensureCleanSimulatorState = true ;
bool EnsureCleanSimulatorState {
get = > ensureCleanSimulatorState & & string . IsNullOrEmpty ( Environment . GetEnvironmentVariable ( "SKIP_SIMULATOR_SETUP" ) ) ;
set = > ensureCleanSimulatorState = value ;
2020-03-11 12:38:03 +03:00
}
2017-01-04 21:45:26 +03:00
2020-03-29 19:02:03 +03:00
public AppBundleInformation AppInformation { get ; }
2020-03-25 09:44:47 +03:00
2020-03-16 16:26:46 +03:00
bool IsExtension = > AppInformation . Extension . HasValue ;
2020-03-25 17:59:29 +03:00
2020-03-16 16:26:46 +03:00
public TestExecutingResult Result { get ; private set ; }
2017-01-04 21:45:26 +03:00
2020-03-16 16:26:46 +03:00
public string FailureMessage { get ; private set ; }
2020-03-25 09:44:47 +03:00
public ILog MainLog { get ; set ; }
2020-03-16 16:26:46 +03:00
public ILogs Logs { get ; }
public AppRunner ( IProcessManager processManager ,
2020-03-24 12:02:22 +03:00
IAppBundleInformationParser appBundleInformationParser ,
2020-03-16 16:26:46 +03:00
ISimulatorsLoaderFactory simulatorsFactory ,
ISimpleListenerFactory simpleListenerFactory ,
IDeviceLoaderFactory devicesFactory ,
2020-03-20 13:42:43 +03:00
ICrashSnapshotReporterFactory snapshotReporterFactory ,
2020-03-19 01:39:10 +03:00
ICaptureLogFactory captureLogFactory ,
2020-03-19 20:38:35 +03:00
IDeviceLogCapturerFactory deviceLogCapturerFactory ,
2020-03-25 09:44:47 +03:00
ITestReporterFactory reporterFactory ,
2020-03-24 12:02:22 +03:00
TestTarget target ,
2020-03-16 16:26:46 +03:00
IHarness harness ,
ILog mainLog ,
2020-03-20 21:18:28 +03:00
ILogs logs ,
2020-03-16 16:26:46 +03:00
string projectFilePath ,
2020-03-20 21:18:28 +03:00
string buildConfiguration ,
2020-03-16 16:26:46 +03:00
ISimulatorDevice [ ] simulators = null ,
string deviceName = null ,
string companionDeviceName = null ,
bool ensureCleanSimulatorState = false ,
double timeoutMultiplier = 1 ,
string variation = null ,
BuildToolTask buildTask = null )
{
2020-03-24 12:02:22 +03:00
if ( appBundleInformationParser is null )
throw new ArgumentNullException ( nameof ( appBundleInformationParser ) ) ;
2020-03-29 19:02:03 +03:00
this . processManager = processManager ? ? throw new ArgumentNullException ( nameof ( processManager ) ) ;
2020-03-16 16:26:46 +03:00
this . simulatorsLoaderFactory = simulatorsFactory ? ? throw new ArgumentNullException ( nameof ( simulatorsFactory ) ) ;
this . listenerFactory = simpleListenerFactory ? ? throw new ArgumentNullException ( nameof ( simpleListenerFactory ) ) ;
this . devicesLoaderFactory = devicesFactory ? ? throw new ArgumentNullException ( nameof ( devicesFactory ) ) ;
2020-03-20 13:42:43 +03:00
this . snapshotReporterFactory = snapshotReporterFactory ? ? throw new ArgumentNullException ( nameof ( snapshotReporterFactory ) ) ;
2020-03-19 01:39:10 +03:00
this . captureLogFactory = captureLogFactory ? ? throw new ArgumentNullException ( nameof ( captureLogFactory ) ) ;
2020-03-19 20:38:35 +03:00
this . deviceLogCapturerFactory = deviceLogCapturerFactory ? ? throw new ArgumentNullException ( nameof ( deviceLogCapturerFactory ) ) ;
2020-03-25 09:44:47 +03:00
this . testReporterFactory = reporterFactory ? ? throw new ArgumentNullException ( nameof ( testReporterFactory ) ) ;
2020-03-16 16:26:46 +03:00
this . harness = harness ? ? throw new ArgumentNullException ( nameof ( harness ) ) ;
this . MainLog = mainLog ? ? throw new ArgumentNullException ( nameof ( mainLog ) ) ;
2020-03-20 21:18:28 +03:00
this . Logs = logs ? ? throw new ArgumentNullException ( nameof ( logs ) ) ;
2020-03-16 16:26:46 +03:00
this . timeoutMultiplier = timeoutMultiplier ;
this . deviceName = deviceName ;
this . companionDeviceName = companionDeviceName ;
this . ensureCleanSimulatorState = ensureCleanSimulatorState ;
this . simulators = simulators ;
2020-03-29 19:02:03 +03:00
this . buildTask = buildTask ;
2020-03-16 16:26:46 +03:00
this . target = target ;
2020-03-29 19:02:03 +03:00
runMode = target . ToRunMode ( ) ;
2020-03-16 16:26:46 +03:00
isSimulator = target . IsSimulator ( ) ;
2020-03-24 12:02:22 +03:00
AppInformation = appBundleInformationParser . ParseFromProject ( projectFilePath , target , buildConfiguration ) ;
2020-03-25 09:44:47 +03:00
AppInformation . Variation = variation ;
2020-03-11 12:38:03 +03:00
}
2016-11-16 17:23:11 +03:00
async Task < bool > FindSimulatorAsync ( )
2016-05-26 16:06:52 +03:00
{
2020-03-11 12:38:03 +03:00
if ( simulators ! = null )
2016-11-16 17:23:11 +03:00
return true ;
2020-03-25 17:59:29 +03:00
var sims = simulatorsLoaderFactory . CreateLoader ( ) ;
2020-03-18 19:10:25 +03:00
await sims . LoadAsync ( Logs . Create ( $"simulator-list-{Helpers.Timestamp}.log" , "Simulator list" ) , false , false ) ;
2020-03-16 16:26:46 +03:00
simulators = await sims . FindAsync ( target , MainLog ) ;
2016-05-26 16:06:52 +03:00
2020-03-11 12:38:03 +03:00
return simulators ! = null ;
2016-05-26 16:06:52 +03:00
}
void FindDevice ( )
{
2020-03-16 16:26:46 +03:00
if ( deviceName ! = null )
2016-05-26 16:06:52 +03:00
return ;
2020-03-25 17:59:29 +03:00
2020-03-16 16:26:46 +03:00
deviceName = Environment . GetEnvironmentVariable ( "DEVICE_NAME" ) ;
if ( ! string . IsNullOrEmpty ( deviceName ) )
2016-05-26 16:06:52 +03:00
return ;
2020-03-25 17:59:29 +03:00
2020-03-16 16:26:46 +03:00
var devs = devicesLoaderFactory . CreateLoader ( ) ;
2020-03-25 17:59:29 +03:00
Task . Run ( async ( ) = > {
2020-03-16 16:26:46 +03:00
await devs . LoadAsync ( MainLog , false , false ) ;
2016-06-06 13:48:53 +03:00
} ) . Wait ( ) ;
2016-05-26 16:06:52 +03:00
2020-03-16 16:26:46 +03:00
DeviceClass [ ] deviceClasses ;
2020-03-29 19:02:03 +03:00
switch ( runMode ) {
2020-03-16 16:26:46 +03:00
case RunMode . iOS :
deviceClasses = new [ ] { DeviceClass . iPhone , DeviceClass . iPad , DeviceClass . iPod } ;
2016-06-06 13:48:53 +03:00
break ;
2020-03-16 16:26:46 +03:00
case RunMode . WatchOS :
deviceClasses = new [ ] { DeviceClass . Watch } ;
2016-06-06 13:48:53 +03:00
break ;
2020-03-16 16:26:46 +03:00
case RunMode . TvOS :
deviceClasses = new [ ] { DeviceClass . AppleTV } ; // Untested
2016-06-06 13:48:53 +03:00
break ;
default :
2020-03-29 19:02:03 +03:00
throw new ArgumentException ( nameof ( runMode ) ) ;
2016-06-06 13:48:53 +03:00
}
2016-05-26 16:06:52 +03:00
2018-02-12 16:43:16 +03:00
var selected = devs . ConnectedDevices . Where ( ( v ) = > deviceClasses . Contains ( v . DeviceClass ) & & v . IsUsableForDebugging ! = false ) ;
2020-03-12 00:06:40 +03:00
IHardwareDevice selected_data ;
2016-06-06 13:48:53 +03:00
if ( selected . Count ( ) = = 0 ) {
2020-03-16 16:26:46 +03:00
throw new NoDeviceFoundException ( $"Could not find any applicable devices with device class(es): {string.Join (" , ", deviceClasses)}" ) ;
2016-06-06 13:48:53 +03:00
} else if ( selected . Count ( ) > 1 ) {
2016-12-22 20:55:25 +03:00
selected_data = selected
2020-03-25 17:59:29 +03:00
. OrderBy ( ( dev ) = > {
2020-03-11 12:38:03 +03:00
Version v ;
if ( Version . TryParse ( dev . ProductVersion , out v ) )
2016-12-22 20:55:25 +03:00
return v ;
return new Version ( ) ;
} )
. First ( ) ;
2020-03-16 16:26:46 +03:00
MainLog . WriteLine ( "Found {0} devices for device class(es) '{1}': '{2}'. Selected: '{3}' (because it has the lowest version)." , selected . Count ( ) , string . Join ( "', '" , deviceClasses ) , string . Join ( "', '" , selected . Select ( ( v ) = > v . Name ) . ToArray ( ) ) , selected_data . Name ) ;
2016-06-06 13:48:53 +03:00
} else {
selected_data = selected . First ( ) ;
}
2016-06-07 19:49:20 +03:00
2020-03-16 16:26:46 +03:00
deviceName = selected_data . Name ;
2016-05-26 16:06:52 +03:00
2020-03-29 19:02:03 +03:00
if ( runMode = = RunMode . WatchOS )
2020-03-16 16:26:46 +03:00
companionDeviceName = devs . FindCompanionDevice ( MainLog , selected_data ) . Name ;
2016-05-26 16:06:52 +03:00
}
2019-02-20 08:33:30 +03:00
public async Task < ProcessExecutionResult > InstallAsync ( CancellationToken cancellation_token )
2016-05-26 16:06:52 +03:00
{
if ( isSimulator ) {
// We reset the simulator when running, so a separate install step does not make much sense.
2020-03-16 16:26:46 +03:00
throw new InvalidOperationException ( "Installing to a simulator is not supported." ) ;
2016-05-26 16:06:52 +03:00
}
FindDevice ( ) ;
2020-03-25 17:59:29 +03:00
var args = new MlaunchArguments ( ) ;
2020-03-16 16:26:46 +03:00
for ( int i = - 1 ; i < harness . Verbosity ; i + + )
2020-03-25 17:59:29 +03:00
args . Add ( new VerbosityArgument ( ) ) ;
args . Add ( new InstallAppOnDeviceArgument ( AppInformation . AppPath ) ) ;
args . Add ( new DeviceNameArgument ( companionDeviceName ? ? deviceName ) ) ;
2016-05-26 16:06:52 +03:00
2020-03-29 19:02:03 +03:00
if ( runMode = = RunMode . WatchOS ) {
2020-03-25 17:59:29 +03:00
args . Add ( new DeviceArgument ( "ios,watchos" ) ) ;
2019-10-14 17:18:46 +03:00
}
2016-05-26 16:06:52 +03:00
2020-03-17 21:42:21 +03:00
var totalSize = Directory . GetFiles ( AppInformation . AppPath , "*" , SearchOption . AllDirectories ) . Select ( ( v ) = > new FileInfo ( v ) . Length ) . Sum ( ) ;
MainLog . WriteLine ( $"Installing '{AppInformation.AppPath}' to '{companionDeviceName ?? deviceName}'. Size: {totalSize} bytes = {totalSize / 1024.0 / 1024.0:N2} MB" ) ;
2017-10-12 18:08:54 +03:00
2020-03-29 19:02:03 +03:00
return await processManager . ExecuteCommandAsync ( args , MainLog , TimeSpan . FromHours ( 1 ) , cancellation_token : cancellation_token ) ;
2016-05-26 16:06:52 +03:00
}
2017-01-04 21:45:26 +03:00
public async Task < ProcessExecutionResult > UninstallAsync ( )
2017-01-02 10:58:46 +03:00
{
if ( isSimulator )
2020-03-16 16:26:46 +03:00
throw new InvalidOperationException ( "Uninstalling from a simulator is not supported." ) ;
2017-01-02 10:58:46 +03:00
FindDevice ( ) ;
2020-03-25 17:59:29 +03:00
var args = new MlaunchArguments ( ) ;
2020-03-16 16:26:46 +03:00
for ( int i = - 1 ; i < harness . Verbosity ; i + + )
2020-03-25 17:59:29 +03:00
args . Add ( new VerbosityArgument ( ) ) ;
2017-01-02 10:58:46 +03:00
2020-03-25 17:59:29 +03:00
args . Add ( new UninstallAppFromDeviceArgument ( AppInformation . BundleIdentifier ) ) ;
args . Add ( new DeviceNameArgument ( companionDeviceName ? ? deviceName ) ) ;
2017-01-02 10:58:46 +03:00
2020-03-29 19:02:03 +03:00
return await processManager . ExecuteCommandAsync ( args , MainLog , TimeSpan . FromMinutes ( 1 ) ) ;
2016-06-06 13:48:53 +03:00
}
2018-11-16 21:31:40 +03:00
2016-06-17 18:21:18 +03:00
public async Task < int > RunAsync ( )
2016-05-26 16:06:52 +03:00
{
2016-10-11 20:30:11 +03:00
if ( ! isSimulator )
FindDevice ( ) ;
2020-03-25 17:59:29 +03:00
var args = new MlaunchArguments ( ) ;
2020-03-20 21:18:28 +03:00
2020-03-16 16:26:46 +03:00
for ( int i = - 1 ; i < harness . Verbosity ; i + + )
2020-03-25 17:59:29 +03:00
args . Add ( new VerbosityArgument ( ) ) ;
args . Add ( new SetAppArgumentArgument ( "-connection-mode" ) ) ;
args . Add ( new SetAppArgumentArgument ( "none" ) ) ; // This will prevent the app from trying to connect to any IDEs
args . Add ( new SetAppArgumentArgument ( "-autostart" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_AUTOSTART" , true ) ) ;
args . Add ( new SetAppArgumentArgument ( "-autoexit" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_AUTOEXIT" , true ) ) ;
args . Add ( new SetAppArgumentArgument ( "-enablenetwork" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_ENABLE_NETWORK" , true ) ) ;
2016-11-15 21:04:37 +03:00
// detect if we are using a jenkins bot.
2020-03-16 16:26:46 +03:00
var useXmlOutput = harness . InCI ;
2017-07-11 09:58:47 +03:00
if ( useXmlOutput ) {
2020-03-25 17:59:29 +03:00
args . Add ( new SetEnvVariableArgument ( "NUNIT_ENABLE_XML_OUTPUT" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_ENABLE_XML_MODE" , "wrapped" ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_XML_VERSION" , "nunitv3" ) ) ;
2017-07-11 09:58:47 +03:00
}
2016-11-15 21:04:37 +03:00
2020-03-16 16:26:46 +03:00
if ( harness . InCI ) {
2019-07-01 20:02:56 +03:00
// We use the 'BUILD_REVISION' variable to detect whether we're running CI or not.
2020-03-25 19:38:10 +03:00
args . Add ( new SetEnvVariableArgument ( "BUILD_REVISION" , Environment . GetEnvironmentVariable ( "BUILD_REVISION" ) ) ) ;
2019-07-01 20:02:56 +03:00
}
2020-03-16 16:26:46 +03:00
if ( ! harness . GetIncludeSystemPermissionTests ( TestPlatform . iOS , ! isSimulator ) )
2020-03-25 17:59:29 +03:00
args . Add ( new SetEnvVariableArgument ( "DISABLE_SYSTEM_PERMISSION_TESTS" , 1 ) ) ;
2017-08-03 19:58:04 +03:00
2016-05-26 16:06:52 +03:00
if ( isSimulator ) {
2020-03-25 17:59:29 +03:00
args . Add ( new SetAppArgumentArgument ( "-hostname:127.0.0.1" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_HOSTNAME" , "127.0.0.1" ) ) ;
2016-05-26 16:06:52 +03:00
} else {
var ips = new StringBuilder ( ) ;
var ipAddresses = System . Net . Dns . GetHostEntry ( System . Net . Dns . GetHostName ( ) ) . AddressList ;
for ( int i = 0 ; i < ipAddresses . Length ; i + + ) {
if ( i > 0 )
ips . Append ( ',' ) ;
ips . Append ( ipAddresses [ i ] . ToString ( ) ) ;
}
2020-03-25 17:59:29 +03:00
var ipArg = ips . ToString ( ) ;
args . Add ( new SetAppArgumentArgument ( $"-hostname:{ipArg}" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_HOSTNAME" , ipArg ) ) ;
2016-05-26 16:06:52 +03:00
}
2020-03-29 19:02:03 +03:00
var listener_log = Logs . Create ( $"test-{runMode.ToString ().ToLowerInvariant ()}-{Helpers.Timestamp}.log" , LogType . TestLog . ToString ( ) , timestamp : ! useXmlOutput ) ;
var ( transport , listener , listenerTmpFile ) = listenerFactory . Create ( runMode , MainLog , listener_log , isSimulator , true , useXmlOutput ) ;
2020-03-25 19:38:10 +03:00
2020-03-25 17:59:29 +03:00
listener . Initialize ( ) ;
2017-06-26 13:47:37 +03:00
2020-03-25 17:59:29 +03:00
args . Add ( new SetAppArgumentArgument ( $"-transport:{transport}" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_TRANSPORT" , transport . ToString ( ) . ToUpper ( ) ) ) ;
2020-03-05 14:41:52 +03:00
2020-03-25 17:59:29 +03:00
if ( transport = = ListenerTransport . File )
args . Add ( new SetEnvVariableArgument ( "NUNIT_LOG_FILE" , listenerTmpFile ) ) ;
2016-05-26 16:06:52 +03:00
2020-03-25 17:59:29 +03:00
args . Add ( new SetAppArgumentArgument ( $"-hostport:{listener.Port}" , true ) ) ;
args . Add ( new SetEnvVariableArgument ( "NUNIT_HOSTPORT" , listener . Port ) ) ;
2016-05-26 16:06:52 +03:00
2017-01-04 21:45:26 +03:00
listener . StartAsync ( ) ;
2020-03-25 09:44:47 +03:00
// object that will take care of capturing and parsing the results
2020-03-29 19:02:03 +03:00
ILog runLog = MainLog ;
2020-03-25 09:44:47 +03:00
var crashLogs = new Logs ( Logs . Directory ) ;
2020-03-29 19:02:03 +03:00
2020-03-25 09:44:47 +03:00
ICrashSnapshotReporter crashReporter = snapshotReporterFactory . Create ( MainLog , crashLogs , isDevice : ! isSimulator , deviceName ) ;
2020-03-29 19:02:03 +03:00
var testReporterTimeout = TimeSpan . FromMinutes ( harness . Timeout * timeoutMultiplier ) ;
var testReporter = testReporterFactory . Create ( MainLog ,
runLog ,
Logs ,
crashReporter ,
listener ,
new XmlResultParser ( ) ,
AppInformation ,
runMode ,
harness . XmlJargon ,
deviceName ,
testReporterTimeout ,
harness . LaunchTimeout ,
buildTask ? . Logs ? . Directory ,
( level , message ) = > harness . Log ( level , message ) ) ;
2017-01-04 21:45:26 +03:00
2019-02-11 19:36:13 +03:00
listener . ConnectedTask
2020-03-16 16:26:46 +03:00
. TimeoutAfter ( TimeSpan . FromMinutes ( harness . LaunchTimeout ) )
2020-03-25 09:44:47 +03:00
. ContinueWith ( testReporter . LaunchCallback )
. DoNotAwait ( ) ;
2017-01-04 21:45:26 +03:00
2020-03-25 17:59:29 +03:00
args . AddRange ( harness . EnvironmentVariables . Select ( kvp = > new SetEnvVariableArgument ( kvp . Key , kvp . Value ) ) ) ;
2016-08-05 23:28:13 +03:00
2020-03-16 16:26:46 +03:00
if ( IsExtension ) {
2020-03-17 21:42:21 +03:00
switch ( AppInformation . Extension ) {
2017-01-04 21:45:26 +03:00
case Extension . TodayExtension :
2020-03-25 17:59:29 +03:00
args . Add ( isSimulator
? ( MlaunchArgument ) new LaunchSimulatorExtensionArgument ( AppInformation . LaunchAppPath , AppInformation . BundleIdentifier )
: new LaunchDeviceExtensionArgument ( AppInformation . LaunchAppPath , AppInformation . BundleIdentifier ) ) ;
2017-01-04 21:45:26 +03:00
break ;
case Extension . WatchKit2 :
default :
throw new NotImplementedException ( ) ;
}
} else {
2020-03-25 17:59:29 +03:00
args . Add ( isSimulator
? ( MlaunchArgument ) new LaunchSimulatorArgument ( AppInformation . LaunchAppPath )
: new LaunchDeviceArgument ( AppInformation . LaunchAppPath ) ) ;
2017-01-04 21:45:26 +03:00
}
2017-10-10 12:02:24 +03:00
if ( ! isSimulator )
2020-03-25 17:59:29 +03:00
args . Add ( new DisableMemoryLimitsArgument ( ) ) ;
2017-01-04 21:45:26 +03:00
2016-05-26 16:06:52 +03:00
if ( isSimulator ) {
2016-11-16 17:23:11 +03:00
if ( ! await FindSimulatorAsync ( ) )
return 1 ;
2016-06-17 18:21:18 +03:00
2020-03-29 19:02:03 +03:00
if ( runMode ! = RunMode . WatchOS ) {
2020-03-20 21:18:28 +03:00
var stderr_tty = harness . GetStandardErrorTty ( ) ;
2016-11-04 14:13:20 +03:00
if ( ! string . IsNullOrEmpty ( stderr_tty ) ) {
2020-03-25 17:59:29 +03:00
args . Add ( new SetStdoutArgument ( stderr_tty ) ) ;
args . Add ( new SetStderrArgument ( stderr_tty ) ) ;
2016-11-04 14:13:20 +03:00
} else {
2020-03-18 19:10:25 +03:00
var stdout_log = Logs . CreateFile ( $"stdout-{Helpers.Timestamp}.log" , "Standard output" ) ;
var stderr_log = Logs . CreateFile ( $"stderr-{Helpers.Timestamp}.log" , "Standard error" ) ;
2020-03-25 17:59:29 +03:00
args . Add ( new SetStdoutArgument ( stdout_log ) ) ;
args . Add ( new SetStderrArgument ( stderr_log ) ) ;
2016-11-04 14:13:20 +03:00
}
}
2020-03-19 01:39:10 +03:00
var systemLogs = new List < ICaptureLog > ( ) ;
2020-03-11 12:38:03 +03:00
foreach ( var sim in simulators ) {
2016-06-16 10:07:47 +03:00
// Upload the system log
2020-03-16 16:26:46 +03:00
MainLog . WriteLine ( "System log for the '{1}' simulator is: {0}" , sim . SystemLog , sim . Name ) ;
2016-06-17 18:21:18 +03:00
bool isCompanion = sim ! = simulator ;
2020-03-19 01:39:10 +03:00
var logDescription = isCompanion ? LogType . CompanionSystemLog . ToString ( ) : LogType . SystemLog . ToString ( ) ;
2020-03-26 16:59:43 +03:00
var log = captureLogFactory . Create (
2020-03-20 21:18:28 +03:00
Path . Combine ( Logs . Directory , sim . Name + ".log" ) ,
2020-03-19 01:39:10 +03:00
sim . SystemLog ,
harness . Action ! = HarnessAction . Jenkins ,
logDescription ) ;
2020-03-20 21:18:28 +03:00
2016-06-17 18:21:18 +03:00
log . StartCapture ( ) ;
Logs . Add ( log ) ;
systemLogs . Add ( log ) ;
2020-03-19 01:39:10 +03:00
WrenchLog . WriteLine ( "AddFile: {0}" , log . FullPath ) ;
2016-06-16 10:07:47 +03:00
}
2020-03-29 19:02:03 +03:00
MainLog . WriteLine ( "*** Executing {0}/{1} in the simulator ***" , AppInformation . AppName , runMode ) ;
2016-06-16 10:07:47 +03:00
2016-06-17 18:21:18 +03:00
if ( EnsureCleanSimulatorState ) {
2020-03-11 12:38:03 +03:00
foreach ( var sim in simulators )
2020-03-17 21:42:21 +03:00
await sim . PrepareSimulatorAsync ( MainLog , AppInformation . BundleIdentifier ) ;
2016-06-17 18:21:18 +03:00
}
2016-05-26 16:06:52 +03:00
2020-03-25 17:59:29 +03:00
args . Add ( new SimulatorUDIDArgument ( simulator . UDID ) ) ;
2016-05-26 16:06:52 +03:00
2020-03-20 21:18:28 +03:00
await crashReporter . StartCaptureAsync ( ) ;
2016-05-26 16:06:52 +03:00
2020-03-16 16:26:46 +03:00
MainLog . WriteLine ( "Starting test run" ) ;
2016-05-26 16:06:52 +03:00
2020-03-25 09:44:47 +03:00
await testReporter . CollectSimulatorResult (
2020-03-29 19:02:03 +03:00
processManager . ExecuteCommandAsync ( args , runLog , testReporterTimeout , cancellation_token : testReporter . CancellationToken ) ) ;
2016-05-26 16:06:52 +03:00
// cleanup after us
2016-06-17 18:21:18 +03:00
if ( EnsureCleanSimulatorState )
2020-03-19 20:37:21 +03:00
await simulator . KillEverythingAsync ( MainLog ) ;
2016-06-16 10:07:47 +03:00
foreach ( var log in systemLogs )
log . StopCapture ( ) ;
2020-03-20 21:18:28 +03:00
2016-05-26 16:06:52 +03:00
} else {
2020-03-29 19:02:03 +03:00
MainLog . WriteLine ( "*** Executing {0}/{1} on device '{2}' ***" , AppInformation . AppName , runMode , deviceName ) ;
2016-05-26 16:06:52 +03:00
2020-03-29 19:02:03 +03:00
if ( runMode = = RunMode . WatchOS ) {
2020-03-25 17:59:29 +03:00
args . Add ( new AttachNativeDebuggerArgument ( ) ) ; // this prevents the watch from backgrounding the app.
2017-01-04 21:45:26 +03:00
} else {
2020-03-25 17:59:29 +03:00
args . Add ( new WaitForExitArgument ( ) ) ;
2016-08-05 22:03:56 +03:00
}
2020-03-20 21:18:28 +03:00
2020-03-25 17:59:29 +03:00
args . Add ( new DeviceNameArgument ( deviceName ) ) ;
2016-05-26 16:06:52 +03:00
2020-03-20 13:42:43 +03:00
var deviceSystemLog = Logs . Create ( $"device-{deviceName}-{Helpers.Timestamp}.log" , "Device log" ) ;
2020-03-20 21:18:28 +03:00
var deviceLogCapturer = deviceLogCapturerFactory . Create ( harness . HarnessLog , deviceSystemLog , deviceName ) ;
2020-03-19 20:38:35 +03:00
deviceLogCapturer . StartCapture ( ) ;
2016-05-26 16:06:52 +03:00
2019-11-27 19:44:26 +03:00
try {
2020-03-20 21:18:28 +03:00
await crashReporter . StartCaptureAsync ( ) ;
2019-11-27 19:44:26 +03:00
2020-03-16 16:26:46 +03:00
MainLog . WriteLine ( "Starting test run" ) ;
2019-11-27 19:44:26 +03:00
// We need to check for MT1111 (which means that mlaunch won't wait for the app to exit).
2020-03-29 19:02:03 +03:00
var aggregatedLog = Log . CreateAggregatedLog ( testReporter . CallbackLog , MainLog ) ;
Task < ProcessExecutionResult > runTestTask = processManager . ExecuteCommandAsync (
args ,
aggregatedLog ,
testReporterTimeout ,
cancellation_token : testReporter . CancellationToken ) ;
await testReporter . CollectDeviceResult ( runTestTask ) ;
2019-11-27 19:44:26 +03:00
} finally {
2020-03-19 20:38:35 +03:00
deviceLogCapturer . StopCapture ( ) ;
deviceSystemLog . Dispose ( ) ;
2016-05-26 16:06:52 +03:00
}
// Upload the system log
2020-03-19 20:38:35 +03:00
if ( File . Exists ( deviceSystemLog . FullPath ) ) {
MainLog . WriteLine ( "A capture of the device log is: {0}" , deviceSystemLog . FullPath ) ;
WrenchLog . WriteLine ( "AddFile: {0}" , deviceSystemLog . FullPath ) ;
2016-05-26 16:06:52 +03:00
}
}
2018-05-15 16:07:45 +03:00
listener . Cancel ( ) ;
2016-05-26 16:06:52 +03:00
listener . Dispose ( ) ;
2020-03-25 09:44:47 +03:00
// check the final status, copy all the required data
( Result , FailureMessage ) = await testReporter . ParseResult ( ) ;
2020-03-29 19:02:03 +03:00
2020-03-25 09:44:47 +03:00
return testReporter . Success . Value ? 0 : 1 ;
2016-05-26 16:06:52 +03:00
}
}
2020-02-04 19:03:38 +03:00
}