run_loop 2.1.6 → 2.1.7

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: ff141b60144498a30b21eb09fa12ac5a6c8e95fd
4
- data.tar.gz: 8f8f501c79a466e8aefae117ead31fa5fc1b0d38
3
+ metadata.gz: 8451119a8e88cf2179b1b7a0bfc554a19459e9c5
4
+ data.tar.gz: 0b75d4af7f258d99780c624750dc3e3f241e5581
5
5
  SHA512:
6
- metadata.gz: e2654a32fa02ca8e27746102748201934a2d27fc5a995fe58dd10e94b147e4688876fc07c6625b513742410224800e2848e5f394416db6be15385061ff7300a5
7
- data.tar.gz: fa60c8ab92dfc6840f45bb242be4b2fec1e4d1394d2f89542e1e159a54c10f8b082d019724c83c26dd3d860ffb9a438faeb0db0d5f65c2defd0b09d73c0c6e99
6
+ metadata.gz: ad70df268ab1bcd8001f71cb81499653ec67428be5e5fd78a7a6a89d83e527b7fe3e2da982be52bb0c1480eee57de119b40b2a1c3a4b290e6a5d5b5c9565afb2
7
+ data.tar.gz: d75408caf251d7b4a4ebf532adfe361697dc7cf46e4aab6f15c6447818622604c13205a764202ff5796079e2e28ec0fed871fbe73309d63cdbf1f99e63eaeed5
data/lib/run_loop.rb CHANGED
@@ -48,6 +48,7 @@ require "run_loop/http/server"
48
48
  require "run_loop/http/request"
49
49
  require "run_loop/http/retriable_client"
50
50
  require "run_loop/physical_device/life_cycle"
51
+ require "run_loop/physical_device/ios_device_manager"
51
52
 
52
53
  module RunLoop
53
54
 
data/lib/run_loop/app.rb CHANGED
@@ -180,7 +180,7 @@ Bundle must:
180
180
  # See #marketing_version
181
181
  alias_method :short_bundle_version, :marketing_version
182
182
 
183
- # Returns the CFBundleVersionString of the app as Version instance.
183
+ # Returns the CFBundleVersion of the app as Version instance.
184
184
  #
185
185
  # Apple docs:
186
186
  #
@@ -195,14 +195,14 @@ Bundle must:
195
195
  # @return [RunLoop::Version, nil] Returns a Version instance if the
196
196
  # CFBundleVersion string is well formed and nil if not.
197
197
  def build_version
198
- string = plist_buddy.plist_read("CFBundleVersionString", info_plist_path)
198
+ string = plist_buddy.plist_read("CFBundleVersion", info_plist_path)
199
199
  begin
200
200
  version = RunLoop::Version.new(string)
201
201
  rescue
202
202
  if string && string != ""
203
- RunLoop.log_debug("CFBundleVersionString: '#{string}' is not a well formed version string")
203
+ RunLoop.log_debug("CFBundleVersion: '#{string}' is not a well formed version string")
204
204
  else
205
- RunLoop.log_debug("CFBundleVersionString is not defined in Info.plist")
205
+ RunLoop.log_debug("CFBundleVersion is not defined in Info.plist")
206
206
  end
207
207
  version = nil
208
208
  end
@@ -218,7 +218,7 @@ Bundle must:
218
218
  executables = []
219
219
  Dir.glob("#{path}/**/*") do |file|
220
220
  next if skip_executable_check?(file)
221
- if otool(file).executable?
221
+ if otool.executable?(file)
222
222
  executables << file
223
223
  end
224
224
  end
@@ -262,9 +262,13 @@ Bundle must:
262
262
  end
263
263
 
264
264
  # @!visibility private
265
- # An otool factory.
266
- def otool(file)
267
- RunLoop::Otool.new(file)
265
+ def otool
266
+ @otool ||= RunLoop::Otool.new(xcode)
267
+ end
268
+
269
+ # @!visibility private
270
+ def xcode
271
+ @xcode ||= RunLoop::Xcode.new
268
272
  end
