public void TearDown()
 {
     processManager = null;
     resultParser   = null;
     configuration  = null;
     harness        = null;
     jenkins        = null;
     factory        = null;
 }
Example #2
0
 public MacTestTasksEnumerable(Jenkins jenkins,
                               IMlaunchProcessManager processManager,
                               ICrashSnapshotReporterFactory crashReportSnapshotFactory,
                               ITestVariationsFactory testVariationsFactory)
 {
     this.jenkins                    = jenkins ?? throw new ArgumentNullException(nameof(jenkins));
     this.processManager             = processManager ?? throw new ArgumentNullException(nameof(processManager));
     this.crashReportSnapshotFactory = crashReportSnapshotFactory ?? throw new ArgumentNullException(nameof(crashReportSnapshotFactory));
     this.testVariationsFactory      = testVariationsFactory ?? throw new ArgumentNullException(nameof(testVariationsFactory));
 }
        public void SetUp()
        {
            processManager = new Mock <IMlaunchProcessManager> ();
            resultParser   = new Mock <IResultParser> ();
            tunnel         = new Mock <ITunnelBore> ();
            configuration  = new HarnessConfiguration();
            harness        = new Harness(resultParser.Object, HarnessAction.Jenkins, configuration);
            jenkins        = new Xharness.Jenkins.Jenkins(harness, processManager.Object, resultParser.Object, tunnel.Object);

            factory = new MakeTestTaskEnumerable(jenkins, processManager.Object);
        }
Example #4
0
        public void SetUp()
        {
            processManager  = new Mock <IMlaunchProcessManager> ();
            resultParser    = new Mock <IResultParser> ();
            tunnel          = new Mock <ITunnelBore> ();
            log             = new Mock <IFileBackedLog> ();
            configuration   = new HarnessConfiguration();
            harness         = new Harness(resultParser.Object, HarnessAction.Jenkins, configuration);
            jenkins         = new Xharness.Jenkins.Jenkins(harness, processManager.Object, resultParser.Object, tunnel.Object);
            jenkins.MainLog = log.Object;

            factory = new NUnitTestTasksEnumerable(jenkins, processManager.Object);
        }
Example #5
0
        public int Jenkins()
        {
            if (autoConf)
            {
                AutoConfigureIOS();
                AutoConfigureMac(false);
            }

            var jenkins = new Jenkins.Jenkins()
            {
                Harness = this,
            };

            return(jenkins.Run());
        }
