run_loop 1.5.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cbbee55fbd11dd5c1cd13fa461ae1be917adc6d3
4
- data.tar.gz: 22f0456c4949e71f6c8d2d951d7f0aa559448674
3
+ metadata.gz: 8d3ac00b7d27f57b3b75a5c968119b85e42106c5
4
+ data.tar.gz: 991d05cd919e9a9beab809a162a654c917404c64
5
5
  SHA512:
6
- metadata.gz: 434db36ae98ba6a3530cb164d9ac0379fbe59cfad22a2851901530abbe20393668ff3c8be03e046a180b3a168f4842376825bb13920fb0f3c9b9417e5b125902
7
- data.tar.gz: 351adc46d8f2849bb6c1b5f8b0772073f3608776fabe3ee324e16daed86e8d6b07fa58fc22f59881d86c60b979a27a2f050e2af6bc5759be833dc3c1e88f36e3
6
+ metadata.gz: b228aeeafd1f6a418deef62898a4001f8902c6566497b6d906da927356982bfc1b3b05f136ead14026135c0223d9ae32cfa9fc8c0f0c32598326d7a74657b466
7
+ data.tar.gz: c0786de6bf90282b0c9e9106a2893ceb8984b2df909aaa6d581b1a7fa7d58864a49066776caa780cefdabb21de960276d1d11ecc64acacbfabde40d2217e1aaf
data/lib/run_loop.rb CHANGED
@@ -13,7 +13,6 @@ require 'run_loop/dylib_injector'
13
13
  require 'run_loop/fifo'
14
14
  require 'run_loop/core'
15
15
  require 'run_loop/version'
16
- require 'run_loop/xctools'
17
16
  require 'run_loop/plist_buddy'
18
17
  require 'run_loop/app'
19
18
  require 'run_loop/ipa'
@@ -24,7 +23,6 @@ require 'run_loop/lipo'
24
23
  require 'run_loop/cache/cache'
25
24
  require 'run_loop/host_cache'
26
25
  require 'run_loop/patches/awesome_print'
27
- require 'run_loop/patches/retriable'
28
26
  require 'run_loop/core_simulator'
29
27
  require 'run_loop/simctl/plists'
30
28
 
@@ -37,11 +35,7 @@ module RunLoop
37
35
  # @return [void]
38
36
  def self.deprecated(version, msg)
39
37
 
40
- if RUBY_VERSION < '2.0'
41
- stack = Kernel.caller[1..6].join("\n")
42
- else
43
- stack = Kernel.caller(0, 6)[1..-1].join("\n")
44
- end
38
+ stack = Kernel.caller(0, 6)[1..-1].join("\n")
45
39
 
46
40
  msg = "deprecated '#{version}' - #{msg}\n#{stack}"
47
41
 
@@ -97,8 +97,12 @@ module RunLoop
97
97
  ENV['DEBUG'] = '1' if debug
98
98
 
99
99
  begin
100
- RunLoop::SimControl.terminate_all_sims
101
- RunLoop::LifeCycle::Simulator.new.terminate_core_simulator_processes
100
+ RunLoop::CoreSimulator.terminate_core_simulator_processes
101
+ process_name = "com.apple.CoreSimulator.CoreSimulatorService"
102
+ RunLoop::ProcessWaiter.new(process_name).pids.each do |pid|
103
+ kill_options = { :timeout => 0.5 }
104
+ RunLoop::ProcessTerminator.new(pid, 'KILL', process_name, kill_options)
105
+ end
102
106
  ensure
103
107
  ENV['DEBUG'] = original_value if debug
104
108
  end
data/lib/run_loop/core.rb CHANGED
@@ -185,7 +185,10 @@ module RunLoop
185
185
  # Quits the simulator.
186
186
  core_sim = RunLoop::CoreSimulator.new(device, app)
187
187
 