269
273
 
270
274
  # @!visibility private
@@ -30,8 +30,8 @@ module RunLoop
30
30
  desc 'instruments', "Interact with Xcode's command-line instruments"
31
31
  subcommand 'instruments', RunLoop::CLI::Instruments
32
32
 
33
- desc 'simctl', "Interact with Xcode's command-line simctl"
34
- subcommand 'simctl', RunLoop::CLI::Simctl
33
+ desc "simctl", "Interact with Xcode's command-line simctl"
34
+ subcommand "simctl", RunLoop::CLI::Simctl
35
35
 
36
36
  desc "locale", "Tools for interacting with locales"
37
37
  subcommand "locale", RunLoop::CLI::Locale
@@ -103,11 +103,6 @@ module RunLoop
103
103
 
104
104
  begin
105
105
  RunLoop::CoreSimulator.terminate_core_simulator_processes
106
- process_name = "com.apple.CoreSimulator.CoreSimulatorService"
107
- RunLoop::ProcessWaiter.new(process_name).pids.each do |pid|
108
- kill_options = { :timeout => 0.5 }
109
- RunLoop::ProcessTerminator.new(pid, 'KILL', process_name, kill_options)
110
- end
111
106
  ensure
112
107
  ENV['DEBUG'] = original_value if debug
113
108
  end
data/lib/run_loop/core.rb CHANGED
@@ -65,7 +65,8 @@ module RunLoop
65
65
  xcode = options[:xcode] || RunLoop::Xcode.new
66
66
  instruments = options[:instruments] || RunLoop::Instruments.new
67
67
 
68
- if xcode.version_gte_8?
68
+ # Guard against Xcode version check on the XTC.
69
+ if !RunLoop::Environment.xtc? && xcode.version_gte_8?
69
70
  raise %Q[
70
71
  UIAutomation is not available on Xcode >= 8.*.
71
72
 
@@ -22,7 +22,8 @@ class RunLoop::CoreSimulator
22
22
  :install_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
23
23
  :uninstall_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
24
24
  :launch_app_timeout => RunLoop::Environment.ci? ? 120 : 30,
25
- :wait_for_state_timeout => RunLoop::Environment.ci? ? 120 : 30
25
+ :wait_for_state_timeout => RunLoop::Environment.ci? ? 120 : 30,
26
+ :app_launch_retries => RunLoop::Environment.ci? ? 5 : 3
26
27
  }
27
28
 
28
29
  # @!visibility private
@@ -178,9 +179,8 @@ class RunLoop::CoreSimulator
178
179
  #
179
180
  # @param [RunLoop::Device] simulator The simulator to erase
180
181
  # @param [Hash] options Control the behavior of the method.
181
- # @option options [Numeric] :timeout (180) How long tow wait for simctl to
182
- # shutdown and erase the simulator. The timeout is apply separately to
183
- # each command.
182
+ # @option options [Numeric] :timeout How long to wait for simctl to
183
+ # shutdown the simulator. This is necessary for the erase to succeed.
184
184
  #
185
185
  # @raise RuntimeError If the simulator cannot be shutdown
186
186
  # @raise RuntimeError If the simulator cannot be erased
@@ -191,61 +191,13 @@ class RunLoop::CoreSimulator
191
191
  "#{simulator} is a physical device. This method is only for Simulators"
192
192
  end
193
193
 
