run_loop_tcc 2.1.3

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.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/bin/run-loop +19 -0
  4. data/lib/run_loop/abstract.rb +18 -0
  5. data/lib/run_loop/app.rb +372 -0
  6. data/lib/run_loop/cache/cache.rb +68 -0
  7. data/lib/run_loop/cli/cli.rb +48 -0
  8. data/lib/run_loop/cli/codesign.rb +24 -0
  9. data/lib/run_loop/cli/errors.rb +11 -0
  10. data/lib/run_loop/cli/instruments.rb +160 -0
  11. data/lib/run_loop/cli/locale.rb +31 -0
  12. data/lib/run_loop/cli/simctl.rb +257 -0
  13. data/lib/run_loop/cli/tcc.rb +139 -0
  14. data/lib/run_loop/codesign.rb +76 -0
  15. data/lib/run_loop/core.rb +902 -0
  16. data/lib/run_loop/core_simulator.rb +960 -0
  17. data/lib/run_loop/detect_aut/detect.rb +185 -0
  18. data/lib/run_loop/detect_aut/errors.rb +126 -0
  19. data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
  20. data/lib/run_loop/detect_aut/xcode.rb +157 -0
  21. data/lib/run_loop/device.rb +722 -0
  22. data/lib/run_loop/device_agent/app/CBX-Runner.app.zip +0 -0
  23. data/lib/run_loop/device_agent/bin/xctestctl +0 -0
  24. data/lib/run_loop/device_agent/cbxrunner.rb +156 -0
  25. data/lib/run_loop/device_agent/frameworks/Frameworks.zip +0 -0
  26. data/lib/run_loop/device_agent/frameworks.rb +65 -0
  27. data/lib/run_loop/device_agent/ipa/CBX-Runner.app.zip +0 -0
  28. data/lib/run_loop/device_agent/launcher.rb +51 -0
  29. data/lib/run_loop/device_agent/xcodebuild.rb +91 -0
  30. data/lib/run_loop/device_agent/xctestctl.rb +109 -0
  31. data/lib/run_loop/directory.rb +179 -0
  32. data/lib/run_loop/dnssd.rb +148 -0
  33. data/lib/run_loop/dot_dir.rb +87 -0
  34. data/lib/run_loop/dylib_injector.rb +145 -0
  35. data/lib/run_loop/encoding.rb +56 -0
  36. data/lib/run_loop/environment.rb +361 -0
  37. data/lib/run_loop/fifo.rb +40 -0
  38. data/lib/run_loop/host_cache.rb +128 -0
  39. data/lib/run_loop/http/error.rb +15 -0
  40. data/lib/run_loop/http/request.rb +44 -0
  41. data/lib/run_loop/http/retriable_client.rb +166 -0
  42. data/lib/run_loop/http/server.rb +17 -0
  43. data/lib/run_loop/instruments.rb +436 -0
  44. data/lib/run_loop/ipa.rb +142 -0
  45. data/lib/run_loop/l10n.rb +93 -0
  46. data/lib/run_loop/language.rb +63 -0
  47. data/lib/run_loop/lipo.rb +132 -0
  48. data/lib/run_loop/lldb.rb +52 -0
  49. data/lib/run_loop/locale.rb +101 -0
  50. data/lib/run_loop/logging.rb +111 -0
  51. data/lib/run_loop/otool.rb +76 -0
  52. data/lib/run_loop/patches/awesome_print.rb +17 -0
  53. data/lib/run_loop/physical_device/life_cycle.rb +268 -0
  54. data/lib/run_loop/plist_buddy.rb +189 -0
  55. data/lib/run_loop/process_terminator.rb +128 -0
  56. data/lib/run_loop/process_waiter.rb +117 -0
  57. data/lib/run_loop/regex.rb +19 -0
  58. data/lib/run_loop/shell.rb +103 -0
  59. data/lib/run_loop/sim_control.rb +1264 -0
  60. data/lib/run_loop/simctl.rb +275 -0
  61. data/lib/run_loop/sqlite.rb +61 -0
  62. data/lib/run_loop/strings.rb +88 -0
  63. data/lib/run_loop/tcc/TCC.db +0 -0
  64. data/lib/run_loop/tcc/tcc.rb +240 -0
  65. data/lib/run_loop/template.rb +61 -0
  66. data/lib/run_loop/version.rb +182 -0
  67. data/lib/run_loop/xcode.rb +318 -0
  68. data/lib/run_loop/xcrun.rb +107 -0
  69. data/lib/run_loop/xcuitest.rb +550 -0
  70. data/lib/run_loop.rb +230 -0
  71. data/plists/simctl/com.apple.UIAutomation.plist +0 -0
  72. data/plists/simctl/com.apple.UIAutomationPlugIn.plist +0 -0
  73. data/scripts/calabash_script_uia.js +28184 -0
  74. data/scripts/lib/json2.min.js +26 -0
  75. data/scripts/lib/log.js +26 -0
  76. data/scripts/lib/on_alert.js +224 -0
  77. data/scripts/read-cmd.sh +2 -0
  78. data/scripts/run_dismiss_location.js +89 -0
  79. data/scripts/run_loop_basic.js +34 -0
  80. data/scripts/run_loop_fast_uia.js +188 -0
  81. data/scripts/run_loop_host.js +117 -0
  82. data/scripts/run_loop_shared_element.js +125 -0
  83. data/scripts/timeout3 +23 -0
  84. data/scripts/udidetect +0 -0
  85. data/vendor-licenses/FBSimulatorControl.LICENSE +30 -0
  86. data/vendor-licenses/xctestctl.LICENSE +32 -0
  87. metadata +443 -0
