run_loop 2.1.1.pre2 → 2.1.1.pre3

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: c874aaaaba2d83da288814e78328d8b663a4d44a
4
- data.tar.gz: 32a4447b971655081d08d06684e974a907d1da8a
3
+ metadata.gz: b32b64f18fc3ecf44595683f3d6627093ecc5c75
4
+ data.tar.gz: 8f3b475ba5794cda548cbec873399ae16f377992
5
5
  SHA512:
6
- metadata.gz: 518708e1ce2e1b5f305c2c0b337f85dd2ca86d62431052eba8837cf88b5834c37b56fc397ed5c67c0f8520b7430779b2e788180dac14aae5a6856c301b29eca1
7
- data.tar.gz: 1899a1efbc4e93ee4bb37763e6a3cf5caacf7001b7cfdea350bc5c12f2c266b67b844c63791e3d5f6f1691695fb338310dfcda6ead233caf95b9229eaa8732d2
6
+ metadata.gz: be639927d12b83cc3b3ddad8c891ebe5115ede7a6db10b67ebf89d449efc954047251ba4d11c9497a14c94df722f540195abf6e66354b7125dc38266e8e72f89
7
+ data.tar.gz: fbe8b2b8af7d8acd600bd0186ea0c83d3906873dbea938adb863bb0d9450b19d03967cf952220202fa2f98286eabbda3e6ce63b5c9ff7b9ac2d17d01ded0c660
@@ -104,7 +104,7 @@ module RunLoop
104
104
  launch_options = {
105
105
  :args => parse_app_launch_args(options),
106
106
  :udid => detect_device_udid_from_options(options),
107
- :bundle_dir_or_bundle_id => detect_bundle_id_or_bundle_path(options)
107
+ :app => detect_bundle_id_or_bundle_path(options)
108
108
  }
109
109
  run_loop = RunLoop.run(launch_options)
110
110
  puts JSON.generate(run_loop)
@@ -404,20 +404,14 @@ $ bundle exec run-loop simctl manage-processes
404
404
 
405
405
  RunLoop.log_debug("Trying #{tries} times to launch #{app.bundle_identifier} on #{device}")
406
406
 
407
- tries.times do
408
- hash = launch_app_with_simctl
407
+ tries.times do |try|
408
+ # Terminates CoreSimulatorService on failures.
409
+ hash = attempt_to_launch_app_with_simctl
410
+
409
411
  exit_status = hash[:exit_status]
410
412
  if exit_status != 0
411
- out = hash[:out]
412
- RunLoop.log_debug("Failed to launch app.")
413
- out.split($-0).each do |line|
414
- RunLoop.log_debug(" #{line}")
415
- end
416
- # Simulator is probably in a bad state, but this will be super disruptive.
417
- # Let's try a softer approach first - sleep.
418
- # self.terminate_core_simulator_processes
419
- sleep(0.5)
420
- last_error = out
413
+ # Last argument is how long to sleep after an error.
414
+ last_error = handle_failed_app_launch(hash, try, tries, 0.5)
421
415
  else
422
416
  last_error = nil
423
417
  break
@@ -432,14 +426,17 @@ $ bundle exec run-loop simctl manage-processes
432
426
  ]
433
427
  end
434
428
 
429
+ wait_for_app_launch
430
+ end
431
+
432
+ # @!visibility private
433
+ def wait_for_app_launch
435
434
  options = {
436
435
  :timeout => 10,
437
436
  :raise_on_timeout => true
438
437
  }
439
-
440
438
  RunLoop::ProcessWaiter.new(app.executable_name, options).wait_for_any
441
439
  device.simulator_wait_for_stable_state
442
-
443
440
  true
444
441
  end
445
442
 
@@ -623,6 +620,39 @@ Command had no output
623
620
  xcrun.exec(args, log_cmd: true, timeout: timeout)
624
621
  end
625
622
 
623
+ # @!visibility private
624
+ def handle_failed_app_launch(hash, try, tries, wait_time)
625
+ out = hash[:out]
626
+ RunLoop.log_debug("Failed to launch app on try #{try + 1} of #{tries}.")
627
+ out.split($-0).each do |line|
628
+ RunLoop.log_debug(" #{line}")
629
+ end
630
+ # If we timed out on the launch, the CoreSimulator processes are quit
631
+ # (see above). If at all possible, we want to avoid terminating
632
+ # CoreSimulatorService, because it takes a long time to launch.
633
+ sleep(wait_time) if wait_time > 0
634
+
635
+ out
636
+ end
637
+
638
+ # @!visibility private
639
+ def attempt_to_launch_app_with_simctl
640
+ begin
641
+ hash = launch_app_with_simctl
642
+ rescue RunLoop::Xcrun::TimeoutError => e
643
+ hash = {
644
+ :exit_status => 1,
645
+ :out => e.message
646
+ }
647
+ # Simulator is probably in a bad state. Terminates the
648
+ # CoreSimulatorService. Restarting this service is expensive!
649
+ RunLoop::CoreSimulator.terminate_core_simulator_processes
650
+ Kernel.sleep(0.5)
651
+ launch_simulator
652
+ end
653
+ hash
654
+ end
655
+
626
656
  # Required for support of iOS 7 CoreSimulators. Can be removed when
