Esempio n. 1
0
        protected override Task <ExitCode> InvokeInternal(ILogger logger)
        {
            logger.LogDebug($"Android Test command called: App = {_arguments.AppPackagePath}{Environment.NewLine}Instrumentation Name = {_arguments.InstrumentationName}");
            logger.LogDebug($"Output Directory:{_arguments.OutputDirectory}{Environment.NewLine}Timeout = {_arguments.Timeout.TotalSeconds} seconds.");
            logger.LogDebug("Arguments to instrumentation:");

            if (!File.Exists(_arguments.AppPackagePath))
            {
                logger.LogCritical($"Couldn't find {_arguments.AppPackagePath}!");
                return(Task.FromResult(ExitCode.PACKAGE_NOT_FOUND));
            }
            var runner = new AdbRunner(logger);

            // Assumption: APKs we test will only have one arch for now
            string apkRequiredArchitecture;

            if (!string.IsNullOrEmpty(_arguments.DeviceArchitecture))
            {
                apkRequiredArchitecture = _arguments.DeviceArchitecture;
                logger.LogInformation($"Will attempt to run device on specified architecture: '{apkRequiredArchitecture}'");
            }
            else
            {
                apkRequiredArchitecture = ApkHelper.GetApkSupportedArchitectures(_arguments.AppPackagePath).First();
                logger.LogInformation($"Will attempt to run device on detected architecture: '{apkRequiredArchitecture}'");
            }

            // Package Name is not guaranteed to match file name, so it needs to be mandatory.
            string apkPackageName = _arguments.PackageName;

            int instrumentationExitCode = (int)ExitCode.GENERAL_FAILURE;

            try
            {
                using (logger.BeginScope("Initialization and setup of APK on device"))
                {
                    // Make sure the adb server is freshly started
                    runner.KillAdbServer();
                    runner.StartAdbServer();

                    // Wait til at least device(s) are ready
                    runner.WaitForDevice();

                    // enumerate the devices attached and their architectures
                    // Tell ADB to only use that one (will always use the present one for systems w/ only 1 machine)
                    runner.SetActiveDevice(GetDeviceToUse(logger, runner, apkRequiredArchitecture));

                    // Empty log as we'll be uploading the full logcat for this execution
                    runner.ClearAdbLog();

                    logger.LogDebug($"Working with {runner.GetAdbVersion()}");

                    // If anything changed about the app, Install will fail; uninstall it first.
                    // (we'll ignore if it's not present)
                    // This is where mismatched architecture APKs fail.
                    runner.UninstallApk(apkPackageName);
                    if (runner.InstallApk(_arguments.AppPackagePath) != 0)
                    {
                        logger.LogCritical("Install failure: Test command cannot continue");
                        return(Task.FromResult(ExitCode.PACKAGE_INSTALLATION_FAILURE));
                    }
                    runner.KillApk(apkPackageName);
                }

                // No class name = default Instrumentation
                (string stdOut, _, int exitCode) = runner.RunApkInstrumentation(apkPackageName, _arguments.InstrumentationName, _arguments.InstrumentationArguments, _arguments.Timeout);

                using (logger.BeginScope("Post-test copy and cleanup"))
                {
                    if (exitCode == (int)ExitCode.SUCCESS)
                    {
                        (var resultValues, var instrExitCode) = ParseInstrumentationOutputs(logger, stdOut);

                        instrumentationExitCode = instrExitCode;

                        foreach (string possibleResultKey in _xmlOutputVariableNames)
                        {
                            if (resultValues.ContainsKey(possibleResultKey))
                            {
                                logger.LogInformation($"Found XML result file: '{resultValues[possibleResultKey]}'(key: {possibleResultKey})");
                                runner.PullFiles(resultValues[possibleResultKey], _arguments.OutputDirectory);
                            }
                        }
                    }

                    // Optionally copy off an entire folder
                    if (!string.IsNullOrEmpty(_arguments.DeviceOutputFolder))
                    {
                        var logs = runner.PullFiles(_arguments.DeviceOutputFolder, _arguments.OutputDirectory);
                        foreach (string log in logs)
                        {
                            logger.LogDebug($"Found output file: {log}");
                        }
                    }
                    runner.DumpAdbLog(Path.Combine(_arguments.OutputDirectory, $"adb-logcat-{_arguments.PackageName}.log"));
                    runner.UninstallApk(apkPackageName);
                }

                if (instrumentationExitCode != (int)ExitCode.SUCCESS)
                {
                    logger.LogError($"Non-success instrumentation exit code: {instrumentationExitCode}");
                }
                else
                {
                    return(Task.FromResult(ExitCode.SUCCESS));
                }
            }
            catch (Exception toLog)
            {
                logger.LogCritical(toLog, $"Failure to run test package: {toLog.Message}");
            }
            finally
            {
                runner.KillAdbServer();
            }

            return(Task.FromResult(ExitCode.GENERAL_FAILURE));
        }