188
- core_sim.install
188
+ # :reset is a legacy variable; has been replaced with :reset_app_sandbox
189
+ if launch_options[:reset] || launch_options[:reset_app_sandbox]
190
+ core_sim.reset_app_sandbox
191
+ end
189
192
 
190
193
  # Will quit the simulator if it is running.
191
194
  # @todo fix accessibility_enabled? so we don't have to quit the sim
@@ -196,17 +199,15 @@ module RunLoop
196
199
  # Will quit the simulator if it is running.
197
200
  # @todo fix software_keyboard_enabled? so we don't have to quit the sim
198
201
  # SimControl#software_keyboard_enabled? is always false during Core#prepare_simulator
199
- # https://github.com/calabash/run_loop/issues/167
202
+ # https://github.com/calabash/run_loop/issues/168
200
203
  sim_control.ensure_software_keyboard(device)
201
204
 
202
- # Xcode 6.3 instruments cannot launch an app that is already installed on
203
- # iOS 8.3 Simulators. See: https://github.com/calabash/calabash-ios/issues/744
204
- if xcode.version_gte_63?
205
+ # Launches the simulator if the app is not installed.
206
+ core_sim.install
205
207
 
206
- if core_sim.app_is_installed? && !sim_control.sim_is_running?
207
- core_sim.launch_simulator
208
- end
209
- end
208
+ # If CoreSimulator has already launched the simulator, it will not
209
+ # launching it again.
210
+ core_sim.launch_simulator
210
211
  end
211
212
  end
212
213
 
@@ -218,15 +219,6 @@ module RunLoop
218
219
  logger = options[:logger]
219
220
  sim_control ||= options[:sim_control] || RunLoop::SimControl.new
220
221
 
221
- if options[:xctools]
222
- if RunLoop::Environment.debug?
223
- RunLoop.deprecated('1.5.0', %q(
224
- RunLoop::XCTools has been replaced with RunLoop::Xcode.
225
- The :xctools key will be ignored. It has been replaced by the :xcode key.
226
- Please update your sources to pass an instance of RunLoop::Xcode))
227
- end
228
- end
229
-
230
222
  xcode ||= options[:xcode] || sim_control.xcode
231
223
 
232
224
  instruments = RunLoop::Instruments.new
@@ -476,34 +468,23 @@ Logfile: #{log_file}
476
468
  #
477
469
  # For historical reasons, the most recent non-64b SDK should be used.
478
470
  #
479
- # @param [RunLoop::XCTools, RunLoop::Xcode] xcode Used to detect the current xcode
471
+ # @param [RunLoop::Xcode] xcode Used to detect the current xcode
480
472
  # version.
481
473
  def self.default_simulator(xcode=RunLoop::Xcode.new)
482
- if xcode.is_a?(RunLoop::XCTools)
483
- if RunLoop::Environment.debug?
484
- RunLoop.deprecated('1.5.0',
485
- %q(
486
- RunLoop::XCTools has been replaced with RunLoop::Xcode.
487
- Please update your sources to pass an instance of RunLoop::Xcode))
488
- end
489
- ensured_xcode = RunLoop::Xcode.new
490
- else
491
- ensured_xcode = xcode
492
- end
493
474
 
494
- if ensured_xcode.version_gte_71?
475
+ if xcode.version_gte_71?
495
476
  'iPhone 6s (9.1)'
496
- elsif ensured_xcode.version_gte_7?
477
+ elsif xcode.version_gte_7?
497
478
  'iPhone 5s (9.0)'
498
- elsif ensured_xcode.version_gte_64?
479
+ elsif xcode.version_gte_64?
499
480
  'iPhone 5s (8.4 Simulator)'
500
- elsif ensured_xcode.version_gte_63?
481
+ elsif xcode.version_gte_63?
501
482
  'iPhone 5s (8.3 Simulator)'
502
- elsif ensured_xcode.version_gte_62?
483
+ elsif xcode.version_gte_62?
503
484
  'iPhone 5s (8.2 Simulator)'
