<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[178444] trunk/Tools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/178444">178444</a></dd>
<dt>Author</dt> <dd>dbates@webkit.org</dd>
<dt>Date</dt> <dd>2015-01-14 14:12:59 -0800 (Wed, 14 Jan 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS] run-webkit-tests --ios hangs trying to launch iOS Simulator with unavailable runtime
https://bugs.webkit.org/show_bug.cgi?id=140301
&lt;rdar://problem/19389266&gt;

Reviewed by Jon Honeycutt.

Fixes an issue where run-webkit-tests --ios will hang when trying to launch iOS Simulator
with an unavailable runtime.

* Scripts/webkitpy/layout_tests/run_webkit_tests.py:
(_set_up_derived_options): Modified to access property Simulator.latest_available_runtime,
which was formerly called Simulator.latest_runtime. Additionally, raise an exception if the
specified runtime cannot be used because it is unavailable.
* Scripts/webkitpy/port/ios.py:
(IOSSimulatorPort.testing_device): Modified to call Simulator.lookup_or_create_device(),
which was formerly named testing_device.
* Scripts/webkitpy/xcode/simulator.py:
(Device.create): Modified to lookup created device by the UDID returned by simctl, which is
more robust than looking up the simulator device by name and runtime. This approach also
avoids returning the wrong device due to &lt;rdar://problem/19444383&gt; (simctl list shows
unavailable runtimes under the same iOS heading it would use to show it as available).
(Simulator.find_device_by_udid): Added.
(Simulator.device): Added optional parameter should_ignore_unavailable_devices (defaults
to False) to ignore devices that are unavailable (say, because their runtime is unavailable).
(Simulator.available_runtimes): Added.
(Simulator.latest_available_runtime): Renamed; formerly named latest_runtime. Take advantage
of the reverse=True argument to sorted() to sort the list of available runtimes such that the
first element of the sorted list is the runtime with the highest version number.
(Simulator.lookup_or_create_device): Renamed; formerly named testing_device.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptswebkitpylayout_testsrun_webkit_testspy">trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportiospy">trunk/Tools/Scripts/webkitpy/port/ios.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyxcodesimulatorpy">trunk/Tools/Scripts/webkitpy/xcode/simulator.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (178443 => 178444)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-01-14 21:33:48 UTC (rev 178443)
+++ trunk/Tools/ChangeLog        2015-01-14 22:12:59 UTC (rev 178444)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2015-01-14  Daniel Bates  &lt;dabates@apple.com&gt;
+
+        [iOS] run-webkit-tests --ios hangs trying to launch iOS Simulator with unavailable runtime
+        https://bugs.webkit.org/show_bug.cgi?id=140301
+        &lt;rdar://problem/19389266&gt;
+
+        Reviewed by Jon Honeycutt.
+
+        Fixes an issue where run-webkit-tests --ios will hang when trying to launch iOS Simulator
+        with an unavailable runtime.
+
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+        (_set_up_derived_options): Modified to access property Simulator.latest_available_runtime,
+        which was formerly called Simulator.latest_runtime. Additionally, raise an exception if the
+        specified runtime cannot be used because it is unavailable.
+        * Scripts/webkitpy/port/ios.py:
+        (IOSSimulatorPort.testing_device): Modified to call Simulator.lookup_or_create_device(),
+        which was formerly named testing_device.
+        * Scripts/webkitpy/xcode/simulator.py:
+        (Device.create): Modified to lookup created device by the UDID returned by simctl, which is
+        more robust than looking up the simulator device by name and runtime. This approach also
+        avoids returning the wrong device due to &lt;rdar://problem/19444383&gt; (simctl list shows
+        unavailable runtimes under the same iOS heading it would use to show it as available).
+        (Simulator.find_device_by_udid): Added.
+        (Simulator.device): Added optional parameter should_ignore_unavailable_devices (defaults
+        to False) to ignore devices that are unavailable (say, because their runtime is unavailable).
+        (Simulator.available_runtimes): Added.
+        (Simulator.latest_available_runtime): Renamed; formerly named latest_runtime. Take advantage
+        of the reverse=True argument to sorted() to sort the list of available runtimes such that the
+        first element of the sorted list is the runtime with the highest version number.
+        (Simulator.lookup_or_create_device): Renamed; formerly named testing_device.
+
</ins><span class="cx"> 2015-01-14  Csaba Osztrogonác  &lt;ossy@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove WK2 Windows cruft
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpylayout_testsrun_webkit_testspy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py (178443 => 178444)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py        2015-01-14 21:33:48 UTC (rev 178443)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py        2015-01-14 22:12:59 UTC (rev 178444)
</span><span class="lines">@@ -391,9 +391,11 @@
</span><span class="cx">     if options.platform == 'ios-simulator':
</span><span class="cx">         from webkitpy import xcode
</span><span class="cx">         if options.runtime is None:
</span><del>-            options.runtime = xcode.simulator.Simulator().latest_runtime
</del><ins>+            options.runtime = xcode.simulator.Simulator().latest_available_runtime
</ins><span class="cx">         else:
</span><span class="cx">             options.runtime = xcode.simulator.Runtime.from_identifier(options.runtime)
</span><ins>+            if not options.runtime.available:
+                raise Exception('The iOS Simulator runtime with identifier &quot;{identifier}&quot; cannot be used because it is unavailable.'.format(identifier=options.runtime.identifier))
</ins><span class="cx">         if options.device_type is None:
</span><span class="cx">             iphone5 = xcode.simulator.DeviceType.from_name('iPhone 5')
</span><span class="cx">             iphone5s = xcode.simulator.DeviceType.from_name('iPhone 5s')
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportiospy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/ios.py (178443 => 178444)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios.py        2015-01-14 21:33:48 UTC (rev 178443)
+++ trunk/Tools/Scripts/webkitpy/port/ios.py        2015-01-14 22:12:59 UTC (rev 178444)
</span><span class="lines">@@ -260,7 +260,7 @@
</span><span class="cx"> 
</span><span class="cx">         device_type = self.get_option('device_type')
</span><span class="cx">         runtime = self.get_option('runtime')
</span><del>-        self._testing_device = simulator.Simulator().testing_device(device_type, runtime)
</del><ins>+        self._testing_device = simulator.Simulator().lookup_or_create_device(device_type.name + ' WebKit Tester', device_type, runtime)
</ins><span class="cx">         return self.testing_device
</span><span class="cx"> 
</span><span class="cx">     def simulator_path(self, udid):
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyxcodesimulatorpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/xcode/simulator.py (178443 => 178444)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/xcode/simulator.py        2015-01-14 21:33:48 UTC (rev 178443)
+++ trunk/Tools/Scripts/webkitpy/xcode/simulator.py        2015-01-14 22:12:59 UTC (rev 178444)
</span><span class="lines">@@ -177,17 +177,15 @@
</span><span class="cx">         :rtype: Device
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         sim = Simulator()
</span><del>-        subprocess.check_call(['xcrun', 'simctl', 'create', name, device_type.identifier, runtime.identifier])
-
-        device = None
-        while device is None:
</del><ins>+        device_udid = subprocess.check_output(['xcrun', 'simctl', 'create', name, device_type.identifier, runtime.identifier]).rstrip()
+        assert(device_udid)
+        while True:
</ins><span class="cx">             sim.refresh()
</span><del>-            device = sim.device(name, runtime)
-            if device is None or device.state == 'Creating':
</del><ins>+            device = sim.find_device_by_udid(device_udid)
+            if not device or device.state == 'Creating':
</ins><span class="cx">                 time.sleep(2)
</span><del>-            else:
-                break
-        return device
</del><ins>+                continue
+            return device
</ins><span class="cx"> 
</span><span class="cx">     def __eq__(self, other):
</span><span class="cx">         return self.udid == other.udid
</span><span class="lines">@@ -338,8 +336,21 @@
</span><span class="cx">             return runtime
</span><span class="cx">         return None
</span><span class="cx"> 
</span><del>-    def device(self, name=None, runtime=None):
</del><ins>+    def find_device_by_udid(self, udid):
</ins><span class="cx">         &quot;&quot;&quot;
</span><ins>+        :param udid: The UDID of the device to find.
+        :type udid: str
+        :return: The `Device` with the specified UDID.
+        :rtype: Device
+        &quot;&quot;&quot;
+        for device in self.devices:
+            if device.udid == udid:
+                return device
+        return None
+
+    # FIXME: We should find an existing device with respect to its name, device type and runtime.
+    def device(self, name=None, runtime=None, should_ignore_unavailable_devices=False):
+        &quot;&quot;&quot;
</ins><span class="cx">         :param name: The name of the desired device.
</span><span class="cx">         :type name: str
</span><span class="cx">         :param runtime: The runtime of the desired device.
</span><span class="lines">@@ -351,6 +362,8 @@
</span><span class="cx">             raise TypeError('Must supply name and/or runtime.')
</span><span class="cx"> 
</span><span class="cx">         for device in self.devices:
</span><ins>+            if should_ignore_unavailable_devices and not device.available:
+                continue
</ins><span class="cx">             if name and device.name != name:
</span><span class="cx">                 continue
</span><span class="cx">             if runtime and device.runtime != runtime:
</span><span class="lines">@@ -359,6 +372,14 @@
</span><span class="cx">         return None
</span><span class="cx"> 
</span><span class="cx">     @property
</span><ins>+    def available_runtimes(self):
+        &quot;&quot;&quot;
+        :return: An iterator of all available runtimes.
+        :rtype: iter
+        &quot;&quot;&quot;
+        return itertools.ifilter(lambda runtime: runtime.available, self.runtimes)
+
+    @property
</ins><span class="cx">     def devices(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         :return: An iterator of all devices from all runtimes.
</span><span class="lines">@@ -367,18 +388,24 @@
</span><span class="cx">         return itertools.chain(*[runtime.devices for runtime in self.runtimes])
</span><span class="cx"> 
</span><span class="cx">     @property
</span><del>-    def latest_runtime(self):
</del><ins>+    def latest_available_runtime(self):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         :return: Returns a Runtime object with the highest version.
</span><span class="cx">         :rtype: Runtime or None
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         if not self.runtimes:
</span><span class="cx">             return None
</span><del>-        return sorted(self.runtimes, key=lambda runtime: runtime.version)[-1]
</del><ins>+        return sorted(self.available_runtimes, key=lambda runtime: runtime.version, reverse=True)[0]
</ins><span class="cx"> 
</span><del>-    def testing_device(self, device_type, runtime):
</del><ins>+    def lookup_or_create_device(self, name, device_type, runtime):
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        Get an iOS Simulator device for testing.
</del><ins>+        Returns an available iOS Simulator device for testing.
+
+        This function will create a new simulator device with the specified name,
+        device type and runtime if one does not already exist.
+
+        :param name: The name of the simulator device to lookup or create.
+        :type name: str
</ins><span class="cx">         :param device_type: The CoreSimulator device type.
</span><span class="cx">         :type device_type: DeviceType
</span><span class="cx">         :param runtime: The CoreSimulator runtime.
</span><span class="lines">@@ -386,9 +413,13 @@
</span><span class="cx">         :return: A dictionary describing the device.
</span><span class="cx">         :rtype: Device
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        # Check to see if the testing device already exists
-        name = device_type.name + ' WebKit Tester'
-        return self.device(name=name, runtime=runtime) or Device.create(name, device_type, runtime)
</del><ins>+        assert(runtime.available)
+        testing_device = self.device(name=name, runtime=runtime, should_ignore_unavailable_devices=True)
+        if testing_device:
+            return testing_device
+        testing_device = Device.create(name, device_type, runtime)
+        assert(testing_device.available)
+        return testing_device
</ins><span class="cx"> 
</span><span class="cx">     def __repr__(self):
</span><span class="cx">         return '&lt;iOS Simulator: {num_runtimes} runtimes, {num_device_types} device types&gt;'.format(
</span></span></pre>
</div>
</div>

</body>
</html>