Esempio n. 2
0
        protected override Task <ExitCode> InvokeInternal(ILogger logger)
        {
            logger.LogDebug($"Android Test command called: App = {_arguments.AppPackagePath}{Environment.NewLine}Instrumentation Name = {_arguments.InstrumentationName}");
            logger.LogDebug($"Output Directory:{_arguments.OutputDirectory}{Environment.NewLine}Timeout = {_arguments.Timeout.TotalSeconds} seconds.");
            logger.LogDebug("Arguments to instrumentation:");

            if (!File.Exists(_arguments.AppPackagePath))
            {
                logger.LogCritical($"Couldn't find {_arguments.AppPackagePath}!");
                return(Task.FromResult(ExitCode.PACKAGE_NOT_FOUND));
            }
            var runner = new AdbRunner(logger);

            // Package Name is not guaranteed to match file name, so it needs to be mandatory.
            string apkPackageName = _arguments.PackageName;

            int instrumentationExitCode = (int)ExitCode.GENERAL_FAILURE;

            try
            {
                using (logger.BeginScope("Initialization and setup of APK on device"))
                {
                    runner.KillAdbServer();
                    runner.StartAdbServer();
                    runner.WaitForDevice();
                    runner.ClearAdbLog();

                    logger.LogDebug($"Working with {runner.GetAdbVersion()}");

                    // If anything changed about the app, Install will fail; uninstall it first.
                    // (we'll ignore if it's not present)
                    runner.UninstallApk(apkPackageName);
                    if (runner.InstallApk(_arguments.AppPackagePath) != 0)
                    {
                        logger.LogCritical("Install failure: Test command cannot continue");
                        return(Task.FromResult(ExitCode.PACKAGE_INSTALLATION_FAILURE));
                    }
                    runner.KillApk(apkPackageName);
                }

                // No class name = default Instrumentation
                (string stdOut, _, int exitCode) = runner.RunApkInstrumentation(apkPackageName, _arguments.InstrumentationName, _arguments.InstrumentationArguments, _arguments.Timeout);

                using (logger.BeginScope("Post-test copy and cleanup"))
                {
                    if (exitCode == (int)ExitCode.SUCCESS)
                    {
                        (var resultValues, var instrExitCode) = ParseInstrumentationOutputs(logger, stdOut);

                        instrumentationExitCode = instrExitCode;

                        foreach (string possibleResultKey in _xmlOutputVariableNames)
                        {
                            if (resultValues.ContainsKey(possibleResultKey))
                            {
                                logger.LogInformation($"Found XML result file: '{resultValues[possibleResultKey]}'(key: {possibleResultKey})");
                                runner.PullFiles(resultValues[possibleResultKey], _arguments.OutputDirectory);
                            }
                        }
                    }

                    // Optionally copy off an entire folder
                    if (!string.IsNullOrEmpty(_arguments.DeviceOutputFolder))
                    {
                        var logs = runner.PullFiles(_arguments.DeviceOutputFolder, _arguments.OutputDirectory);
                        foreach (string log in logs)
                        {
                            logger.LogDebug($"Detected output file: {log}");
                        }
                    }
                    runner.DumpAdbLog(Path.Combine(_arguments.OutputDirectory, $"adb-logcat-{_arguments.PackageName}.log"));
                    runner.UninstallApk(apkPackageName);
                }

                if (instrumentationExitCode != (int)ExitCode.SUCCESS)
                {
                    logger.LogError($"Non-success instrumentation exit code: {instrumentationExitCode}");
                }
                else
                {
                    return(Task.FromResult(ExitCode.SUCCESS));
                }
            }
            catch (Exception toLog)
            {
                logger.LogCritical(toLog, $"Failure to run test package: {toLog.Message}");
            }
            finally
            {
                runner.KillAdbServer();
            }

            return(Task.FromResult(ExitCode.GENERAL_FAILURE));
        }