504
- elsif ensured_xcode.version_gte_61?
485
+ elsif xcode.version_gte_61?
505
486
  'iPhone 5s (8.1 Simulator)'
506
- elsif ensured_xcode.version_gte_6?
487
+ elsif xcode.version_gte_6?
507
488
  'iPhone 5s (8.0 Simulator)'
508
489
  else
509
490
  'iPhone Retina (4-inch) - Simulator - iOS 7.1'
@@ -731,18 +712,7 @@ Please update your sources to pass an instance of RunLoop::Xcode))
731
712
  candidate
732
713
  end
733
714
 
734
- def self.default_tracetemplate(instruments_arg=RunLoop::Instruments.new)
735
- if instruments_arg.is_a?(RunLoop::XCTools)
736
- if RunLoop::Environment.debug?
737
- RunLoop.deprecated('1.5.0',
738
- %q(
739
- RunLoop::XCTools has been replaced with RunLoop::Xcode.
740
- Please update your sources to pass an instance of RunLoop::Instruments))
741
- end
742
- instruments = RunLoop::Instruments.new
743
- else
744
- instruments = instruments_arg
745
- end
715
+ def self.default_tracetemplate(instruments=RunLoop::Instruments.new)
746
716
 
747
717
  templates = instruments.templates
748
718
 
@@ -1,6 +1,34 @@
1
1
  # A class to manage interactions with CoreSimulators.
2
2
  class RunLoop::CoreSimulator
3
3
 
4
+ # These options control various aspects of an app's life cycle on the iOS
5
+ # Simulator.
6
+ #
7
+ # You can override these values if they do not work in your environment.
8
+ #
9
+ # For cucumber users, the best place to override would be in your
10
+ # features/support/env.rb.
11
+ #
12
+ # For example:
13
+ #
14
+ # RunLoop::CoreSimulator::DEFAULT_OPTIONS[:install_app_timeout] = 60
15
+ DEFAULT_OPTIONS = {
16
+ # In most cases 30 seconds is a reasonable amount of time to wait for an
17
+ # install. When testing larger apps, on slow machines, or in CI, this
18
+ # value may need to be higher. 120 is the default for CI.
19
+ :install_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
20
+ :uninstall_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
21
+ :launch_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
22
+ :wait_for_state_timeout => RunLoop::Environment.ci? ? 120 : 30
23
+ }
24
+
25
+ # @!visibility private
26
+ # This should not be overridden
27
+ WAIT_FOR_SIMULATOR_STATE_INTERVAL = 0.1
28
+
29
+ # @!visibility private
30
+ @@simulator_pid = nil
31
+
4
32
  # @!visibility private
5
33
  attr_reader :app
6
34
 
@@ -16,20 +44,12 @@ class RunLoop::CoreSimulator
16
44
  # @!visibility private
17
45
  attr_reader :xcrun
18
46
 
19
- # @!visibility private
20
- attr_reader :simulator_pid
21
-
22
47
  # @!visibility private
23
48
  METADATA_PLIST = '.com.apple.mobile_container_manager.metadata.plist'
24
49
 
25
50
  # @!visibility private
26
51
  CORE_SIMULATOR_DEVICE_DIR = File.expand_path('~/Library/Developer/CoreSimulator/Devices')
27
52
 
28
- # @!visibility private
29
- WAIT_FOR_DEVICE_STATE_OPTS = {
30
- interval: 0.1,
31
- timeout: 5
32
- }
33
53
 
34
54
  # @!visibility private
35
55
  MANAGED_PROCESSES =
@@ -109,6 +129,122 @@ class RunLoop::CoreSimulator
109
129
  send_term_first = process_details[1]
110
130
  self.term_or_kill(process_name, send_term_first)
111
131
  end
