[xharness] Fix simulator configuration to do all configuration before first launch.

This commit is contained in:
Rolf Bjarne Kvinge 2016-06-07 18:49:20 +02:00
Родитель 2d3001cd25
Коммит 0c1f235800
3 изменённых файлов: 190 добавлений и 70 удалений

Просмотреть файл

@ -224,10 +224,10 @@ namespace xharness
foreach (var service in sim_services) {
if (delete_first && !ExecuteCommand ("sqlite3", string.Format ("{0} \"DELETE FROM access WHERE service = '{1}' and client ='{2}';\"", TCC_db, service, bundle_identifier), true, output_verbosity_level: 1)) {
failure = true;
} else {
if (!ExecuteCommand ("sqlite3", string.Format ("{0} \"INSERT INTO access VALUES('{1}','{2}',0,1,0,NULL,NULL);\"", TCC_db, service, bundle_identifier), true, output_verbosity_level: 1)) {
failure = true;
}
}
if (!failure && !ExecuteCommand ("sqlite3", string.Format ("{0} \"INSERT INTO access VALUES('{1}','{2}',0,1,0,NULL,NULL);\"", TCC_db, service, bundle_identifier), true, output_verbosity_level: 1)) {
failure = true;
}
}
if (failure) {
@ -245,11 +245,11 @@ namespace xharness
}
}
void PrepareSimulator ()
public void PrepareSimulator ()
{
if (SkipSimulatorSetup) {
Harness.Log (0, "Simulator setup skipped.");
AgreeToPrompts (false);
Harness.Log (0, "Simulator setup skipped.");
return;
}
@ -308,8 +308,13 @@ namespace xharness
}
}
void Initialize ()
bool initialized;
public void Initialize ()
{
if (initialized)
return;
initialized = true;
var csproj = new XmlDocument ();
csproj.LoadWithoutNetworkAccess (ProjectFile);
appName = csproj.GetAssemblyName ();
@ -817,8 +822,12 @@ namespace xharness
ExecuteCommand ("killall", "-9 \"" + k + "\"", true, output_verbosity_level: 1);
}
static bool shown_simulator_list;
void ShowSimulatorList ()
{
if (shown_simulator_list)
return;
shown_simulator_list = true;
if (Harness.Verbosity > 0)
ExecuteXcodeCommand ("simctl", "list", ignore_errors: true, timeout: TimeSpan.FromSeconds (10));
}

Просмотреть файл

@ -41,7 +41,7 @@ namespace xharness
// Configure
public bool AutoConf { get; set; }
public bool Mac { get; set; }
public bool Mac { get; set; }
public string WatchOSContainerTemplate { get; set; }
public string WatchOSAppTemplate { get; set; }
public string WatchOSExtensionTemplate { get; set; }
@ -81,18 +81,23 @@ namespace xharness
}
}
string mlaunch;
public string MlaunchPath {
get {
var path = Path.GetFullPath (Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (RootDirectory)), "maccore", "tools", "mlaunch", "mlaunch"));
if (!File.Exists (path)) {
Log ("Could not find mlaunch locally ({0}), will try in Xamarin Studio.app.", path);
path = "/Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.IPhone/mlaunch.app/Contents/MacOS/mlaunch";
if (mlaunch == null) {
var path = Path.GetFullPath (Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (RootDirectory)), "maccore", "tools", "mlaunch", "mlaunch"));
if (!File.Exists (path)) {
Log ("Could not find mlaunch locally ({0}), will try in Xamarin Studio.app.", path);
path = "/Applications/Xamarin Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.IPhone/mlaunch.app/Contents/MacOS/mlaunch";
}
if (!File.Exists (path))
throw new FileNotFoundException (string.Format ("Could not find mlaunch: {0}", path));
mlaunch = path;
}
if (!File.Exists (path))
throw new FileNotFoundException (string.Format ("Could not find mlaunch: {0}", path));
return path;
return mlaunch;
}
}

Просмотреть файл

