run_loop 2.1.1.pre2 → 2.1.1.pre3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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