Esempio n. 3
0
        protected override Task <int> InvokeInternal()
        {
            _log.LogDebug($"Android Test command called: App = {_arguments.AppPackagePath}{Environment.NewLine}Instrumentation Name = {_arguments.InstrumentationName}");
            _log.LogDebug($"Output Directory:{_arguments.OutputDirectory}{Environment.NewLine}Working Directory = {_arguments.WorkingDirectory}{Environment.NewLine}Timeout = {_arguments.Timeout.TotalSeconds} seconds.");
            _log.LogDebug("Arguments to instrumentation:");

            if (!File.Exists(_arguments.AppPackagePath))
            {
                _log.LogCritical($"Couldn't find {_arguments.AppPackagePath}!");
                return(Task.FromResult((int)ExitCodes.PACKAGE_NOT_FOUND));
            }
            var runner = new AdbRunner(_log);

            // Package Name is not guaranteed to match file name, so it needs to be mandatory.
            string apkPackageName = _arguments.PackageName;

            try
            {
                using (_log.BeginScope("Initialization and setup of APK on device"))
                {
                    runner.KillAdbServer();
                    runner.StartAdbServer();
                    runner.ClearAdbLog();

                    _log.LogDebug($"Working with {runner.GetAdbVersion()}");

                    // If anything changed about the app, Install will fail; uninstall it first.
                    // (we'll ignore if it's not present)
                    runner.UninstallApk(apkPackageName);
                    if (runner.InstallApk(_arguments.AppPackagePath) != 0)
                    {
                        _log.LogCritical("Install failure: Test command cannot continue");
                        return(Task.FromResult((int)ExitCodes.PACKAGE_INSTALLATION_FAILURE));
                    }
                    runner.KillApk(apkPackageName);
                }

                // No class name = default Instrumentation
                runner.RunApkInstrumentation(apkPackageName, _arguments.InstrumentationName, _arguments.InstrumentationArguments, _arguments.Timeout);

                using (_log.BeginScope("Post-test copy and cleanup"))
                {
                    if (!string.IsNullOrEmpty(_arguments.DeviceOutputFolder))
                    {
                        var logs = runner.PullFiles(_arguments.DeviceOutputFolder, _arguments.OutputDirectory);
                        foreach (string log in logs)
                        {
                            _log.LogDebug($"Detected output file: {log}");
                        }
                    }
                    runner.DumpAdbLog(Path.Combine(_arguments.OutputDirectory, $"adb-logcat-{_arguments.PackageName}.log"));
                    runner.UninstallApk(apkPackageName);
                }

                return(Task.FromResult((int)ExitCodes.SUCCESS));
            }
            catch (Exception toLog)
            {
                _log.LogCritical(toLog, $"Failure to run test package: {toLog.Message}");
            }
            finally
            {
                runner.KillAdbServer();
            }

            return(Task.FromResult((int)ExitCodes.GENERAL_FAILURE));
        }
Esempio n. 4
0
        protected override Task <int> InvokeInternal()
        {
            _log.LogDebug($"Android Test command called: App = {_arguments.AppPackagePath}{Environment.NewLine}Instrumentation Name = {_arguments.InstrumentationName}");
            _log.LogDebug($"Output Directory:{_arguments.OutputDirectory}{Environment.NewLine}Working Directory = {_arguments.WorkingDirectory}{Environment.NewLine}Timeout = {_arguments.Timeout.TotalSeconds} seconds.");
            _log.LogDebug("Arguments to instrumentation:");

            if (!File.Exists(_arguments.AppPackagePath))
            {
                _log.LogCritical($"Couldn't find {_arguments.AppPackagePath}!");
                return(Task.FromResult((int)ExitCodes.PACKAGE_NOT_FOUND));
            }
            var    runner  = new AdbRunner(_log);
            string apkName = Path.GetFileNameWithoutExtension(_arguments.AppPackagePath);

            try
            {
                using (_log.BeginScope("Initialization and setup of APK on device"))
                {
                    runner.KillAdbServer();
                    runner.StartAdbServer();
                    runner.ClearAdbLog();

                    _log.LogDebug($"Working with {runner.GetAdbVersion()}");

                    // If anything changed about the app, Install will fail; uninstall it first.
                    // (we'll ignore if it's not present)
                    runner.UninstallApk(apkName);
                    if (runner.InstallApk(_arguments.AppPackagePath) != 0)
                    {
                        _log.LogCritical("Install failure: Test command cannot continue");
                        return(Task.FromResult((int)ExitCodes.PACKAGE_INSTALLATION_FAILURE));
                    }
                    runner.KillApk(apkName);

                    // App needs to be able to read and write the storage folders we use for IO
                    runner.GrantPermissions(apkName,
                                            new string[] { "android.permission.READ_EXTERNAL_STORAGE",
                                                           "android.permission.WRITE_EXTERNAL_STORAGE" });
                }

                // No class name = default Instrumentation
                runner.RunApkInstrumentation(apkName, _arguments.InstrumentationName, _arguments.InstrumentationArguments);

                using (_log.BeginScope("Post-test copy and cleanup"))
                {
                    var logs = runner.PullFiles("/sdcard/Documents/helix-results", _arguments.OutputDirectory);
                    foreach (string log in logs)
                    {
                        _log.LogDebug($"Detected output file: {log}");
                    }
                    runner.DumpAdbLog(Path.Combine(_arguments.OutputDirectory, "adb-logcat.log"));
                    runner.UninstallApk(apkName);
                }

                return(Task.FromResult((int)ExitCodes.SUCCESS));
            }
            catch (Exception toLog)
            {
                _log.LogCritical(toLog, $"Failure to run test package: {toLog.Message}");
            }
            finally
            {
                runner.KillAdbServer();
            }

            return(Task.FromResult((int)ExitCodes.GENERAL_FAILURE));
        }