Example #6
0
        public Task <IEnumerable <ITestTask> > CreateAsync(Jenkins jenkins, IProcessManager processManager, TestVariationsFactory testVariationsFactory)
        {
            var rv           = new List <RunDeviceTask> ();
            var projectTasks = new List <RunDeviceTask> ();

            foreach (var project in jenkins.Harness.IOSTestProjects)
            {
                if (!project.IsExecutableProject)
                {
                    continue;
                }

                if (project.SkipDeviceVariations)
                {
                    continue;
                }

                bool ignored = !jenkins.IncludeDevice;
                if (!jenkins.IsIncluded(project))
                {
                    ignored = true;
                }

                projectTasks.Clear();

                bool createiOS;
                bool createTodayExtension;
                bool createtvOS;
                bool createwatchOS;

                if (project.GenerateVariations)
                {
                    createiOS            = !project.SkipiOSVariation;
                    createTodayExtension = !project.SkipTodayExtensionVariation;
                    createtvOS           = !project.SkiptvOSVariation;
                    createwatchOS        = !project.SkipwatchOSVariation;
                }
                else
                {
                    createiOS            = project.TestPlatform == TestPlatform.iOS_Unified;
                    createTodayExtension = project.TestPlatform == TestPlatform.iOS_TodayExtension64;
                    createtvOS           = project.TestPlatform == TestPlatform.tvOS;
                    createwatchOS        = project.TestPlatform == TestPlatform.watchOS;
                }

                if (createiOS)
                {
                    var build64 = new MSBuildTask(jenkins: jenkins, testProject: project, processManager: processManager)
                    {
                        ProjectConfiguration = "Debug64",
                        ProjectPlatform      = "iPhone",
                        Platform             = TestPlatform.iOS_Unified64,
                        TestName             = project.Name,
                    };
                    build64.CloneTestProject(jenkins.MainLog, processManager, project);
                    projectTasks.Add(new RunDeviceTask(
                                         jenkins: jenkins,
                                         devices: jenkins.Devices,
                                         buildTask: build64,
                                         processManager: processManager,
                                         tunnelBore: jenkins.TunnelBore,
                                         errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                         useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                         candidates: jenkins.Devices.Connected64BitIOS.Where(d => project.IsSupported(d.DevicePlatform, d.ProductVersion)))
                    {
                        Ignored = !jenkins.IncludeiOS64
                    });

                    var build32 = new MSBuildTask(jenkins: jenkins, testProject: project, processManager: processManager)
                    {
                        ProjectConfiguration = project.Name != "dont link" ? "Debug32" : "Release32",
                        ProjectPlatform      = "iPhone",
                        Platform             = TestPlatform.iOS_Unified32,
                        TestName             = project.Name,
                    };
                    build32.CloneTestProject(jenkins.MainLog, processManager, project);
                    projectTasks.Add(new RunDeviceTask(
                                         jenkins: jenkins,
                                         devices: jenkins.Devices,
                                         buildTask: build32,
                                         processManager: processManager,
                                         tunnelBore: jenkins.TunnelBore,
                                         errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                         useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                         candidates: jenkins.Devices.Connected32BitIOS.Where(d => project.IsSupported(d.DevicePlatform, d.ProductVersion)))
                    {
                        Ignored = !jenkins.IncludeiOS32
                    });

                    if (createTodayExtension)
                    {
                        var todayProject = project.GenerateVariations ? project.AsTodayExtensionProject() : project;
                        var buildToday   = new MSBuildTask(jenkins: jenkins, testProject: todayProject, processManager: processManager)
                        {
                            ProjectConfiguration = "Debug64",
                            ProjectPlatform      = "iPhone",
                            Platform             = TestPlatform.iOS_TodayExtension64,
                            TestName             = project.Name,
                        };
                        buildToday.CloneTestProject(jenkins.MainLog, processManager, todayProject);
                        projectTasks.Add(new RunDeviceTask(
                                             jenkins: jenkins,
                                             devices: jenkins.Devices,
                                             buildTask: buildToday,
                                             processManager: processManager,
                                             tunnelBore: jenkins.TunnelBore,
                                             errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                             useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                             candidates: jenkins.Devices.Connected64BitIOS.Where(d => project.IsSupported(d.DevicePlatform, d.ProductVersion)))
                        {
                            Ignored = !jenkins.IncludeiOSExtensions, BuildOnly = jenkins.ForceExtensionBuildOnly
                        });
                    }
                }

                if (createtvOS)
                {
                    var tvOSProject = project.GenerateVariations ? project.AsTvOSProject() : project;
                    var buildTV     = new MSBuildTask(jenkins: jenkins, testProject: tvOSProject, processManager: processManager)
                    {
                        ProjectConfiguration = "Debug",
                        ProjectPlatform      = "iPhone",
                        Platform             = TestPlatform.tvOS,
                        TestName             = project.Name,
                    };
                    buildTV.CloneTestProject(jenkins.MainLog, processManager, tvOSProject);
                    projectTasks.Add(new RunDeviceTask(
                                         jenkins: jenkins,
                                         devices: jenkins.Devices,
                                         buildTask: buildTV,
                                         processManager: processManager,
                                         tunnelBore: jenkins.TunnelBore,
                                         errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                         useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                         candidates: jenkins.Devices.ConnectedTV.Where(d => project.IsSupported(d.DevicePlatform, d.ProductVersion)))
                    {
                        Ignored = !jenkins.IncludetvOS
                    });
                }

                if (createwatchOS)
                {
                    var watchOSProject = project.GenerateVariations ? project.AsWatchOSProject() : project;
                    if (!project.SkipwatchOS32Variation)
                    {
                        var buildWatch32 = new MSBuildTask(jenkins: jenkins, testProject: watchOSProject, processManager: processManager)
                        {
                            ProjectConfiguration = "Debug32",
                            ProjectPlatform      = "iPhone",
                            Platform             = TestPlatform.watchOS_32,
                            TestName             = project.Name,
                        };
                        buildWatch32.CloneTestProject(jenkins.MainLog, processManager, watchOSProject);
                        projectTasks.Add(new RunDeviceTask(
                                             jenkins: jenkins,
                                             devices: jenkins.Devices,
                                             buildTask: buildWatch32,
                                             processManager: processManager,
                                             tunnelBore: jenkins.TunnelBore,
                                             errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                             useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                             candidates: jenkins.Devices.ConnectedWatch)
                        {
                            Ignored = !jenkins.IncludewatchOS
                        });
                    }

                    if (!project.SkipwatchOSARM64_32Variation)
                    {
                        var buildWatch64_32 = new MSBuildTask(jenkins: jenkins, testProject: watchOSProject, processManager: processManager)
                        {
                            ProjectConfiguration = "Release64_32",                             // We don't support Debug for ARM64_32 yet.
                            ProjectPlatform      = "iPhone",
                            Platform             = TestPlatform.watchOS_64_32,
                            TestName             = project.Name,
                        };
                        buildWatch64_32.CloneTestProject(jenkins.MainLog, processManager, watchOSProject);
                        projectTasks.Add(new RunDeviceTask(
                                             jenkins: jenkins,
                                             devices: jenkins.Devices,
                                             buildTask: buildWatch64_32,
                                             processManager: processManager,
                                             tunnelBore: jenkins.TunnelBore,
                                             errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                             useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                             candidates: jenkins.Devices.ConnectedWatch32_64.Where(d => project.IsSupported(d.DevicePlatform, d.ProductVersion)))
                        {
                            Ignored = !jenkins.IncludewatchOS
                        });
                    }
                }
                foreach (var task in projectTasks)
                {
                    task.TimeoutMultiplier = project.TimeoutMultiplier;
                    task.BuildOnly        |= project.BuildOnly;
                    task.Ignored          |= ignored;
                }
                rv.AddRange(projectTasks);
            }

            return(Task.FromResult <IEnumerable <ITestTask> > (testVariationsFactory.CreateTestVariations(rv, (buildTask, test, candidates)
                                                                                                          => new RunDeviceTask(
                                                                                                              jenkins: jenkins,
                                                                                                              devices: jenkins.Devices,
                                                                                                              buildTask: buildTask,
                                                                                                              processManager: processManager,
                                                                                                              tunnelBore: jenkins.TunnelBore,
                                                                                                              errorKnowledgeBase: jenkins.ErrorKnowledgeBase,
                                                                                                              useTcpTunnel: jenkins.Harness.UseTcpTunnel,
                                                                                                              candidates: candidates?.Cast <IHardwareDevice> () ?? test.Candidates))));
        }