@@ -0,0 +1,361 @@
1
+ module RunLoop
2
+ class Environment
3
+
4
+ # Returns the user home directory
5
+ def self.user_home_directory
6
+ if self.xtc?
7
+ home = File.join("./", "tmp", "home")
8
+ FileUtils.mkdir_p(home)
9
+ home
10
+ else
11
+ require 'etc'
12
+ Etc.getpwuid.dir
13
+ end
14
+ end
15
+
16
+ # Returns true if Windows environment
17
+ def self.windows_env?
18
+ if @@windows_env.nil?
19
+ @@windows_env = Environment.host_os_is_win?
20
+ end
21
+
22
+ @@windows_env
23
+ end
24
+
25
+ # Returns true if debugging is enabled.
26
+ def self.debug?
27
+ ENV['DEBUG'] == '1'
28
+ end
29
+
30
+ # Returns true if read debugging is enabled.
31
+ def self.debug_read?
32
+ ENV['DEBUG_READ'] == '1'
33
+ end
34
+
35
+ # Returns true if we are running on the XTC
36
+ def self.xtc?
37
+ ENV['XAMARIN_TEST_CLOUD'] == '1'
38
+ end
39
+
40
+ # Returns the value of DEVICE_TARGET
41
+ def self.device_target
42
+ value = ENV["DEVICE_TARGET"]
43
+ if value.nil? || value == ""
44
+ nil
45
+ else
46
+ value
47
+ end
48
+ end
49
+
50
+ # Returns the value of DEVICE_ENDPOINT
51
+ def self.device_endpoint
52
+ value = ENV["DEVICE_ENDPOINT"]
53
+ if value.nil? || value == ""
54
+ nil
55
+ else
56
+ value
57
+ end
58
+ end
59
+
60
+ # Should the app data be reset between Scenarios?
61
+ def self.reset_between_scenarios?
62
+ ENV["RESET_BETWEEN_SCENARIOS"] == "1"
63
+ end
64
+
65
+ # Returns the value of XCODEPROJ which can be used to specify an Xcode
66
+ # project directory (my.xcodeproj).
67
+ #
68
+ # This is useful if your project has multiple xcodeproj directories.
69
+ #
70
+ # Most users should not set this variable.
71
+ def self.xcodeproj
72
+ value = ENV["XCODEPROJ"]
73
+ if value.nil? || value == ""
74
+ nil
75
+ else
76
+ File.expand_path(value)
77
+ end
78
+ end
79
+
80
+ # Returns the value of DERIVED_DATA which can be used to specify an
81
+ # alternative DerivedData directory.
82
+ #
83
+ # The default is ~/Library/Xcode/DerivedData, but Xcode allows you to
84
+ # change this value.
85
+ def self.derived_data
86
+ value = ENV["DERIVED_DATA"]
87
+ if value.nil? || value == ""
88
+ nil
89
+ else
90
+ File.expand_path(value)
91
+ end
92
+ end
93
+
94
+ # Returns the value of SOLUTION which can be used to specify a
95
+ # Xamarin Studio .sln
96
+ #
97
+ # This is useful if your project has multiple solutions (.sln)
98
+ # and Calabash cannot detect the correct one.
99
+ def self.solution
100
+ value = ENV["SOLUTION"]
101
+ if value.nil? || value == ""
102
+ nil
103
+ else
104
+ File.expand_path(value)
105
+ end
106
+ end
107
+
108
+ # Returns the value of TRACE_TEMPLATE; the Instruments template to use
109
+ # during testing.
110
+ def self.trace_template
111
+ value = ENV['TRACE_TEMPLATE']
112
+ if value.nil? || value == ""
113
+ nil
114
+ else
115
+ File.expand_path(value)
116
+ end
117
+ end
118
+
119
+ # Returns the value of UIA_TIMEOUT. Use this control how long to wait
120
+ # for instruments to launch and attach to your application.
121
+ #
122
+ # Non-empty values are converted to a float.
123
+ def self.uia_timeout
124
+ timeout = ENV['UIA_TIMEOUT']
125
+ timeout ? timeout.to_f : nil
126
+ end
127
+
128
+ # Returns the value of BUNDLE_ID
129
+ def self.bundle_id
130
+ value = ENV['BUNDLE_ID']
131
+ if !value || value == ''
132
+ nil
133
+ else
134
+ value
135
+ end
136
+ end
137
+
138
+ # Returns to the path to the app bundle (simulator builds).
139
+ #
140
+ # Both APP_BUNDLE_PATH and APP are checked and in that order.
141
+ #
142
+ # Use of APP_BUNDLE_PATH is deprecated and will be removed.
143
+ def self.path_to_app_bundle
144
+ value = ENV['APP_BUNDLE_PATH'] || ENV['APP']
145
+ if !value || value == ''
146
+ nil
147
+ else
148
+ File.expand_path(value)
149
+ end
150
+ end
151
+
152
+ # Returns the value of DEVELOPER_DIR
153
+ #
154
+ # @note Never call this directly. Always create an Xcode instance
155
+ # and allow it to derive the path to the Xcode toolchain.
156
+ def self.developer_dir
157
+ value = ENV['DEVELOPER_DIR']
158
+ if !value || value == ''
159
+ nil
160
+ else
161
+ value
162
+ end
163
+ end
164
+
165
+ # Returns the value of CODESIGN_IDENTITY
166
+ def self.codesign_identity
167
+ value = ENV["CODESIGN_IDENTITY"]
168
+ if !value || value == ""
169
+ nil
170
+ else
171
+ value
172
+ end
173
+ end
174
+
175
+ # Returns the value of KEYCHAIN
176
+ #
177
+ # Use this to specify a non-default KEYCHAIN for code signing.
178
+ #
179
+ # The default KEYCHAIN is login.keychain.
180
+ def self.keychain
181
+ value = ENV["KEYCHAIN"]
182
+ if !value || value == ""
183
+ nil
184
+ else
185
+ value
186
+ end
187
+ end
188
+
189
+ # Returns the value of XCTESTCTL
190
+ #
191
+ # Use this to specify a non-default xctestctl binary.
192
+ #
193
+ # The default xctestctl binary is bundled with this gem.
194
+ def self.xctestctl
195
+ value = ENV["XCTESTCTL"]
196
+ if !value || value == ""
197
+ nil
198
+ else
199
+ value
200
+ end
201
+ end
202
+
203
+ # Returns the value of CBXDEVICE
204
+ #
205
+ # Use this to specify a non-default CBX-Runner for physical devices.
206
+ #
207
+ # The default CBX-Runner is bundled with this gem.
208
+ def self.cbxdevice
209
+ value = ENV["CBXDEVICE"]
210
+ if !value || value == ""
211
+ nil
212
+ else
213
+ value
214
+ end
215
+ end
216
+
217
+ # Returns the value of CBXSIM
218
+ #
219
+ # Use this to specify a non-default CBX-Runner for simulators.
220
+ #
221
+ # The default CBX-Runner is bundled with this gem.
222
+ def self.cbxsim
223
+ value = ENV["CBXSIM"]
224
+ if !value || value == ""
225
+ nil
226
+ else
227
+ value
228
+ end
229
+ end
230
+
231
+ # Returns the value of DEVICE_ENDPOINT
232
+ def self.device_agent_url
233
+ value = ENV["DEVICE_AGENT_URL"]
234
+ if value.nil? || value == ""
235
+ nil
236
+ else
237
+ value
238
+ end
239
+ end
240
+
241
+ # Returns true if running in Jenkins CI
242
+ #
243
+ # Checks the value of JENKINS_HOME
244
+ def self.jenkins?
245
+ value = ENV["JENKINS_HOME"]
246
+ !!value && value != ''
247
+ end
248
+
249
+ # Returns true if running in Travis CI
250
+ #
251
+ # Checks the value of TRAVIS
252
+ def self.travis?
253
+ value = ENV["TRAVIS"]
254
+ !!value && value != ''
255
+ end
256
+
257
+ # Returns true if running in Circle CI
258
+ #
259
+ # Checks the value of CIRCLECI
260
+ def self.circle_ci?
261
+ value = ENV["CIRCLECI"]
262
+ !!value && value != ''
263
+ end
264
+
265
+ # Returns true if running in Teamcity
266
+ #
267
+ # Checks the value of TEAMCITY_PROJECT_NAME
268
+ def self.teamcity?
269
+ value = ENV["TEAMCITY_PROJECT_NAME"]
270
+ !!value && value != ''
271
+ end
272
+
273
+ # Returns true if running in Teamcity
274
+ #
275
+ # Checks the value of GITLAB_CI
276
+ def self.gitlab?
277
+ value = ENV["GITLAB_CI"]
278
+ !!value && value != ''
279
+ end
280
+
281
+ # Returns true if running in a CI environment
282
+ def self.ci?
283
+ [
284
+ self.ci_var_defined?,
285
+ self.travis?,
286
+ self.jenkins?,
287
+ self.circle_ci?,
288
+ self.teamcity?,
289
+ self.gitlab?
290
+ ].any?
291
+ end
292
+
293
+ # !@visibility private
294
+ def self.with_debugging(debug, &block)
295
+ if debug
296
+ original_value = ENV['DEBUG']
297
+
298
+ begin
299
+ ENV['DEBUG'] = '1'
300
+ block.call
301
+ ensure
302
+ ENV['DEBUG'] = original_value
303
+ end
304
+
305
+ else
306
+ block.call
307
+ end
308
+ end
309
+
310
+ private
311
+
312
+ # !@visibility private
313
+ def self.ci_var_defined?
314
+ value = ENV["CI"]
315
+ !!value && value != ''
316
+ end
317
+
318
+ # !@visibility private
319
+ # Returns the value of CBXWS. This can be used to override the default
320
+ # CBXDriver.xcworkspace. You should only set this if you are actively
321
+ # developing the CBXDriver.
322
+ def self.cbxws
323
+ value = ENV["CBXWS"]
324
+ if value.nil? || value == ""
325
+ nil
326
+ else
327
+ path = File.expand_path(value)
328
+ if !File.directory?(path)
329
+ raise RuntimeError, %Q[CBXWS is set, but there is no workspace at
330
+ #{path}
331
+
332
+ Only set CBXWS if you are developing new features in the CBXRunner.
333
+
334
+ Check your environment.]
335
+ end
336
+ path
337
+ end
338
+ end
339
+
340
+ private
341
+
342
+ # @visibility private
343
+ WIN_PATTERNS = [
344
+ /bccwin/i,
345
+ /cygwin/i,
346
+ /djgpp/i,
347
+ /mingw/i,
348
+ /mswin/i,
349
+ /wince/i,
350
+ ]
351
+
352
+ # @!visibility private
353
+ @@windows_env = nil
354
+
355
+ # @!visibility private
356
+ def self.host_os_is_win?
357
+ ruby_platform = RbConfig::CONFIG["host_os"]
358
+ !!WIN_PATTERNS.find { |r| ruby_platform =~ r }
359
+ end
360
+ end
361
+ end
@@ -0,0 +1,40 @@
1
+ require 'timeout'
2
+ module RunLoop
3
+ module Fifo
4
+ BUFFER_SIZE = 4096
5
+
6
+ class NoReaderConfiguredError < RuntimeError
7
+ end
8
+
9
+ class WriteTimedOut < RuntimeError
10
+ end
11
+
12
+ def self.write(pipe, msg, options={})
13
+ msg = "#{msg}\n"
14
+ timeout = options[:timeout] || 10
15
+ begin_at = Time.now
16
+ begin
17
+ open(pipe, File::WRONLY | File::NONBLOCK) do |pipe_io|
18
+ bytes_written = 0
19
+ bytes_to_write = msg.length
20
+ until bytes_written >= bytes_to_write do
21
+ begin
22
+ wrote = pipe_io.write_nonblock msg
23
+ bytes_written += wrote
24
+ msg = msg[wrote..-1]
25
+ rescue IO::WaitWritable, Errno::EINTR, Errno::EPIPE
26
+ timeout_left = timeout - (Time.now - begin_at)
27
+ raise WriteTimedOut if timeout_left <= 0
28
+ IO.select nil, [pipe_io], nil, timeout_left
29
+ end
30
+ end
31
+ end
32
+ rescue Errno::ENXIO
33
+ sleep(0.5)
34
+ timeout_left = timeout - (Time.now - begin_at)
35
+ raise NoReaderConfiguredError if timeout_left <= 0
36
+ retry
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,128 @@
1
+ require 'fileutils'
2
+ require 'digest/sha1'
3
+
4
+ module RunLoop
5
+
6
+ # @!visibility private
7
+ # A class for managing an on-disk hash table that represents the current
8
+ # state of the :host strategy run-loop. It is used by Calabash iOS
9
+ # `console_attach` method.
10
+ # @see http://calabashapi.xamarin.com/ios/Calabash/Cucumber/Core.html#console_attach-instance_method
11
+ #
12
+ # Marshal is safe to use here because:
13
+ # 1. This code is not executed on the XTC.
14
+ # 2. Users who muck about with this cache can only hurt themselves.
15
+ class HostCache
16
+
17
+ # The path to the cache file.
18
+ #
19
+ # @!attribute [r] path
20
+ # @return [String] An expanded path to the cache file.
21
+ attr_reader :path
22
+
23
+ # The directory where the cache is stored.
24
+ # @return [String] Expanded path to the default cache directory.
25
+ # @raise [RuntimeError] When the ~/.run_loop exists, but is not a directory.
26
+ def self.default_directory
27
+ run_loop_dir = File.join(RunLoop::Environment.user_home_directory, ".run-loop")
28
+ if !File.exist?(run_loop_dir)
29
+ FileUtils.mkdir(run_loop_dir)
30
+ elsif !File.directory?(run_loop_dir)
31
+ raise %Q[
32
+ Expected ~/.run_loop to be a directory.
33
+
34
+ RunLoop requires this directory to cache files
35
+ ]
36
+
37
+ end
38
+ run_loop_dir
39
+ end
40
+
41
+ # The default cache.
42
+ def self.default
43
+ RunLoop::HostCache.new(self.default_directory)
44
+ end
45
+
46
+ # Creates a new HostCache that is ready for IO.
47
+ #
48
+ # @param [String] directory The directory where the cache file is located.
49
+ # If the directory does not exist, it will be created.
50
+ # @options [Hash] options Options to control the state of the new object.
51
+ # @option [String] filename (host_run_loop.hash) The cache filename.
52
+ # @option [Boolean] clear (false) If true, the current cache will be cleared.
53
+ # @return [RunLoop::HostCache] A cache that is ready for IO.
54
+ def initialize(directory, options = {})
55
+ sha1 = Digest::SHA1.hexdigest 'host_run_loop.hash'
56
+ default_opts = {:filename => sha1,
57
+ :clear => false}
58
+ merged_opts = default_opts.merge(options)
59
+
60
+ dir_expanded = File.expand_path(directory)
61
+ unless Dir.exist?(dir_expanded)
62
+ FileUtils.mkdir_p(dir_expanded)
63
+ end
64
+
65
+ @path = File.join(dir_expanded, merged_opts[:filename])
66
+
67
+ if merged_opts[:clear] && File.exist?(@path)
68
+ FileUtils.rm_rf @path
69
+ end
70
+ end
71
+
72
+ # @!visibility private
73
+ def to_s
74
+ "#<HostCache #{path}>"
75
+ end
76
+
77
+ # @!visibility private
78
+ def inspect
79
+ to_s
80
+ end
81
+
82
+ # Reads the current cache.
83
+ # @return [Hash] A hash representation of the current state of the run-loop.
84
+ def read
85
+ if File.exist? path
86
+ File.open(path) do |file|
87
+ Marshal.load(file)
88
+ end
89
+ else
90
+ self.write({})
91
+ self.read
92
+ end
93
+ end
94
+
95
+ # @!visibility private
96
+ #
97
+ # Writes `hash` as a serial object. The existing data is overwritten.
98
+ #
99
+ # @param [Hash] hash The hash to write.
100
+ # @raise [ArgumentError] The `hash` parameter must not be nil and it must
101
+ # be a Hash.
102
+ # @raise [TypeError] If the hash contains objects that cannot be written
103
+ # by Marshal.dump.
104
+ #
105
+ # @return [Boolean] Returns true if `hash` was successfully Marshal.dump'ed.
106
+ def write(hash)
107
+ if hash.nil?
108
+ raise ArgumentError, 'Expected the hash parameter to be non-nil'
109
+ end
110
+
111
+ unless hash.is_a?(Hash)
112
+ raise ArgumentError, "Expected #{hash} to a Hash, but it is a #{hash.class}"
113
+ end
114
+
115
+ File.open(path, 'w+') do |file|
116
+ Marshal.dump(hash, file)
117
+ end
118
+ true
119
+ end
120
+
121
+ # @!visibility private
122
+ # Clears the current cache.
123
+ # @return [Boolean] Returns true if the hash was cleared.
124
+ def clear
125
+ self.write({})
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,15 @@
1
+ module RunLoop
2
+ module HTTP
3
+
4
+ # Raised when there is a problem communicating with the Calabash test
5
+ # server.
6
+ class Error < StandardError
7
+
8
+ end
9
+
10
+ # Raised when there is a problem creating an HTTP request.
11
+ class RequestError < StandardError
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ module RunLoop
2
+ module HTTP
3
+
4
+ # A representation of an HTTP request that can be passed passed to the HTTP
5
+ # client as an argument for `get` or `post`.
6
+ # @!visibility private
7
+ class Request
8
+ attr_reader :route, :params
9
+
10
+ def initialize(route, params={})
11
+ @route = route
12
+ @params = params
13
+ end
14
+
15
+ # Create a new Request from `route` and `parameters`.
16
+ #
17
+ # @param [String] route The http route for the new request.
18
+ # @param [Array, Hash] parameters An Array or Hash of parameters.
19
+ # @return [Request] A new Request for `route` with `parameters`.
20
+ # @raise [RequestError] Raises an error if the parameters cannot be
21
+ # converted to JSON
22
+ def self.request(route, parameters)
23
+ Request.new(route, Request.data(parameters))
24
+ end
25
+
26
+ private
27
+
28
+ # Converts `parameters` to JSON.
29
+ #
30
+ # @param [Array, Hash] parameters An Array or Hash of parameters.
31
+ # @return [String] A JSON formatted string that represents the parameters.
32
+ # @raise [RequestError] Raises an error if the parameters cannot be
33
+ # converted to JSON
34
+ def self.data(parameters)
35
+ begin
36
+ JSON.generate(parameters)
37
+ rescue *[TypeError, JSON::GeneratorError] => e
38
+ raise RequestError, "#{e}: could not generate JSON from '#{parameters}'"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+