627
657
  # Xcode support is dropped.
628
658
  def sdk_gte_8?
@@ -1146,7 +1146,10 @@ module RunLoop
1146
1146
  line[/Apple Watch/, 0],
1147
1147
  line[/watchOS/, 0],
1148
1148
  line[/Apple TV/, 0],
1149
- line[/tvOS/, 0]
1149
+ line[/tvOS/, 0],
1150
+ line[/Devices/, 0],
1151
+ line[/CoreSimulatorService/, 0],
1152
+ line[/simctl\[.+\]/, 0]
1150
1153
  ].any?
1151
1154
 
1152
1155
  if not_ios
@@ -30,18 +30,18 @@ module RunLoop
30
30
  end
31
31
 
32
32
  # @!visibility private
33
- attr_accessor :device
33
+ attr_reader :device
34
34
 
35
35
  # @!visibility private
36
- #
37
- # @param [RunLoop::Device] device Cannot be nil.
38
- def initialize(device)
39
- @device = device
36
+ def initialize
37
+ @ios_devices = []
38
+ @tvos_devices = []
39
+ @watchos_devices = []
40
40
  end
41
41
 
42
42
  # @!visibility private
43
43
  def to_s
44
- "#<Simctl: #{device.name} #{device.udid}>"
44
+ "#<Simctl: #{xcode.version}>"
45
45
  end
46
46
 
47
47
  # @!visibility private
@@ -49,6 +49,15 @@ module RunLoop
49
49
  to_s
50
50
  end
51
51
 
52
+ # @!visibility private
53
+ def simulators
54
+ simulators = ios_devices
55
+ if simulators.empty?
56
+ simulators = fetch_devices![:ios]
57
+ end
58
+ simulators
59
+ end
60
+
52
61
  # @!visibility private
53
62
  #
54
63
  # This method is not supported on Xcode < 7 - returns nil.
@@ -62,8 +71,9 @@ module RunLoop
62
71
  # TODO ensure a booted state.
63
72
  #
64
73
  # @param [String] bundle_id The CFBundleIdentifier of the app.
74
+ # @param [RunLoop::Device] device The device under test.
65
75
  # @return [String] The path to the .app bundle if it exists; nil otherwise.
66
- def app_container(bundle_id)
76
+ def app_container(device, bundle_id)
67
77
  return nil if !xcode.version_gte_7?
68
78
  cmd = ["simctl", "get_app_container", device.udid, bundle_id]
69
79
  hash = execute(cmd, DEFAULTS)
@@ -78,12 +88,157 @@ module RunLoop
78
88
 
79
89
  private
80
90
 
91
+ # @!visibility private
92
+ attr_reader :ios_devices, :tvos_devices, :watchos_devices
93
+
81
94
  # @!visibility private
82
95
  def execute(array, options)
83
96
  merged = DEFAULTS.merge(options)
84
97
  xcrun.exec(array, merged)
85
98
  end
86
99
 