132
+
133
+ self.simulator_pid = nil
134
+ end
135
+
136
+ # @!visibility private
137
+ #
138
+ # Some operations, like erase, require that the simulator be
139
+ # 'Shutdown'.
140
+ #
141
+ # @param [RunLoop::Device] simulator the sim to wait for
142
+ # @param [String] target_state the state to wait for
143
+ def self.wait_for_simulator_state(simulator, target_state)
144
+ now = Time.now
145
+ timeout = DEFAULT_OPTIONS[:wait_for_state_timeout]
146
+ poll_until = now + timeout
147
+ delay = WAIT_FOR_SIMULATOR_STATE_INTERVAL
148
+ in_state = false
149
+ while Time.now < poll_until
150
+ in_state = simulator.update_simulator_state == target_state
151
+ break if in_state
152
+ sleep delay if delay != 0
153
+ end
154
+
155
+ elapsed = Time.now - now
156
+ RunLoop.log_debug("Waited for #{elapsed} seconds for device to have state: '#{target_state}'.")
157
+
158
+ unless in_state
159
+ raise "Expected '#{target_state} but found '#{simulator.state}' after waiting."
160
+ end
161
+ in_state
162
+ end
163
+
164
+ # @!visibility private
165
+ # Erase a simulator. This is the same as touching the Simulator
166
+ # "Reset Content & Settings" menu item.
167
+ #
168
+ # @param [RunLoop::Device] simulator The simulator to erase
169
+ # @param [Hash] options Control the behavior of the method.
170
+ # @option options [Numeric] :timout (180) How long tow wait for simctl to
171
+ # shutdown and erase the simulator. The timeout is apply separately to
172
+ # each command.
173
+ #
174
+ # @raise RuntimeError If the simulator cannot be shutdown
175
+ # @raise RuntimeError If the simulator cannot be erased
176
+ # @raise ArgumentError If the simulator is a physical device
177
+ def self.erase(simulator, options={})
178
+ if simulator.physical_device?
179
+ raise ArgumentError,
180
+ "#{simulator} is a physical device. This method is only for Simulators"
181
+ end
182
+
183
+ default_options = {
184
+ :timeout => 60*3
185
+ }
186
+
187
+ merged_options = default_options.merge(options)
188
+
189
+ self.quit_simulator
190
+
191
+ xcrun = merged_options[:xcrun] || RunLoop::Xcrun.new
192
+ timeout = merged_options[:timeout]
193
+ xcrun_opts = {
194
+ :log_cmd => true,
195
+ :timeout => timeout
196
+ }
197
+
198
+ if simulator.update_simulator_state != "Shutdown"
199
+ args = ["simctl", "shutdown", simulator.udid]
200
+ xcrun.exec(args, xcrun_opts)
201
+ begin
202
+ self.wait_for_simulator_state(simulator, "Shutdown")
203
+ rescue RuntimeError => _
204
+ raise RuntimeError, %Q{
205
+ Could not erase simulator because it could not be Shutdown.
206
+
207
+ This usually means your CoreSimulator processes need to be restarted.
208
+
209
+ You can restart the CoreSimulator processes with this command:
210
+
211
+ $ bundle exec run-loop simctl manage-processes
212
+
213
+ }
214
+
215
+ end
216
+ end
217
+
218
+ args = ["simctl", "erase", simulator.udid]
219
+ hash = xcrun.exec(args, xcrun_opts)
220
+
221
+ if hash[:exit_status] != 0
222
+ raise RuntimeError, %Q{
223
+ Could not erase simulator because simctl returned this error:
224
+
225
+ #{hash[:out]}
226
+
227
+ This usually means your CoreSimulator processes need to be restarted.
228
+
229
+ You can restart the CoreSimulator processes with this command:
230
+
231
+ $ bundle exec run-loop simctl manage-processes
232
+
233
+ }
234
+
235
+ end
236
+
237
+ hash
238
+ end
239
+
240
+ # @!visibility private
241
+ def self.simulator_pid
242
+ @@simulator_pid
243
+ end
244
+
245
+ # @!visibility private
246
+ def self.simulator_pid=(pid)
247
+ @@simulator_pid = pid
112
248
  end