194
- default_options = {
195
- :timeout => 60*3
196
- }
197
-
198
- merged_options = default_options.merge(options)
199
-
200
- self.quit_simulator
201
-
202
- xcrun = merged_options[:xcrun] || RunLoop::Xcrun.new
203
- timeout = merged_options[:timeout]
204
- xcrun_opts = {
205
- :log_cmd => true,
206
- :timeout => timeout
207
- }
208
-
209
- if simulator.update_simulator_state != "Shutdown"
210
- args = ["simctl", "shutdown", simulator.udid]
211
- xcrun.run_command_in_context(args, xcrun_opts)
212
- begin
213
- self.wait_for_simulator_state(simulator, "Shutdown")
214
- rescue RuntimeError => _
215
- raise RuntimeError, %Q{
216
- Could not erase simulator because it could not be Shutdown.
194
+ merged_options = DEFAULT_OPTIONS.merge(options)
195
+ simctl = merged_options[:simctl] || RunLoop::Simctl.new
196
+ timeout = merged_options[:timeout] || merged_options[:wait_for_state_timeout]
217
197
 
218
- This usually means your CoreSimulator processes need to be restarted.
219
-
220
- You can restart the CoreSimulator processes with this command:
221
-
222
- $ bundle exec run-loop simctl manage-processes
223
-
224
- }
225
-
226
- end
227
- end
228
-
229
- args = ["simctl", "erase", simulator.udid]
230
- hash = xcrun.run_command_in_context(args, xcrun_opts)
231
-
232
- if hash[:exit_status] != 0
233
- raise RuntimeError, %Q{
234
- Could not erase simulator because simctl returned this error:
235
-
236
- #{hash[:out]}
237
-
238
- This usually means your CoreSimulator processes need to be restarted.
239
-
240
- You can restart the CoreSimulator processes with this command:
241
-
242
- $ bundle exec run-loop simctl manage-processes
243
-
244
- }
245
-
246
- end
247
-
248
- hash
198
+ simctl.erase(simulator,
199
+ timeout,
200
+ WAIT_FOR_SIMULATOR_STATE_INTERVAL)
249
201
  end
250
202
 
251
203
  # @!visibility private
@@ -351,6 +303,11 @@ $ bundle exec run-loop simctl manage-processes
351
303
  @xcrun ||= RunLoop::Xcrun.new
352
304
  end
353
305
 
306
+ # @!visibility private
307
+ def simctl
308
+ @simctl ||= RunLoop::Simctl.new
309
+ end
310
+
354
311
  # Launch the simulator indicated by device.
355
312
  def launch_simulator
356
313
 
@@ -404,29 +361,19 @@ $ bundle exec run-loop simctl manage-processes
404
361
  # relaunch it.
405
362
  launch_simulator
406
363
 
407
- tries = RunLoop::Environment.ci? ? 5 : 3
408
- last_error = nil
364
+ tries = app_launch_retries
409
365
 
410
366
  RunLoop.log_debug("Trying #{tries} times to launch #{app.bundle_identifier} on #{device}")
411
367
 
412
- tries.times do |try|
413
- # Terminates CoreSimulatorService on failures.
414
- hash = attempt_to_launch_app_with_simctl
415
-
416
- exit_status = hash[:exit_status]
417
- if exit_status != 0
418
- # Last argument is how long to sleep after an error.
419
- last_error = handle_failed_app_launch(hash, try, tries, 0.5)
420
- else
421
- last_error = nil
422
- break
423
- end
424
- end
368
+ last_error = try_to_launch_app_n_times(tries)
425
369
 
426
370
  if last_error
