private async Task <IEnumerable <ISimulatorDevice> > FindOrCreateDevicesAsync(ILog log, string runtime, string devicetype, bool force = false)
        {
            if (runtime is null)
            {
                throw new ArgumentNullException(nameof(runtime));
            }

            if (devicetype is null)
            {
                throw new ArgumentNullException(nameof(devicetype));
            }

            IEnumerable <ISimulatorDevice> devices;

            if (!force)
            {
                if (!_loaded)
                {
                    await LoadDevices(log);
                }

                devices = AvailableDevices.Where(v => v.SimRuntime == runtime && v.SimDeviceType == devicetype);
                if (devices.Any())
                {
                    return(devices);
                }
            }

            var rv = await _processManager.ExecuteXcodeCommandAsync("simctl", new[] { "create", CreateName(devicetype, runtime), devicetype, runtime }, log, TimeSpan.FromMinutes(1));

            if (!rv.Succeeded)
            {
                var message = $"Could not create device{Environment.NewLine}" +
                              $"runtime: {runtime}{Environment.NewLine}" +
                              $"device type: {devicetype}";
                log.WriteLine(message);
                throw new NoDeviceFoundException(message);
            }

            await LoadDevices(log, forceRefresh : true);

            devices = AvailableDevices.Where((ISimulatorDevice v) => v.SimRuntime == runtime && v.SimDeviceType == devicetype);
            if (!devices.Any())
            {
                var message = $"Simulator not found after creating it{Environment.NewLine}" +
                              $"runtime: {runtime}{Environment.NewLine}" +
                              $"device type: {devicetype}";
                log.WriteLine(message);
                throw new NoDeviceFoundException(message);
            }

            return(devices);
        }
Beispiel #2
0
        public async Task Erase(ILog log)
        {
            // here we don't care if execution fails.
            // erase the simulator (make sure the device isn't running first)
            await _processManager.ExecuteXcodeCommandAsync("simctl", new[] { "shutdown", UDID }, log, TimeSpan.FromMinutes(1));

            await _processManager.ExecuteXcodeCommandAsync("simctl", new[] { "erase", UDID }, log, TimeSpan.FromMinutes(1));

            // boot & shutdown to make sure it actually works
            await _processManager.ExecuteXcodeCommandAsync("simctl", new[] { "boot", UDID }, log, TimeSpan.FromMinutes(1));

            await _processManager.ExecuteXcodeCommandAsync("simctl", new[] { "shutdown", UDID }, log, TimeSpan.FromMinutes(1));
        }
Beispiel #3
0
 public Task <ProcessExecutionResult> UninstallSimulatorApp(ISimulatorDevice simulator, string appBundleId, CancellationToken cancellationToken = default)
 => _processManager.ExecuteXcodeCommandAsync(
     "simctl",
     new[] { "uninstall", simulator.UDID, appBundleId },
     _mainLog,
     TimeSpan.FromMinutes(3),
     cancellationToken: cancellationToken);