100
+ # @!visibility private
101
+ #
102
+ # Starting in Xcode 7, simctl allows a --json option for listing devices.
103
+ #
104
+ # On Xcode 6, we will fall back to SimControl which does a line-by-line
105
+ # processing of `simctl list devices`. tvOS and watchOS devices are not
106
+ # available on Xcode < 7.
107
+ #
108
+ # This is a destructive operation on `@ios_devices`, `@tvos_devices`, and
109
+ # `@watchos_devices`. Callers should check for existing devices to avoid
110
+ # the overhead of calling `simctl list devices --json`.
111
+ def fetch_devices!
112
+ if !xcode.version_gte_7?
113
+ return {
114
+ :ios => sim_control.simulators,
115
+ :tvos => [],
116
+ :watchos => []
117
+ }
118
+ end
119
+
120
+ @ios_devices = []
121
+ @tvos_devices = []
122
+ @watchos_devices = []
123
+
124
+ cmd = ["simctl", "list", "devices", "--json"]
125
+ hash = execute(cmd, DEFAULTS)
126
+
127
+ out = hash[:out]
128
+ exit_status = hash[:exit_status]
129
+ if exit_status != 0
130
+ raise RuntimeError, %Q[simctl exited #{exit_status}:
131
+
132
+ #{out}
133
+
134
+ while trying to list devices.
135
+ ]
136
+ end
137
+
138
+ devices = json_to_hash(out)["devices"]
139
+
140
+ devices.each do |key, device_list|
141
+ version = device_key_to_version(key)
142
+ bucket = bucket_for_key(key)
143
+
144
+ device_list.each do |record|
145
+ if device_available?(record)
146
+ bucket << device_from_record(record, version)
147
+ end
148
+ end
149
+ end
150
+ {
151
+ :ios => ios_devices,
152
+ :tvos => tvos_devices,
153
+ :watchos => watchos_devices
154
+ }
155
+ end
156
+
157
+ # @!visibility private
158
+ #
159
+ # command_runner_ng combines stderr and stdout and starting in Xcode 7.3,
160
+ # simctl has started generating stderr output. This must be filtered out
161
+ # so that we can parse the JSON response.
162
+ def filter_stderr(out)
163
+ out.split($-0).map do |line|
164
+ if stderr_line?(line)
165
+ nil
166
+ else
167
+ line
168
+ end
169
+ end.compact.join($-0)
170
+ end
171
+
172
+ # @!visibility private
173
+ def stderr_line?(line)
174
+ line[/CoreSimulatorService/, 0] || line[/simctl\[.+\]/, 0]
175
+ end
176
+
177
+ # @!visibility private
178
+ def json_to_hash(json)
179
+ filtered = filter_stderr(json)
180
+ begin
181
+ JSON.parse(filtered)
182
+ rescue TypeError, JSON::ParserError => e
183
+ raise RuntimeError, %Q[Could not parse simctl JSON response:
184
+
185
+ #{e}
186
+ ]
187
+ end
188
+ end
189
+
190
+ # @!visibility private
191
+ def device_key_is_ios?(key)
192
+ key[/iOS/, 0]
193
+ end
194
+
195
+ # @!visibility private
196
+ def device_key_is_tvos?(key)
197
+ key[/tvOS/, 0]
198
+ end
199
+
200
+ # @!visibility private
201
+ def device_key_is_watchos?(key)
202
+ key[/watchOS/, 0]
203
+ end
204
+
205
+ # @!visibility private
206
+ def device_key_to_version(key)
207
+ str = key.split(" ").last
208
+ RunLoop::Version.new(str)
209
+ end
210
+
211
+ # @!visibility private
212
+ def device_available?(record)
213
+ record["availability"] == "(available)"
214
+ end
215
+
216
+ # @!visibility private
217
+ def device_from_record(record, version)
218
+ RunLoop::Device.new(record["name"],
219
+ version,
220
+ record["udid"],
221
+ record["state"])
222
+ end
223
+
224
+ # @!visibility private
225
+ def bucket_for_key(key)
226
+ if device_key_is_ios?(key)
227
+ bin = @ios_devices
228
+ elsif device_key_is_tvos?(key)
229
+ bin = @tvos_devices
230
+ elsif device_key_is_watchos?(key)
231
+ bin = @watchos_devices
232
+ else
233
+ raise RuntimeError, "Unexpected key while processing simctl output:
234
+
235
+ key = #{key}
236
+
237
+ is not an iOS, tvOS, or watchOS device"
238
+ end
239
+ bin
240
+ end
241
+
87
242
  # @!visibility private
88
243
  def xcrun
89
244
  @xcrun ||= RunLoop::Xcrun.new
@@ -93,5 +248,12 @@ module RunLoop
93
248
  def xcode
94
249
  @xcode ||= RunLoop::Xcode.new
95
250
  end
251
+
252
+ # @!visibility private
253
+ # Support for Xcode < 7 when trying to collect simulators. Xcode 7 allows
254
+ # a --json option which is much easier to parse.
255
+ def sim_control
256
+ @sim_control ||= RunLoop::SimControl.new
257
+ end
96
258
  end
97
259
  end
@@ -1,5 +1,5 @@
1
1
  module RunLoop
2
- VERSION = "2.1.1.pre2"
2
+ VERSION = "2.1.1.pre3"
3
3
 
4
4
  # A model of a software release version that can be used to compare two versions.
5
5
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: run_loop
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1.pre2
4
+ version: 2.1.1.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karl Krukow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-08 00:00:00.000000000 Z
11
+ date: 2016-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json