Example #7
0
 public TestSelector(Jenkins jenkins, IProcessManager processManager, IVersionControlSystem versionControlSystem)
 {
     this.jenkins        = jenkins;
     this.processManager = processManager;
     this.vcs            = versionControlSystem;
 }
Example #8
0
 public TestVariationsFactory(Jenkins jenkins, IProcessManager processManager)
 {
     this.jenkins        = jenkins ?? throw new ArgumentNullException(nameof(jenkins));
     this.processManager = processManager ?? throw new ArgumentNullException(nameof(processManager));
 }
 public NUnitTestTasksEnumerable(Jenkins jenkins, IProcessManager processManager)
 {
     this.jenkins        = jenkins ?? throw new ArgumentNullException(nameof(jenkins));
     this.processManager = processManager ?? throw new ArgumentNullException(nameof(processManager));
 }
Example #10
0
        public Task RunAsync(Jenkins jenkins, HtmlReportWriter htmlReportWriter)
        {
            var server = new HttpListener();

            // Try and find an unused port
            int    attemptsLeft = 50;
            int    port         = 51234;  // Try this port first, to try to not vary between runs just because.
            Random r            = new Random((int)DateTime.Now.Ticks);

            while (attemptsLeft-- > 0)
            {
                var newPort = port != 0 ? port : r.Next(49152, 65535);                  // The suggested range for dynamic ports is 49152-65535 (IANA)
                server.Prefixes.Clear();
                server.Prefixes.Add("http://*:" + newPort + "/");
                try {
                    server.Start();
                    port = newPort;
                    break;
                } catch (Exception ex) {
                    jenkins.MainLog.WriteLine("Failed to listen on port {0}: {1}", newPort, ex.Message);
                    port = 0;
                }
            }
            jenkins.MainLog.WriteLine($"Created server on localhost:{port}");

            var tcs    = new TaskCompletionSource <bool> ();
            var thread = new System.Threading.Thread(() =>
            {
                while (server.IsListening)
                {
                    var context   = server.GetContext();
                    var request   = context.Request;
                    var response  = context.Response;
                    var arguments = System.Web.HttpUtility.ParseQueryString(request.Url.Query);
                    try {
                        var allTasks = jenkins.Tasks.SelectMany((v) =>
                        {
                            var rv     = new List <ITestTask> ();
                            var runsim = v as AggregatedRunSimulatorTask;
                            if (runsim != null)
                            {
                                rv.AddRange(runsim.Tasks);
                            }
                            rv.Add(v);
                            return(rv);
                        });

                        IEnumerable <ITestTask> find_tasks(StreamWriter writer, string ids)
                        {
                            IEnumerable <ITestTask> tasks;
                            switch (request.Url.Query)
                            {
                            case "?all":
                                tasks = jenkins.Tasks;
                                break;

                            case "?selected":
                                tasks = allTasks.Where((v) => !v.Ignored);
                                break;

                            case "?failed":
                                tasks = allTasks.Where((v) => v.Failed);
                                break;

                            case "?":
                                writer.WriteLine("No tasks specified");
                                return(Array.Empty <AppleTestTask> ());

                            default:
                                var id_inputs = ids.Substring(1).Split(',');
                                var rv        = new List <ITestTask> (id_inputs.Length);
                                foreach (var id_input in id_inputs)
                                {
                                    if (int.TryParse(id_input, out var id))
                                    {
                                        var task = jenkins.Tasks.FirstOrDefault((t) => t.ID == id);
                                        if (task == null)
                                        {
                                            task = jenkins.Tasks.Where((v) => v is AggregatedRunSimulatorTask).Cast <AggregatedRunSimulatorTask> ().SelectMany((v) => v.Tasks).FirstOrDefault((t) => t.ID == id);
                                        }
                                        if (task == null)
                                        {
                                            writer.WriteLine($"Could not find test {id}");
                                        }
                                        else
                                        {
                                            rv.Add(task);
                                        }
                                    }
                                    else
                                    {
                                        writer.WriteLine($"Could not parse {arguments ["id"]}");
                                    }
                                }
                                tasks = rv;
                                break;
                            }
                            return(tasks);
                        }

                        string serveFile = null;
                        switch (request.Url.LocalPath)
                        {
                        case "/":
                            response.ContentType = System.Net.Mime.MediaTypeNames.Text.Html;
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                htmlReportWriter.Write(jenkins.Tasks, writer);
                            }
                            break;

                        case "/set-option":
                            response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
                            switch (request.Url.Query)
                            {
                            case "?clean":
                                jenkins.CleanSuccessfulTestRuns = true;
                                break;

                            case "?do-not-clean":
                                jenkins.CleanSuccessfulTestRuns = false;
                                break;

                            case "?uninstall-test-app":
                                jenkins.UninstallTestApp = true;
                                break;

                            case "?do-not-uninstall-test-app":
                                jenkins.UninstallTestApp = false;
                                break;

                            case "?skip-permission-tests":
                                jenkins.Harness.IncludeSystemPermissionTests = false;
                                break;

                            case "?include-permission-tests":
                                jenkins.Harness.IncludeSystemPermissionTests = true;
                                break;

                            case "?clear-permission-tests":
                                jenkins.Harness.IncludeSystemPermissionTests = null;
                                break;

                            default:
                                throw new NotImplementedException(request.Url.Query);
                            }
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                writer.WriteLine("OK");
                            }
                            break;

                        case "/select":
                        case "/deselect":
                            response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                foreach (var task in allTasks)
                                {
                                    bool?is_match = null;
                                    if (!(task.Ignored || task.NotStarted))
                                    {
                                        continue;
                                    }
                                    switch (request.Url.Query)
                                    {
                                    case "?all":
                                        is_match = true;
                                        break;

                                    case "?all-device":
                                        is_match = task is RunDeviceTask;
                                        break;

                                    case "?all-simulator":
                                        is_match = task is RunSimulatorTask;
                                        break;

                                    case "?all-ios":
                                        switch (task.Platform)
                                        {
                                        case TestPlatform.iOS:
                                        case TestPlatform.iOS_TodayExtension64:
                                        case TestPlatform.iOS_Unified:
                                        case TestPlatform.iOS_Unified32:
                                        case TestPlatform.iOS_Unified64:
                                            is_match = true;
                                            break;

                                        default:
                                            if (task.Platform.ToString().StartsWith("iOS", StringComparison.Ordinal))
                                            {
                                                throw new NotImplementedException();
                                            }
                                            break;
                                        }
                                        break;

                                    case "?all-tvos":
                                        switch (task.Platform)
                                        {
                                        case TestPlatform.tvOS:
                                            is_match = true;
                                            break;

                                        default:
                                            if (task.Platform.ToString().StartsWith("tvOS", StringComparison.Ordinal))
                                            {
                                                throw new NotImplementedException();
                                            }
                                            break;
                                        }
                                        break;

                                    case "?all-watchos":
                                        switch (task.Platform)
                                        {
                                        case TestPlatform.watchOS:
                                        case TestPlatform.watchOS_32:
                                        case TestPlatform.watchOS_64_32:
                                            is_match = true;
                                            break;

                                        default:
                                            if (task.Platform.ToString().StartsWith("watchOS", StringComparison.Ordinal))
                                            {
                                                throw new NotImplementedException();
                                            }
                                            break;
                                        }
                                        break;

                                    case "?all-mac":
                                        switch (task.Platform)
                                        {
                                        case TestPlatform.Mac:
                                        case TestPlatform.Mac_Modern:
                                        case TestPlatform.Mac_Full:
                                        case TestPlatform.Mac_System:
                                            is_match = true;
                                            break;

                                        default:
                                            if (task.Platform.ToString().StartsWith("Mac", StringComparison.Ordinal))
                                            {
                                                throw new NotImplementedException();
                                            }
                                            break;
                                        }
                                        break;

                                    default:
                                        writer.WriteLine("unknown query: {0}", request.Url.Query);
                                        break;
                                    }
                                    if (request.Url.LocalPath == "/select")
                                    {
                                        if (is_match.HasValue && is_match.Value)
                                        {
                                            task.Ignored = false;
                                        }
                                    }
                                    else if (request.Url.LocalPath == "/deselect")
                                    {
                                        if (is_match.HasValue && is_match.Value)
                                        {
                                            task.Ignored = true;
                                        }
                                    }
                                }

                                writer.WriteLine("OK");
                            }
                            break;

                        case "/stop":
                            response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                foreach (var task in find_tasks(writer, request.Url.Query))
                                {
                                    if (!task.Waiting)
                                    {
                                        writer.WriteLine($"Test '{task.TestName}' is not in a waiting state.");
                                    }
                                    else
                                    {
                                        task.Reset();
                                    }
                                }
                                writer.WriteLine("OK");
                            }
                            break;

                        case "/run":
                            response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                // We want to randomize the order the tests are added, so that we don't build first the test for one device,
                                // then for another, since that would not take advantage of running tests on several devices in parallel.
                                foreach (var task in find_tasks(writer, request.Url.Query).Shuffle())
                                {
                                    if (task.InProgress || task.Waiting)
                                    {
                                        writer.WriteLine($"Test '{task.TestName}' is already executing.");
                                    }
                                    else
                                    {
                                        task.Reset();
                                        task.BuildOnly = false;
                                        task.RunAsync();
                                    }
                                }
                                writer.WriteLine("OK");
                            }
                            break;

                        case "/build":
                            response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                foreach (var task in find_tasks(writer, request.Url.Query))
                                {
                                    if (task.InProgress || task.Waiting)
                                    {
                                        writer.WriteLine($"Test '{task.TestName}' is already executing.");
                                    }
                                    else if (task is RunTestTask rtt)
                                    {
                                        rtt.Reset();
                                        rtt.BuildAsync().ContinueWith((z) => {
                                            if (rtt.ExecutionResult == TestExecutingResult.Built)
                                            {
                                                rtt.ExecutionResult = TestExecutingResult.BuildSucceeded;
                                            }
                                        });
                                    }
                                    else
                                    {
                                        writer.WriteLine($"Test '{task.TestName}' is not a test that can be only built.");
                                    }
                                }

                                writer.WriteLine("OK");
                            }
                            break;

                        case "/reload-devices":
                            jenkins.DeviceLoader.LoadDevicesAsync().DoNotAwait();
                            break;

                        case "/reload-simulators":
                            jenkins.DeviceLoader.LoadSimulatorsAsync().DoNotAwait();
                            break;

                        case "/quit":
                            using (var writer = new StreamWriter(response.OutputStream)) {
                                writer.WriteLine("<!DOCTYPE html>");
                                writer.WriteLine("<html>");
                                writer.WriteLine("<body onload='close ();'>Closing web page...</body>");
                                writer.WriteLine("</html>");
                            }
                            server.Stop();
                            break;

                        case "/favicon.ico":
                            serveFile = Path.Combine(HarnessConfiguration.RootDirectory, "xharness", "favicon.ico");
                            goto default;

                        case "/index.html":
                            var redirect_to = request.Url.AbsoluteUri.Replace("/index.html", "/" + Path.GetFileName(jenkins.LogDirectory) + "/index.html");
                            response.Redirect(redirect_to);
                            break;

                        default:
                            var filename = Path.GetFileName(request.Url.LocalPath);
                            if (filename == "index.html" && Path.GetFileName(jenkins.LogDirectory) == Path.GetFileName(Path.GetDirectoryName(request.Url.LocalPath)))
                            {
                                // We're asked for the report for the current test run, so re-generate it.
                                jenkins.GenerateReport();
                            }

                            if (serveFile == null)
                            {
                                serveFile = Path.Combine(Path.GetDirectoryName(jenkins.LogDirectory), request.Url.LocalPath.Substring(1));
                            }
                            var path = serveFile;
                            if (File.Exists(path))
                            {
                                var buffer = new byte [4096];
                                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
                                    int read;
                                    response.ContentLength64 = fs.Length;
                                    switch (Path.GetExtension(path).ToLowerInvariant())
                                    {
                                    case ".html":
                                        response.ContentType = System.Net.Mime.MediaTypeNames.Text.Html;
                                        break;

                                    case ".css":
                                        response.ContentType = "text/css";
                                        break;

                                    case ".js":
                                        response.ContentType = "text/javascript";
                                        break;

                                    case ".ico":
                                        response.ContentType = "image/png";
                                        break;

                                    default:
                                        response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain + ";charset=UTF-8";
                                        break;
                                    }
                                    while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
                                    {
                                        response.OutputStream.Write(buffer, 0, read);
                                    }
                                }
                            }
                            else
                            {
                                Console.WriteLine($"404: {request.Url.LocalPath}");
                                response.StatusCode = 404;
                                response.OutputStream.WriteByte((byte)'?');
                            }
                            break;
                        }
                    } catch (IOException ioe) {
                        Console.WriteLine(ioe.Message);
                    } catch (Exception e) {
                        Console.WriteLine(e);
                    }
                    response.Close();
                }
                tcs.SetResult(true);
            })
            {
                IsBackground = true,
            };

            thread.Start();

            var url = $"http://localhost:{port}/" + Path.GetFileName(jenkins.LogDirectory) + "/index.html";

            Console.WriteLine($"Launching {url} in the system's default browser.");
            Process.Start("open", url);

            return(tcs.Task);
        }
        public async Task <IEnumerable <ITestTask> > CreateAsync(Jenkins jenkins, IMlaunchProcessManager processManager, TestVariationsFactory testVariationsFactory)
        {
            var runSimulatorTasks = new List <RunSimulatorTask> ();

            foreach (var project in jenkins.Harness.IOSTestProjects)
            {
                if (!project.IsExecutableProject)
                {
                    continue;
                }

                bool ignored = project.Ignore ?? !jenkins.IncludeSimulator;
                if (!jenkins.IsIncluded(project))
                {
                    ignored = true;
                }

                var ps = new List <Tuple <TestProject, TestPlatform, bool> > ();
                if (!project.GenerateVariations)
                {
                    ps.Add(new Tuple <TestProject, TestPlatform, bool> (project, project.TestPlatform, ignored));
                }
                else
                {
                    if (!project.SkipiOSVariation)
                    {
                        ps.Add(new Tuple <TestProject, TestPlatform, bool> (project, TestPlatform.iOS_Unified, ignored));
                    }
                    if (project.MonoNativeInfo != null)
                    {
                        ps.Add(new Tuple <TestProject, TestPlatform, bool> (project, TestPlatform.iOS_TodayExtension64, ignored));
                    }
                    if (!project.SkiptvOSVariation)
                    {
                        ps.Add(new Tuple <TestProject, TestPlatform, bool> (project.AsTvOSProject(), TestPlatform.tvOS, ignored));
                    }
                    if (!project.SkipwatchOSVariation)
                    {
                        ps.Add(new Tuple <TestProject, TestPlatform, bool> (project.AsWatchOSProject(), TestPlatform.watchOS, ignored));
                    }
                }

                var configurations = project.Configurations;
                if (configurations == null)
                {
                    configurations = new string [] { "Debug" }
                }
                ;
                foreach (var config in configurations)
                {
                    foreach (var pair in ps)
                    {
                        var configIgnored = pair.Item3;
                        var testPlatform  = pair.Item2;
                        switch (testPlatform)
                        {
                        case TestPlatform.iOS_Unified:
                        case TestPlatform.iOS_TodayExtension64:
                            configIgnored |= !jenkins.IncludeiOS64;
                            break;

                        case TestPlatform.tvOS:
                            configIgnored |= !jenkins.IncludetvOS;
                            break;

                        case TestPlatform.watchOS:
                            configIgnored |= !jenkins.IncludewatchOS;
                            break;

                        default:
                            Console.WriteLine("Unknown test platform for ignore check: {0}", testPlatform);
                            break;
                        }

                        configIgnored |= project.IsDotNetProject && !jenkins.IncludeDotNet;

                        var derived = new MSBuildTask(jenkins: jenkins, testProject: project, processManager: processManager);
                        derived.ProjectConfiguration = config;
                        derived.ProjectPlatform      = "iPhoneSimulator";
                        derived.Platform             = testPlatform;
                        derived.Ignored    = configIgnored;
                        derived.TestName   = project.Name;
                        derived.Dependency = project.Dependency;
                        derived.CloneTestProject(jenkins.MainLog, processManager, pair.Item1, HarnessConfiguration.RootDirectory);
                        var simTasks = CreateAsync(jenkins, processManager, derived);
                        runSimulatorTasks.AddRange(simTasks);
                        foreach (var task in simTasks)
                        {
                            if (configurations.Length > 1)
                            {
                                task.Variation = config;
                            }
                            task.TimeoutMultiplier = project.TimeoutMultiplier;
                        }
                    }
                }
            }

            var testVariations = testVariationsFactory.CreateTestVariations(runSimulatorTasks, (buildTask, test, candidates) =>
                                                                            new RunSimulatorTask(
                                                                                jenkins: jenkins,
                                                                                simulators: jenkins.Simulators,
                                                                                buildTask: buildTask,
                                                                                processManager: processManager,
                                                                                candidates: candidates?.Cast <SimulatorDevice> () ?? test.Candidates)).ToList();

            if (jenkins.IsServerMode)
            {
                return(testVariations);
            }

            foreach (var tv in testVariations)
            {
                if (!tv.Ignored)
                {
                    await tv.FindSimulatorAsync();
                }
            }

            var rv = new List <AggregatedRunSimulatorTask> ();

            foreach (var taskGroup in testVariations.GroupBy((RunSimulatorTask task) => task.Device?.UDID ?? task.Candidates.ToString()))
            {
                rv.Add(new AggregatedRunSimulatorTask(jenkins: jenkins, tasks: taskGroup)
                {
                    TestName = $"Tests for {taskGroup.Key}",
                });
            }
            return(rv);
        }

        IEnumerable <RunSimulatorTask> CreateAsync(Jenkins jenkins, IMlaunchProcessManager processManager, MSBuildTask buildTask)
        {
            var runtasks = new List <RunSimulatorTask> ();

            TestTarget []   targets = buildTask.Platform.GetAppRunnerTargets();
            TestPlatform [] platforms;
            bool []         ignored;

            switch (buildTask.Platform)
            {
            case TestPlatform.tvOS:
                platforms = new TestPlatform [] { TestPlatform.tvOS };
                ignored   = new [] { false };
                break;

            case TestPlatform.watchOS:
                platforms = new TestPlatform [] { TestPlatform.watchOS_32 };
                ignored   = new [] { false };
                break;

            case TestPlatform.iOS_Unified:
                platforms = new TestPlatform [] { TestPlatform.iOS_Unified64 };
                ignored   = new [] { false };
                break;

            case TestPlatform.iOS_TodayExtension64:
                platforms = new TestPlatform [] { TestPlatform.iOS_TodayExtension64 };
                ignored   = new [] { false };
                break;

            default:
                throw new NotImplementedException();
            }

            for (int i = 0; i < targets.Length; i++)
            {
                var sims = jenkins.Simulators.SelectDevices(targets [i], jenkins.SimulatorLoadLog, false);
                runtasks.Add(new RunSimulatorTask(
                                 jenkins: jenkins,
                                 simulators: jenkins.Simulators,
                                 buildTask: buildTask,
                                 processManager: processManager,
                                 candidates: sims)
                {
                    Platform = platforms [i],
                    Ignored  = ignored [i] || buildTask.Ignored
                });
            }

            return(runtasks);
        }
    }