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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/bin/run-loop +19 -0
- data/lib/run_loop/abstract.rb +18 -0
- data/lib/run_loop/app.rb +372 -0
- data/lib/run_loop/cache/cache.rb +68 -0
- data/lib/run_loop/cli/cli.rb +48 -0
- data/lib/run_loop/cli/codesign.rb +24 -0
- data/lib/run_loop/cli/errors.rb +11 -0
- data/lib/run_loop/cli/instruments.rb +160 -0
- data/lib/run_loop/cli/locale.rb +31 -0
- data/lib/run_loop/cli/simctl.rb +257 -0
- data/lib/run_loop/cli/tcc.rb +139 -0
- data/lib/run_loop/codesign.rb +76 -0
- data/lib/run_loop/core.rb +902 -0
- data/lib/run_loop/core_simulator.rb +960 -0
- data/lib/run_loop/detect_aut/detect.rb +185 -0
- data/lib/run_loop/detect_aut/errors.rb +126 -0
- data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
- data/lib/run_loop/detect_aut/xcode.rb +157 -0
- data/lib/run_loop/device.rb +722 -0
- data/lib/run_loop/device_agent/app/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/bin/xctestctl +0 -0
- data/lib/run_loop/device_agent/cbxrunner.rb +156 -0
- data/lib/run_loop/device_agent/frameworks/Frameworks.zip +0 -0
- data/lib/run_loop/device_agent/frameworks.rb +65 -0
- data/lib/run_loop/device_agent/ipa/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/launcher.rb +51 -0
- data/lib/run_loop/device_agent/xcodebuild.rb +91 -0
- data/lib/run_loop/device_agent/xctestctl.rb +109 -0
- data/lib/run_loop/directory.rb +179 -0
- data/lib/run_loop/dnssd.rb +148 -0
- data/lib/run_loop/dot_dir.rb +87 -0
- data/lib/run_loop/dylib_injector.rb +145 -0
- data/lib/run_loop/encoding.rb +56 -0
- data/lib/run_loop/environment.rb +361 -0
- data/lib/run_loop/fifo.rb +40 -0
- data/lib/run_loop/host_cache.rb +128 -0
- data/lib/run_loop/http/error.rb +15 -0
- data/lib/run_loop/http/request.rb +44 -0
- data/lib/run_loop/http/retriable_client.rb +166 -0
- data/lib/run_loop/http/server.rb +17 -0
- data/lib/run_loop/instruments.rb +436 -0
- data/lib/run_loop/ipa.rb +142 -0
- data/lib/run_loop/l10n.rb +93 -0
- data/lib/run_loop/language.rb +63 -0
- data/lib/run_loop/lipo.rb +132 -0
- data/lib/run_loop/lldb.rb +52 -0
- data/lib/run_loop/locale.rb +101 -0
- data/lib/run_loop/logging.rb +111 -0
- data/lib/run_loop/otool.rb +76 -0
- data/lib/run_loop/patches/awesome_print.rb +17 -0
- data/lib/run_loop/physical_device/life_cycle.rb +268 -0
- data/lib/run_loop/plist_buddy.rb +189 -0
- data/lib/run_loop/process_terminator.rb +128 -0
- data/lib/run_loop/process_waiter.rb +117 -0
- data/lib/run_loop/regex.rb +19 -0
- data/lib/run_loop/shell.rb +103 -0
- data/lib/run_loop/sim_control.rb +1264 -0
- data/lib/run_loop/simctl.rb +275 -0
- data/lib/run_loop/sqlite.rb +61 -0
- data/lib/run_loop/strings.rb +88 -0
- data/lib/run_loop/tcc/TCC.db +0 -0
- data/lib/run_loop/tcc/tcc.rb +240 -0
- data/lib/run_loop/template.rb +61 -0
- data/lib/run_loop/version.rb +182 -0
- data/lib/run_loop/xcode.rb +318 -0
- data/lib/run_loop/xcrun.rb +107 -0
- data/lib/run_loop/xcuitest.rb +550 -0
- data/lib/run_loop.rb +230 -0
- data/plists/simctl/com.apple.UIAutomation.plist +0 -0
- data/plists/simctl/com.apple.UIAutomationPlugIn.plist +0 -0
- data/scripts/calabash_script_uia.js +28184 -0
- data/scripts/lib/json2.min.js +26 -0
- data/scripts/lib/log.js +26 -0
- data/scripts/lib/on_alert.js +224 -0
- data/scripts/read-cmd.sh +2 -0
- data/scripts/run_dismiss_location.js +89 -0
- data/scripts/run_loop_basic.js +34 -0
- data/scripts/run_loop_fast_uia.js +188 -0
- data/scripts/run_loop_host.js +117 -0
- data/scripts/run_loop_shared_element.js +125 -0
- data/scripts/timeout3 +23 -0
- data/scripts/udidetect +0 -0
- data/vendor-licenses/FBSimulatorControl.LICENSE +30 -0
- data/vendor-licenses/xctestctl.LICENSE +32 -0
- 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
|
+
|