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); }
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)); }
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);
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); }