Beispiel #4
0
    public async Task <bool> AgreeToPromptsAsync(string simRuntime, string TCCDb, string udid, ILog log, params string[] bundleIdentifiers)
    {
        if (bundleIdentifiers == null || bundleIdentifiers.Length == 0)
        {
            log.WriteLine("No bundle identifiers given when requested permission editing.");
            return(false);
        }

        var sim_services = new string[]
        {
            "kTCCServiceAll",     // You'd think 'All' means all prompts, but some prompts still show up.
            "kTCCServiceAddressBook",
            "kTCCServiceCalendar",
            "kTCCServiceCamera",
            "kTCCServicePhotos",
            "kTCCServiceMediaLibrary",
            "kTCCServiceMicrophone",
            "kTCCServiceUbiquity",
            "kTCCServiceWillow"
        };

        var failure          = false;
        var tcc_edit_timeout = 3;
        var watch            = new Stopwatch();

        watch.Start();
        var format = GetTCCFormat(simRuntime);

        if (format >= 4)
        {
            // We don't care if booting fails (it'll fail if it's already booted for instance)
            await _processManager.ExecuteXcodeCommandAsync("simctl", new[] { "boot", udid }, log, TimeSpan.FromMinutes(1));

            // execute 'simctl privacy <udid> grant all <bundle identifier>' for each bundle identifier
            foreach (var bundle_identifier in bundleIdentifiers)
            {
                foreach (var bundle_id in new[] { bundle_identifier, bundle_identifier + ".watchkitapp" })
                {
                    foreach (var service in sim_services)
                    {
                        var args = new List <string>
                        {
                            "privacy",
                            udid,
                            "grant",
                            service,
                            bundle_id
                        };
                        var rv = await _processManager.ExecuteXcodeCommandAsync("simctl", args, log, TimeSpan.FromSeconds(30));

                        if (!rv.Succeeded)
                        {
                            failure = true;
                            break;
                        }
                    }
                }

                if (failure)
                {
                    break;
                }
            }
        }
        else
        {
            do
            {
                if (failure)
                {
                    log.WriteLine("Failed to edit TCC.db, trying again in 1 second... ", (int)(tcc_edit_timeout - watch.Elapsed.TotalSeconds));
                    await Task.Delay(TimeSpan.FromSeconds(1));
                }
                failure = false;
                foreach (var bundle_identifier in bundleIdentifiers)
                {
                    var args = new List <string>();
                    var sql  = new System.Text.StringBuilder("\n");
                    args.Add(TCCDb);
                    foreach (var bundle_id in new[] { bundle_identifier, bundle_identifier + ".watchkitapp" })
                    {
                        foreach (var service in sim_services)
                        {
                            switch (format)
                            {
                            case 1:
                                // CREATE TABLE access (service TEXT NOT NULL, client TEXT NOT NULL, client_type INTEGER NOT NULL, allowed INTEGER NOT NULL, prompt_count INTEGER NOT NULL, csreq BLOB, CONSTRAINT key PRIMARY KEY (service, client, client_type));
                                sql.AppendFormat("DELETE FROM access WHERE service = '{0}' AND client = '{1}';\n", service, bundle_id);
                                sql.AppendFormat("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL);\n", service, bundle_id);
                                break;

                            case 2:
                                // CREATE TABLE access (service	TEXT NOT NULL, client TEXT NOT NULL, client_type INTEGER NOT NULL, allowed INTEGER NOT NULL, prompt_count INTEGER NOT NULL, csreq BLOB, policy_id INTEGER, PRIMARY KEY (service, client, client_type), FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE ON UPDATE CASCADE);
                                sql.AppendFormat("DELETE FROM access WHERE service = '{0}' AND client = '{1}';\n", service, bundle_id);
                                sql.AppendFormat("INSERT INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL);\n", service, bundle_id);
                                break;

                            case 3:     // Xcode 10+
                                        // CREATE TABLE access (service TEXT NOT NULL, client TEXT NOT NULL, client_type INTEGER NOT NULL, allowed INTEGER NOT NULL, prompt_count INTEGER NOT NULL, csreq BLOB, policy_id INTEGER, indirect_object_identifier_type INTEGER, indirect_object_identifier TEXT, indirect_object_code_identity BLOB, flags INTEGER, last_modified  INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER)), PRIMARY KEY (service, client, client_type, indirect_object_identifier), FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE ON UPDATE CASCADE)
                                sql.AppendFormat("INSERT OR REPLACE INTO access VALUES('{0}','{1}',0,1,0,NULL,NULL,NULL,'UNUSED',NULL,NULL,{2});\n", service, bundle_id, DateTimeOffset.Now.ToUnixTimeSeconds());
                                break;

                            default:
                                throw new NotImplementedException();
                            }
                        }
                    }

                    args.Add(sql.ToString());

                    var rv = await _processManager.ExecuteCommandAsync("sqlite3", args, log, TimeSpan.FromSeconds(5));

                    if (!rv.Succeeded)
                    {
                        failure = true;
                        break;
                    }
                }
            } while (failure && watch.Elapsed.TotalSeconds <= tcc_edit_timeout);
        }

        if (failure)
        {
            log.WriteLine("Failed to edit TCC.db, the test run might hang due to permission request dialogs");
        }
        else
        {
            log.WriteLine("Successfully edited TCC.db");
        }

        log.WriteLine("Current TCC database contents:");
        await _processManager.ExecuteCommandAsync("sqlite3", new[] { TCCDb, ".dump" }, log, TimeSpan.FromSeconds(5));

        return(!failure);
    }