113
249
 
114
250
  # @param [RunLoop::Device] device The device.
@@ -130,7 +266,7 @@ class RunLoop::CoreSimulator
130
266
  RunLoop::CoreSimulator.quit_simulator
131
267
  end
132
268
 
133
- # stdio.pipe - can cause problems finding the SHA or size data dir
269
+ # stdio.pipe - can cause problems finding the SHA of a simulator
134
270
  rm_instruments_pipe
135
271
  end
136
272
 
@@ -149,19 +285,14 @@ class RunLoop::CoreSimulator
149
285
  @xcrun ||= RunLoop::Xcrun.new
150
286
  end
151
287
 
152
- # @!visibility private
153
- def simulator_pid
154
- @simulator_pid
155
- end
156
-
157
288
  # Launch the simulator indicated by device.
158
289
  def launch_simulator
159
290
 
160
- if sim_pid != nil
291
+ if running_simulator_pid != nil
161
292
  # There is a running simulator.
162
293
 
163
294
  # Did we launch it?
164
- if sim_pid == simulator_pid
295
+ if running_simulator_pid == RunLoop::CoreSimulator.simulator_pid
165
296
  # Nothing to do, we already launched the simulator.
166
297
  return
167
298
  else
@@ -177,12 +308,9 @@ class RunLoop::CoreSimulator
177
308
 
178
309
  start_time = Time.now
179
310
 
180
- pid = spawn('xcrun', *args)
311
+ pid = Process.spawn('xcrun', *args)
181
312
  Process.detach(pid)
182
313
 
183
- # Keep track of the pid so we can know if we have already launched this sim.
184
- @simulator_pid = pid
185
-
186
314
  options = { :timeout => 5, :raise_on_timeout => true }
187
315
  RunLoop::ProcessWaiter.new(sim_name, options).wait_for_any
188
316
 
@@ -191,6 +319,9 @@ class RunLoop::CoreSimulator
191
319
  elapsed = Time.now - start_time
192
320
  RunLoop.log_debug("Took #{elapsed} seconds to launch the simulator")
193
321
 
322
+ # Keep track of the pid so we can know if we have already launched this sim.
323
+ RunLoop::CoreSimulator.simulator_pid = running_simulator_pid
324
+
194
325
  true
195
326
  end
196
327
 
@@ -201,14 +332,20 @@ class RunLoop::CoreSimulator
201
332
  def launch
202
333
  install
203
334
 
335
+ # If the app is the same, install will not launch the simulator.
336
+ # In order to launch the app, the simulator needs to be running.
337
+ # launch_simulator ensures that the sim is launched and will not
338
+ # relaunch it.
339
+ launch_simulator
340
+
204
341
  args = ['simctl', 'launch', device.udid, app.bundle_identifier]
205
- hash = xcrun.exec(args, log_cmd: true, timeout: 20)
342
+ timeout = DEFAULT_OPTIONS[:launch_app_timeout]
343
+ hash = xcrun.exec(args, log_cmd: true, timeout: timeout)
206
344
 
207
345
  exit_status = hash[:exit_status]
208
346
 
209
347
  if exit_status != 0
210
- err = hash[:err]
211
- RunLoop.log_error(err)
348
+ RunLoop.log_error(hash[:out])
212
349
  raise RuntimeError, "Could not launch #{app.bundle_identifier} on #{device}"
213
350
  end
214
351
 
@@ -254,7 +391,7 @@ class RunLoop::CoreSimulator
254
391
  def reset_app_sandbox
255
392
  return true if !app_is_installed?
256
393
 
257
- wait_for_device_state('Shutdown')
394
+ RunLoop::CoreSimulator.wait_for_simulator_state(device, "Shutdown")
258
395
 