427
- raise RuntimeError, %Q[Could not launch #{app.bundle_identifier} on #{device}
371
+ raise RuntimeError, %Q[
372
+ Could not launch #{app.bundle_identifier} on #{device} after trying #{tries} times:
428
373
 
429
- #{last_error}
374
+ #{last_error}:
375
+
376
+ #{last_error.message}
430
377
 
431
378
  ]
432
379
  end
@@ -487,10 +434,8 @@ $ bundle exec run-loop simctl manage-processes
487
434
 
488
435
  launch_simulator
489
436
 
490
- args = ['simctl', 'uninstall', device.udid, app.bundle_identifier]
491
-
492
437
  timeout = DEFAULT_OPTIONS[:uninstall_app_timeout]
493
- xcrun.run_command_in_context(args, log_cmd: true, timeout: timeout)
438
+ simctl.uninstall(device, app, timeout)
494
439
 
495
440
  device.simulator_wait_for_stable_state
496
441
  true
@@ -610,9 +555,8 @@ Command had no output
610
555
  def install_app_with_simctl
611
556
  launch_simulator
612
557
 
613
- args = ['simctl', 'install', device.udid, app.path]
614
558
  timeout = DEFAULT_OPTIONS[:install_app_timeout]
615
- xcrun.run_command_in_context(args, log_cmd: true, timeout: timeout)
559
+ simctl.install(device, app, timeout)
616
560
 
617
561
  device.simulator_wait_for_stable_state
618
562
  installed_app_bundle_dir
@@ -620,42 +564,48 @@ Command had no output
620
564
 
621
565
  # @!visibility private
622
566
  def launch_app_with_simctl
623
- args = ['simctl', 'launch', device.udid, app.bundle_identifier]
624
567
  timeout = DEFAULT_OPTIONS[:launch_app_timeout]
625
- xcrun.run_command_in_context(args, log_cmd: true, timeout: timeout)
568
+ simctl.launch(device, app, timeout)
626
569
  end
627
570
 
628
571
  # @!visibility private
629
- def handle_failed_app_launch(hash, try, tries, wait_time)
630
- out = hash[:out]
631
- RunLoop.log_debug("Failed to launch app on try #{try + 1} of #{tries}.")
632
- out.split($-0).each do |line|
633
- RunLoop.log_debug(" #{line}")
572
+ #
573
+ # Returns nil if launch_app_with_simctl succeeds and the error if it fails.
574
+ def try_to_launch_app
575
+ begin
576
+ launch_app_with_simctl
577
+ nil
578
+ rescue RuntimeError, RunLoop::Xcrun::TimeoutError => error
579
+ # Simulator is probably in a bad state. Restart the service.
580
+ RunLoop::CoreSimulator.terminate_core_simulator_processes
581
+ Kernel.sleep(0.5)
582
+ launch_simulator
583
+ error
634
584
  end
635
- # If we timed out on the launch, the CoreSimulator processes are quit
636
- # (see above). If at all possible, we want to avoid terminating
637
- # CoreSimulatorService, because it takes a long time to launch.
638
- sleep(wait_time) if wait_time > 0
585
+ end
639
586
 
640
- out
587
+ # @!visibility private
588
+ def app_launch_retries
589
+ DEFAULT_OPTIONS[:app_launch_retries]
641
590
  end
642
591
 
643
592
  # @!visibility private
644
- def attempt_to_launch_app_with_simctl
645
- begin
646
- hash = launch_app_with_simctl
647
- rescue RunLoop::Xcrun::TimeoutError => e
648
- hash = {
649
- :exit_status => 1,
650
- :out => e.message
651
- }
652
- # Simulator is probably in a bad state. Terminates the
653
- # CoreSimulatorService. Restarting this service is expensive!
654
- RunLoop::CoreSimulator.terminate_core_simulator_processes
655
- Kernel.sleep(0.5)
656
- launch_simulator
593
+ #
594
+ # Returns nil if launch_app_with_simctl succeeds and the error if it fails.
595
+ def try_to_launch_app_n_times(tries)
596
+ last_error = nil
597
+
598
+ tries.times do |try|
599
+ # Terminates CoreSimulatorService on failures and launches the simulator again.
600
+ # Returns nil if app launched.
601
+ # Returns rescued Runtime or Timeout errors.
602
+ last_error = try_to_launch_app
603
+
604
+ break if last_error.nil?
605
+ RunLoop.log_debug("Failed to launch app on try #{try + 1} of #{tries}.")
657
606
  end
658
- hash
607
+
608
+ last_error
659
609
  end
660
610
 
661
611
  # Required for support of iOS 7 CoreSimulators. Can be removed when
@@ -4,6 +4,9 @@ module RunLoop
4
4
  require 'securerandom'
5
5
  include RunLoop::Regex
6
6
 
7
+ require "run_loop/shell"
8
+ include RunLoop::Shell
9
+
7
10
  # Starting in Xcode 7, iOS 9 simulators have a new "booting" state.
8
11
  #
9
12
  # The simulator must completely boot before run-loop tries to do things
@@ -39,7 +42,6 @@ module RunLoop
39
42
  attr_reader :simulator_accessibility_plist_path
40
43
  attr_reader :simulator_preferences_plist_path
41
44
  attr_reader :simulator_log_file_path
42
- attr_reader :pbuddy
43
45
 
44
46
  # Create a new device.
45
47
  #
@@ -268,7 +270,7 @@ version: #{version}
268
270
  raise RuntimeError, 'This method is available only for simulators'
269
271
  end
270
272
 
271
- @state = fetch_simulator_state
273
+ @state = simctl.simulator_state_as_string(self)
272
274
  end
273
275
 
274
276
  # @!visibility private
@@ -498,20 +500,35 @@ version: #{version}
498
500
  global_plist = simulator_global_preferences_path
499
501
 
500
502
  cmd = [
501
- "PlistBuddy",
503
+ "/usr/libexec/PlistBuddy",
502
504
  "-c",
503
505
  "Add :AppleLanguages:0 string '#{lang_code}'",
504
506
  global_plist
505
507
  ]
506
508
 
507
509
  # RunLoop::PlistBuddy cannot add items to arrays.
508
- xcrun.run_command_in_context(cmd, {:log_cmd => true})
510
+ hash = run_shell_command(cmd, {:log_cmd => true})
511
+
512
+ if hash[:exit_status] != 0
513
+ raise RuntimeError, %Q[
514
+ Could not update the Simulator languages because this command:
515
+
516
+ #{cmd.join(" ")}
517
+
518
+ failed with this output:
519
+
520
+ #{hash[:out]}
521
+
522
+ ]
523
+ end
509
524
 
510
525
  simulator_languages
511
526
  end
512
527
 
513
528
  private
514
529
 
530
+ attr_reader :pbuddy, :simctl, :xcrun
531
+
515
532
  # @!visibility private
516
533
  def xcrun
517
534
  RunLoop::Xcrun.new
@@ -523,43 +540,8 @@ version: #{version}
523
540
  end
524
541
 
525
542
  # @!visibility private
526
- def detect_state_from_line(line)
527
-
528
- if line[/unavailable/, 0]
529
- RunLoop.log_debug("Simulator state is unavailable: #{line}")
530
- return 'Unavailable'
531
- end
532
-
533
- state = line[/(Booted|Shutdown|Shutting Down)/,0]
534
-
535
- if state.nil?
536
- RunLoop.log_debug("Simulator state is unknown: #{line}")
537
- 'Unknown'
538
- else
539
- state
540
- end
541
- end
542
-
543
- # @!visibility private
544
- def fetch_simulator_state
545
- if physical_device?
546
- raise RuntimeError, 'This method is available only for simulators'
547
- end
548
-
549
- args = ['simctl', 'list', 'devices']
550
- hash = xcrun.run_command_in_context(args)
551
- out = hash[:out]
552
-
553
- matched_line = out.split("\n").find do |line|
554
- line.include?(udid)
555
- end
556
-
557
- if matched_line.nil?
558
- raise RuntimeError,
559
- "Expected a simulator with udid '#{udid}', but found none"
560
- end
561
-
562
- detect_state_from_line(matched_line)
543
+ def simctl
544
+ @simctl ||= RunLoop::Simctl.new
563
545
  end
564
546
 
565
547
  # @!visibility private