Esempio n. 5
0
    public ExitCode RunApkInstrumentation(
        string apkPackageName,
        string?instrumentationName,
        Dictionary <string, string> instrumentationArguments,
        string outputDirectory,
        string?deviceOutputFolder,
        TimeSpan timeout,
        int expectedExitCode)
    {
        int?instrumentationExitCode = null;

        // No class name = default Instrumentation
        ProcessExecutionResults result = _runner.RunApkInstrumentation(apkPackageName, instrumentationName, instrumentationArguments, timeout);

        bool processCrashed      = false;
        bool failurePullingFiles = false;
        bool logCatSucceeded;

        using (_logger.BeginScope("Post-test copy and cleanup"))
        {
            if (result.ExitCode == (int)ExitCode.SUCCESS)
            {
                (instrumentationExitCode, processCrashed, failurePullingFiles) = ParseInstrumentationResult(apkPackageName, outputDirectory, result.StandardOutput);
            }

            // Optionally copy off an entire folder
            if (!string.IsNullOrEmpty(deviceOutputFolder))
            {
                try
                {
                    var logs = _runner.PullFiles(apkPackageName, deviceOutputFolder, outputDirectory);
                    foreach (string log in logs)
                    {
                        _logger.LogDebug($"Found output file: {log}");
                    }
                }
                catch (Exception toLog)
                {
                    _logger.LogError(toLog, "Hit error (typically permissions) trying to pull {filePathOnDevice}", deviceOutputFolder);
                    failurePullingFiles = true;
                }
            }

            logCatSucceeded = _runner.TryDumpAdbLog(Path.Combine(outputDirectory, $"adb-logcat-{apkPackageName}-{(instrumentationName ?? "default")}.log"));

            if (processCrashed)
            {
                _runner.DumpBugReport(Path.Combine(outputDirectory, $"adb-bugreport-{apkPackageName}"));
            }
        }

        // In case emulator crashes halfway through, we can tell by failing to pull ADB logs from it
        if (!logCatSucceeded)
        {
            return(ExitCode.SIMULATOR_FAILURE);
        }

        if (result.ExitCode == (int)AdbExitCodes.INSTRUMENTATION_TIMEOUT)
        {
            return(ExitCode.TIMED_OUT);
        }

        if (processCrashed)
        {
            return(ExitCode.APP_CRASH);
        }

        if (failurePullingFiles)
        {
            _logger.LogError($"Received expected instrumentation exit code ({instrumentationExitCode}), " +
                             "but we hit errors pulling files from the device (see log for details.)");
            return(ExitCode.DEVICE_FILE_COPY_FAILURE);
        }

        if (!instrumentationExitCode.HasValue)
        {
            return(ExitCode.RETURN_CODE_NOT_SET);
        }

        if (instrumentationExitCode != expectedExitCode)
        {
            _logger.LogError($"Non-success instrumentation exit code: {instrumentationExitCode}, expected: {expectedExitCode}");
            return(ExitCode.TESTS_FAILED);
        }

        return(ExitCode.SUCCESS);
    }