Make it possible to use an existing simulator instance for one-off testing
authorjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Dec 2016 20:02:11 +0000 (20:02 +0000)
committerjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Dec 2016 20:02:11 +0000 (20:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164568
<rdar://problem/29189133>

Reviewed by Daniel Bates.

With this patch, if a simulator is currently running on the machine and
'--dedicated-simulators' is not passed into the application, only one simulator
instance will be used, and this instance will be the existing instance.
If no simulator is running or '--dedicated-simulators' is passed to the script,
previous behavior will be used.

* Scripts/webkitpy/layout_tests/run_webkit_tests.py:
(parse_args):
* Scripts/webkitpy/port/ios.py:
(IOSSimulatorPort.__init__): Logic for enabling usage of currently running simulator.
(IOSSimulatorPort._create_simulators): Only create simulators when needed, don't reset already running simulators.
(IOSSimulatorPort.setup_test_run): Don't open already running simulators.
(IOSSimulatorPort._quit_ios_simulator): Only quit simulators if we manage them.
(IOSSimulatorPort.clean_up_test_run): Only clean up simulators if we manage them.
(IOSSimulatorPort._using_dedicated_simulators): True if simulators need to be managed, false if using an existing instance.
(IOSSimulatorPort.device_id_for_worker_number): Access currently running simulator if not managing devices.
* Scripts/webkitpy/xcode/simulator.py:
(Simulator.refresh): Check if xcode_simctl_list returned None instead of a generator.
(Simulator.current_device): Get currently running device.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209337 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
Tools/Scripts/webkitpy/port/ios.py
Tools/Scripts/webkitpy/xcode/simulator.py

index 8c252b7..59bdd71 100644 (file)
@@ -1,3 +1,31 @@
+2016-12-05  Jonathan Bedard  <jbedard@apple.com>
+
+        Make it possible to use an existing simulator instance for one-off testing
+        https://bugs.webkit.org/show_bug.cgi?id=164568
+        <rdar://problem/29189133>
+
+        Reviewed by Daniel Bates.
+
+        With this patch, if a simulator is currently running on the machine and
+        '--dedicated-simulators' is not passed into the application, only one simulator
+        instance will be used, and this instance will be the existing instance.
+        If no simulator is running or '--dedicated-simulators' is passed to the script,
+        previous behavior will be used.
+
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+        (parse_args):
+        * Scripts/webkitpy/port/ios.py:
+        (IOSSimulatorPort.__init__): Logic for enabling usage of currently running simulator.
+        (IOSSimulatorPort._create_simulators): Only create simulators when needed, don't reset already running simulators.
+        (IOSSimulatorPort.setup_test_run): Don't open already running simulators.
+        (IOSSimulatorPort._quit_ios_simulator): Only quit simulators if we manage them.
+        (IOSSimulatorPort.clean_up_test_run): Only clean up simulators if we manage them. 
+        (IOSSimulatorPort._using_dedicated_simulators): True if simulators need to be managed, false if using an existing instance.
+        (IOSSimulatorPort.device_id_for_worker_number): Access currently running simulator if not managing devices.
+        * Scripts/webkitpy/xcode/simulator.py:
+        (Simulator.refresh): Check if xcode_simctl_list returned None instead of a generator.
+        (Simulator.current_device): Get currently running device.
+
 2016-12-05  Dan Bernstein  <mitz@apple.com>
 
         Disable a crashing test on iOS.
index 8254333..7173809 100755 (executable)
@@ -296,6 +296,8 @@ def parse_args(args):
     option_group_definitions.append(("iOS Simulator Options", [
         optparse.make_option('--runtime', help='iOS Simulator runtime identifier (default: latest runtime)'),
         optparse.make_option('--device-type', help='iOS Simulator device type identifier (default: i386 -> iPhone 5, x86_64 -> iPhone 5s)'),
+        optparse.make_option('--dedicated-simulators', action="store_true", default=False,
+            help="If set, dedicated iOS simulators will always be created.  If not set, the script will attempt to use any currently running simulator."),
     ]))
 
     option_group_definitions.append(("Miscellaneous Options", [
index 04d2d4b..e44703f 100644 (file)
@@ -103,6 +103,14 @@ class IOSSimulatorPort(DarwinPort):
         self._device_class = optional_device_class if optional_device_class else self.DEFAULT_DEVICE_CLASS
         _log.debug('IOSSimulatorPort _device_class is %s', self._device_class)
 
+        self._current_device = Simulator(host).current_device()
+        if not self._current_device:
+            self.set_option('dedicated_simulators', True)
+        if not self.get_option('dedicated_simulators'):
+            if self.get_option('child_processes') > 1:
+                _log.warn('Cannot have more than one child process when using a running simulator.  Setting child_processes to 1.')
+            self.set_option('child_processes', 1)
+
     def driver_name(self):
         if self.get_option('driver_name'):
             return self.get_option('driver_name')
@@ -276,15 +284,21 @@ class IOSSimulatorPort(DarwinPort):
                 _log.warn("maximum child-processes which can be supported on this system are: {0}".format(self.default_child_processes()))
                 _log.warn("This is very likely to fail.")
 
-        self._createSimulatorApps()
+        if self._using_dedicated_simulators():
+            self._createSimulatorApps()
 
-        for i in xrange(self.child_processes()):
-            self._create_device(i)
+            for i in xrange(self.child_processes()):
+                self._create_device(i)
 
-        for i in xrange(self.child_processes()):
-            device_udid = self._testing_device(i).udid
-            Simulator.wait_until_device_is_in_state(device_udid, Simulator.DeviceState.SHUTDOWN)
-            Simulator.reset_device(device_udid)
+            for i in xrange(self.child_processes()):
+                device_udid = self._testing_device(i).udid
+                Simulator.wait_until_device_is_in_state(device_udid, Simulator.DeviceState.SHUTDOWN)
+                Simulator.reset_device(device_udid)
+        else:
+            assert(self._current_device)
+            if self._current_device.name != self.simulator_device_type().name:
+                _log.warn("Expected simulator of type '" + self.simulator_device_type().name + "' but found simulator of type '" + self._current_device.name + "'")
+                _log.warn('The next block of tests may fail due to device mis-match')
 
     def setup_test_run(self, device_class=None):
         mac_os_version = self.host.platform.os_version
@@ -296,6 +310,9 @@ class IOSSimulatorPort(DarwinPort):
 
         self._create_simulators()
 
+        if not self._using_dedicated_simulators():
+            return
+
         for i in xrange(self.child_processes()):
             device_udid = self._testing_device(i).udid
             _log.debug('testing device %s has udid %s', i, device_udid)
@@ -313,6 +330,8 @@ class IOSSimulatorPort(DarwinPort):
             Simulator.wait_until_device_is_booted(self._testing_device(i).udid)
 
     def _quit_ios_simulator(self):
+        if not self._using_dedicated_simulators():
+            return
         _log.debug("_quit_ios_simulator killing all Simulator processes")
         # FIXME: We should kill only the Simulators we started.
         subprocess.call(["killall", "-9", "-m", "Simulator"])
@@ -329,6 +348,9 @@ class IOSSimulatorPort(DarwinPort):
                 _log.warning('Unable to remove ' + fifo)
                 pass
 
+        if not self._using_dedicated_simulators():
+            return
+
         for i in xrange(self.child_processes()):
             simulator_path = self.get_simulator_path(i)
             device_udid = self._testing_device(i).udid
@@ -379,6 +401,9 @@ class IOSSimulatorPort(DarwinPort):
 
     SUBPROCESS_CRASH_REGEX = re.compile('#CRASHED - (?P<subprocess_name>\S+) \(pid (?P<subprocess_pid>\d+)\)')
 
+    def _using_dedicated_simulators(self):
+        return self.get_option('dedicated_simulators')
+
     def _create_device(self, number):
         return Simulator.create_device(number, self.simulator_device_type(), self.simulator_runtime)
 
@@ -392,7 +417,9 @@ class IOSSimulatorPort(DarwinPort):
     def device_id_for_worker_number(self, number):
         if self._printing_cmd_line:
             return '<dummy id>'
-        return self._testing_device(number).udid
+        if self._using_dedicated_simulators():
+            return self._testing_device(number).udid
+        return self._current_device.udid
 
     def get_simulator_path(self, suffix=""):
         return os.path.join(self.SIMULATOR_DIRECTORY, "Simulator" + str(suffix) + ".app")
index b6aa3da..658e304 100644 (file)
@@ -400,6 +400,8 @@ class Simulator(object):
         Refresh runtime and device type information from ``simctl list``.
         """
         lines = self._host.platform.xcode_simctl_list()
+        if not lines:
+            return
         device_types_header = next(lines)
         if device_types_header != '== Device Types ==':
             raise RuntimeError('Expected == Device Types == header but got: "{}"'.format(device_types_header))
@@ -529,6 +531,14 @@ class Simulator(object):
                 return device
         return None
 
+    def current_device(self):
+        # FIXME: Find the simulator device that was booted by Simulator.app. For now, pick some booted simulator device, which
+        # may have been booted using the simctl command line tool.
+        for device in self.devices:
+            if device.state == Simulator.DeviceState.BOOTED:
+                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):
         """