259
396
  reset_app_sandbox_internal
260
397
  end
@@ -266,7 +403,9 @@ class RunLoop::CoreSimulator
266
403
  launch_simulator
267
404
 
268
405
  args = ['simctl', 'uninstall', device.udid, app.bundle_identifier]
269
- xcrun.exec(args, log_cmd: true, timeout: 20)
406
+
407
+ timeout = DEFAULT_OPTIONS[:uninstall_app_timeout]
408
+ xcrun.exec(args, log_cmd: true, timeout: timeout)
270
409
 
271
410
  device.simulator_wait_for_stable_state
272
411
  true
@@ -345,12 +484,46 @@ class RunLoop::CoreSimulator
345
484
  #
346
485
  # @note Will only search for the current Xcode simulator.
347
486
  #
348
- # @return [String, nil] The pid as a String or nil if no process is found.
487
+ # @return [Integer, nil] The pid as a String or nil if no process is found.
349
488
  #
350
489
  # @todo Convert this to force UTF8
351
- def sim_pid
490
+ def running_simulator_pid
352
491
  process_name = "MacOS/#{sim_name}"
353
- `xcrun ps x -o pid,command | grep "#{process_name}" | grep -v grep`.strip.split(' ').first
492
+
493
+ args = ["xcrun", "ps", "x", "-o", "pid,command"]
494
+ hash = xcrun.exec(args)
495
+
496
+ exit_status = hash[:exit_status]
497
+ if exit_status != 0
498
+ raise RuntimeError,
499
+ %Q{Could not find the pid of #{sim_name} with:
500
+
501
+ #{args.join(" ")}
502
+
503
+ Command exited with status #{exit_status}
504
+ Message: '#{hash[:out]}'
505
+ }
506
+ end
507
+
508
+ if hash[:out].nil? || hash[:out] == ""
509
+ raise RuntimeError,
510
+ %Q{Could not find the pid of #{sim_name} with:
511
+
512
+ #{args.join(" ")}
513
+
514
+ Command had no output
515
+ }
516
+ end
517
+
518
+ lines = hash[:out].split("\n")
519
+
520
+ match = lines.detect do |line|
521
+ line[/#{process_name}/, 0]
522
+ end
523
+
524
+ return nil if match.nil?
525
+
526
+ match.split(" ").first.to_i
354
527
  end
355
528
 
356
529
  # @!visibility private
@@ -358,34 +531,13 @@ class RunLoop::CoreSimulator
358
531
  launch_simulator
359
532
 
360
533
  args = ['simctl', 'install', device.udid, app.path]
361
- xcrun.exec(args, log_cmd: true, timeout: 20)
534
+ timeout = DEFAULT_OPTIONS[:install_app_timeout]
535
+ xcrun.exec(args, log_cmd: true, timeout: timeout)
362
536
 
363
537
  device.simulator_wait_for_stable_state
364
538
  installed_app_bundle_dir
365
539
  end
366
540
 
367
- # @!visibility private
368
- def wait_for_device_state(target_state)
369
- now = Time.now
370
- timeout = WAIT_FOR_DEVICE_STATE_OPTS[:timeout]
371
- poll_until = now + timeout
372
- delay = WAIT_FOR_DEVICE_STATE_OPTS[:interval]
373
- in_state = false
374
- while Time.now < poll_until
375
- in_state = device.update_simulator_state == target_state
376
- break if in_state
377
- sleep delay
378
- end
379
-
380
- elapsed = Time.now - now
381
- RunLoop.log_debug("Waited for #{elapsed} seconds for device to have state: '#{target_state}'.")
382
-
383
- unless in_state
384
- raise "Expected '#{target_state} but found '#{device.state}' after waiting."
385
- end
386
- in_state
387
- end
388
-
389
541
  # Required for support of iOS 7 CoreSimulators. Can be removed when
390
542
  # Xcode support is dropped.
391
543
  def sdk_gte_8?