@ -23,7 +23,7 @@ namespace xharness
List<TestTask> Tasks = new List<TestTask> ();
internal static Resource DesktopResource = new Resource { Name = "Desktop" };
internal static Resource DesktopResource = new Resource ("Desktop", Environment.ProcessorCount);
async Task<IEnumerable<RunSimulatorTask>> CreateRunSimulatorTaskAsync (XBuildTask buildTask)
{
@ -155,12 +155,12 @@ namespace xharness
return "maroon";
else if (tests.Any ((v) => v.Failed))
return "red";
else if (tests.Any ((v) => v.ExecutionResult == TestExecutingResult.TimedOut))
else if (tests.Any ((v) => v.TimedOut))
return "purple";
else if (tests.Any ((v) => v.ExecutionState == TestExecutionState.Running))
return "blue";
else if (tests.Any ((v) => v.ExecutionState == TestExecutionState.NotStarted))
return "gray";
return "black";
else
return "black";
}
@ -169,7 +169,11 @@ namespace xharness
{
switch (test.ExecutionState) {
case TestExecutionState.NotStarted:
return "gray";
return "black";
case TestExecutionState.Building:
return "darkblue";
case TestExecutionState.Built:
return "lime";
case TestExecutionState.Running:
return "blue";
case TestExecutionState.Finished:
@ -184,6 +188,8 @@ namespace xharness
return "green";
case TestExecutingResult.TimedOut:
return "purple";
case TestExecutingResult.BuildFailure:
return "darkred";
case TestExecutingResult.None: // shouldn't happen
default:
return "pink";
@ -256,13 +262,14 @@ function toggleLogVisibility (logName)
} else {
state = test.ExecutionState.ToString ();
}
if (test.ExecutionState != TestExecutionState.NotStarted) {
//if (test.ExecutionState != TestExecutionState.NotStarted) {
var log_id = id_counter++;
writer.WriteLine ("{0} (<span style='color: {3}'>{1}</span>) <a id='button_{2}' href=\"javascript: toggleLogVisibility ('{2}');\">Show details</a><br />", test.Mode, state, log_id, GetTestColor (test));
writer.WriteLine ("<div id='logs_{0}' style='display: none; padding-bottom: 10px; padding-top: 10px; padding-left: 20px;'>", log_id);
writer.WriteLine ("Duration: {0} <br />", test.Duration);
if (test.Logs.Count > 0) {
foreach (var log in test.Logs) {
var logs = test.AggregatedLogs;
if (logs.Count () > 0) {
foreach (var log in logs) {
writer.WriteLine ("<a href='{0}' type='text/plain'>{1}</a><br />", log.Path.Substring (LogDirectory.Length + 1), log.Description);
if (log.Description == "Test log") {
var summary = string.Empty;
@ -298,9 +305,9 @@ function toggleLogVisibility (logName)
writer.WriteLine ("No logs<br />");
}
writer.WriteLine ("</div>");
} else {
writer.WriteLine ("{0} ({1}) <br />", test.Mode, state);
}
//} else {
// writer.WriteLine ("{0} ({1}) <br />", test.Mode, state);
//}
}
}
writer.WriteLine ("</body>");
@ -332,6 +339,8 @@ function toggleLogVisibility (logName)
public bool Succeeded { get { return ExecutionResult == TestExecutingResult.Succeeded; } }
public bool Failed { get { return ExecutionResult == TestExecutingResult.Failed; } }
public bool Crashed { get { return ExecutionResult == TestExecutingResult.Crashed; } }
public bool TimedOut { get { return ExecutionResult == TestExecutingResult.TimedOut; } }
public bool BuildFailure { get { return ExecutionResult == TestExecutingResult.BuildFailure; } }
public virtual string Mode { get; set; }
@ -368,24 +377,29 @@ function toggleLogVisibility (logName)
public LogFiles Logs = new LogFiles ();
public List<Resource> Resources = new List<Resource> ();
public virtual IEnumerable<LogFile> AggregatedLogs {
get {
return Logs;
}
}
public string LogDirectory {
get {
return Path.Combine (Jenkins.LogDirectory, TestName);
}
}
public async Task RunAsync ()
Task build_task;
async Task RunInternalAsync ()
{
if (ExecutionState == TestExecutionState.Finished)
return;
ExecutionState = TestExecutionState.Running;
Jenkins.GenerateReport ();
duration.Start ();
await ExecuteAsync ();
build_task = ExecuteAsync ();
await build_task;
duration.Stop ();
@ -396,6 +410,13 @@ function toggleLogVisibility (logName)
Jenkins.GenerateReport ();
}
public Task RunAsync ()
{
if (build_task == null)
build_task = RunInternalAsync ();
return build_task;
}
protected abstract Task ExecuteAsync ();
public abstract void WriteReport (StreamWriter writer);
}
@ -409,19 +430,21 @@ function toggleLogVisibility (logName)
protected override async Task ExecuteAsync ()
{
using (var xbuild = new Process ()) {
xbuild.StartInfo.FileName = "xbuild";
xbuild.StartInfo.Arguments = $"/verbosity:diagnostic /p:Platform={ProjectPlatform} /p:Configuration={ProjectConfiguration} {Harness.Quote (ProjectFile)}";
Harness.Log ("Building {0} ({1})", TestName, Mode);
var log = Logs.Create (LogDirectory, "build-" + Platform + ".txt", "Build log");
log.WriteLine ("{0} {1}", xbuild.StartInfo.FileName, xbuild.StartInfo.Arguments);
if (Harness.DryRun) {
Harness.Log ("{0} {1}", xbuild.StartInfo.FileName, xbuild.StartInfo.Arguments);
} else {
await xbuild.RunAsync (log.Path, true);
ExecutionResult = xbuild.ExitCode == 0 ? TestExecutingResult.Succeeded : TestExecutingResult.Failed;
using (var resource = await Jenkins.DesktopResource.AcquireConcurrentAsync ()) {
using (var xbuild = new Process ()) {
xbuild.StartInfo.FileName = "xbuild";
xbuild.StartInfo.Arguments = $"/verbosity:diagnostic /p:Platform={ProjectPlatform} /p:Configuration={ProjectConfiguration} {Harness.Quote (ProjectFile)}";
Harness.Log ("Building {0} ({1})", TestName, Mode);
var log = Logs.Create (LogDirectory, "build-" + Platform + ".txt", "Build log");
log.WriteLine ("{0} {1}", xbuild.StartInfo.FileName, xbuild.StartInfo.Arguments);
if (Harness.DryRun) {
Harness.Log ("{0} {1}", xbuild.StartInfo.FileName, xbuild.StartInfo.Arguments);
} else {
await xbuild.RunAsync (log.Path, true);
ExecutionResult = xbuild.ExitCode == 0 ? TestExecutingResult.Succeeded : TestExecutingResult.Failed;
}
Harness.Log ("Built {0} ({1})", TestName, Mode);
}
Harness.Log ("Built {0} ({1})", TestName, Mode);
}
}
@ -435,9 +458,28 @@ function toggleLogVisibility (logName)
{
public SimDevice Device;
public XBuildTask BuildTask;
public bool SkipSetupAndCleanup;
public string AppRunnerTarget;
AppRunner runner;
public async Task BuildAsync ()
{
ExecutionState = TestExecutionState.Building;
await BuildTask.RunAsync ();
if (BuildTask.ExecutionResult == TestExecutingResult.Succeeded) {
ExecutionState = TestExecutionState.Built;
} else {
ExecutionState = TestExecutionState.Finished;
ExecutionResult = TestExecutingResult.BuildFailure;
}
}
public override IEnumerable<LogFile> AggregatedLogs {
get {
return base.AggregatedLogs.Union (BuildTask.Logs);
}
}
public override string Mode {
get {
switch (Platform) {
@ -476,31 +518,39 @@ function toggleLogVisibility (logName)
}
}
protected override async Task ExecuteAsync ()
public Task PrepareSimulatorAsync (bool initialize)
{
if (BuildTask.ExecutionResult != TestExecutingResult.Succeeded)
return Task.FromResult (true);
runner = new AppRunner ()
{
Harness = Harness,
ProjectFile = ProjectFile,
SkipSimulatorSetup = !initialize,
SkipSimulatorCleanup = !initialize,
Target = AppRunnerTarget,
LogDirectory = LogDirectory,
};
runner.Simulators = new SimDevice [] { Device };
runner.Initialize ();
runner.PrepareSimulator ();
return Task.FromResult (true);
}
protected override Task ExecuteAsync ()
{
Harness.Log ("Running simulator '{0}' ({2}) for {1}", Device.Name, ProjectFile, Jenkins.Simulators.SupportedRuntimes.Where ((v) => v.Identifier == Device.SimRuntime).First ().Name);
await BuildTask.RunAsync ();
Logs.AddRange (BuildTask.Logs);
if (!BuildTask.Succeeded) {
ExecutionResult = TestExecutingResult.Failed;
return;
if (BuildTask.ExecutionResult != TestExecutingResult.Succeeded) {
ExecutionResult = TestExecutingResult.BuildFailure;
return Task.FromResult (true);
}
if (Harness.DryRun) {
Harness.Log ("<running app in simulator>");
} else {
var runner = new AppRunner ()
{
Harness = Harness,
ProjectFile = ProjectFile,
SkipSimulatorSetup = SkipSetupAndCleanup,
SkipSimulatorCleanup = SkipSetupAndCleanup,
Target = AppRunnerTarget,
LogDirectory = LogDirectory,
};
runner.Simulators = new SimDevice [] { Device };
try {
runner.Run ();
ExecutionResult = runner.Result;
@ -513,6 +563,8 @@ function toggleLogVisibility (logName)
foreach (var log in Logs)
Console.WriteLine ("Log: {0}: {1}", log.Description, log.Path);
return Task.FromResult (true);
}
public override void WriteReport (StreamWriter writer)
@ -534,6 +586,13 @@ function toggleLogVisibility (logName)
public IEnumerable<RunSimulatorTask> Tasks;
// Due to parallelization this isn't the same as the sum of the duration for all the build tasks.
Stopwatch build_timer = new Stopwatch ();
public TimeSpan BuildDuration { get { return build_timer.Elapsed; } }
Stopwatch run_timer = new Stopwatch ();
public TimeSpan RunDuration { get { return run_timer.Elapsed; } }
public AggregatedRunSimulatorTask (IEnumerable<RunSimulatorTask> tasks)
{
this.Tasks = tasks;
@ -541,14 +600,27 @@ function toggleLogVisibility (logName)
protected override async Task ExecuteAsync ()
{
using (var desktop = await Jenkins.DesktopResource.AcquireAsync ()) {
// First build everything. This is required for the run simulator
// task to properly configure the simulator.
build_timer.Start ();
await Task.WhenAll (Tasks.Select ((v) => v.BuildAsync ()).Distinct ());
build_timer.Stop ();
using (var desktop = await Jenkins.DesktopResource.AcquireExclusiveAsync ()) {
Harness.Log ("Preparing simulator: {0}", Device.Name);
// We need to set the dialog permissions for all the apps
// before launching the simulator, because once launched
// the simulator caches the values in-memory.
bool first = true;
foreach (var task in Tasks) {
task.SkipSetupAndCleanup = !first;
await task.PrepareSimulatorAsync (first);
first = false;
await task.RunAsync ();
}
run_timer.Start ();
foreach (var task in Tasks)
await task.RunAsync ();
run_timer.Stop ();
}
ExecutionResult = Tasks.Any ((v) => !v.Succeeded) ? TestExecutingResult.Failed : TestExecutingResult.Succeeded;
@ -572,19 +644,43 @@ function toggleLogVisibility (logName)
{
public string Name;
ConcurrentQueue<TaskCompletionSource<IDisposable>> queue = new ConcurrentQueue<TaskCompletionSource<IDisposable>> ();
ConcurrentQueue<TaskCompletionSource<IDisposable>> exclusive_queue = new ConcurrentQueue<TaskCompletionSource<IDisposable>> ();
int users;
int max_users = 1;
int max_concurrent_users = 1;
bool exclusive;
public Task<IDisposable> AcquireAsync ()
public Resource (string name, int max_concurrent_users = 1)
{
this.Name = name;
this.max_concurrent_users = max_concurrent_users;
}
public Task<IDisposable> AcquireConcurrentAsync ()
{
lock (queue) {
if (users == max_users) {
if (!exclusive && users < max_concurrent_users) {
users++;
return Task.FromResult<IDisposable> (new AcquiredResource (this));
} else {
var tcs = new TaskCompletionSource<IDisposable> (new AcquiredResource (this));
queue.Enqueue (tcs);
return tcs.Task;
} else {
}
}
}
public Task<IDisposable> AcquireExclusiveAsync ()
{
lock (queue) {
if (users == 0) {
users++;
exclusive = true;
return Task.FromResult<IDisposable> (new AcquiredResource (this));
} else {
var tcs = new TaskCompletionSource<IDisposable> (new AcquiredResource (this));
exclusive_queue.Enqueue (tcs);
return tcs.Task;
}
}
}
@ -595,8 +691,15 @@ function toggleLogVisibility (logName)
lock (queue) {
users--;
if (queue.TryDequeue (out tcs))
exclusive = false;
if (queue.TryDequeue (out tcs)) {
users++;
tcs.SetResult ((IDisposable) tcs.Task.AsyncState);
} else if (users == 0 && exclusive_queue.TryDequeue (out tcs)) {
users++;
exclusive = true;
tcs.SetResult ((IDisposable) tcs.Task.AsyncState);
}
}
}
@ -627,6 +730,8 @@ function toggleLogVisibility (logName)
public enum TestExecutionState
{
NotStarted,
Building,
Built,
Running,
Finished,
}
@ -639,6 +744,7 @@ function toggleLogVisibility (logName)
Failed,
TimedOut,
HarnessException,
BuildFailure,
}
}