run_loop_tcc 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
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,148 @@
1
+ module RunLoop
2
+
3
+ # @!visibility private
4
+ # This class is a work in progress.
5
+ #
6
+ # At the moment, it is only useful for debugging the bonjour
7
+ # server that is started by DeviceAgent.
8
+ class DNSSD
9
+
10
+ # @!visibility private
11
+ def self.factory(json)
12
+ array = JSON.parse(json, {:symbolize_names => true})
13
+ array.map do |dns|
14
+ RunLoop::DNSSD.new(dns[:service],
15
+ dns[:ip],
16
+ dns[:port],
17
+ dns[:txt])
18
+ end
19
+ end
20
+
21
+ # @!visibility private
22
+ attr_reader :service
23
+
24
+ # @!visibility private
25
+ attr_reader :ip
26
+
27
+ # @!visibility private
28
+ attr_reader :port
29
+
30
+ # @!visibility private
31
+ attr_reader :txt
32
+
33
+ # @!visibility private
34
+ def initialize(service, ip, port, txt)
35
+ @service = service
36
+ @ip = ip
37
+ @port = port
38
+ @txt = txt
39
+ end
40
+
41
+ # @!visibility private
42
+ def url
43
+ @url ||= "http://#{ip}:#{port}"
44
+ end
45
+
46
+ # @!visibility private
47
+ def to_s
48
+ "#<#{service}: #{url} TXT: #{txt}"
49
+ end
50
+
51
+ # @!visibility private
52
+ def inspect
53
+ to_s
54
+ end
55
+
56
+ # @!visibility private
57
+ def ==(other)
58
+ service == other.service
59
+ end
60
+
61
+ DEVICE_AGENT = "_calabus._tcp"
62
+
63
+ def self.wait_for_new_device_agent(old, options={})
64
+ new = self.wait_for_device_agents(options)
65
+ new.find do |new_dns|
66
+ !old.include?(new_dns)
67
+ end
68
+ end
69
+
70
+ def self.wait_for_device_agents(options={})
71
+ default_opts = {
72
+ :timeout => 0.1,
73
+ :retries => 150,
74
+ :interval => 0.1
75
+ }
76
+
77
+ merged_opts = default_opts.merge(options)
78
+ timeout = merged_opts[:timeout]
79
+ retries = merged_opts[:retries]
80
+ interval = merged_opts[:interval]
81
+
82
+ start_time = Time.now
83
+
84
+ retries.times do |try|
85
+ time_diff = start_time + timeout - Time.now
86
+
87
+ if time_diff <= 0
88
+ elapsed = Time.now - start_time
89
+ RunLoop.log_debug("Timed out waiting after #{elapsed} seconds for DeviceAgents")
90
+ return []
91
+ end
92
+
93
+ agents = self.device_agents(timeout)
94
+
95
+ if !agents.empty?
96
+ elapsed = Time.now - start_time
97
+ RunLoop.log_debug("Found #{agents.count} DeviceAgents after #{elapsed} seconds")
98
+ return agents
99
+ end
100
+
101
+ sleep(interval)
102
+ end
103
+ []
104
+ end
105
+
106
+ def self.device_agents(timeout)
107
+ services = []
108
+ addresses = []
109
+ self.browse(DEVICE_AGENT, timeout) do |reply|
110
+ if reply.flags.add?
111
+ services << reply
112
+ end
113
+ next if reply.flags.more_coming?
114
+
115
+ services.each do |service|
116
+ resolved = service.resolve
117
+ addr = Socket.getaddrinfo(resolved.target, nil, Socket::AF_INET)
118
+ addr.each do |address|
119
+ match = addresses.find do |dns|
120
+ dns.service == service.name
121
+ end
122
+
123
+ if !match
124
+ dns = RunLoop::DNSSD.new(service.name,
125
+ addr[0][2],
126
+ resolved.port,
127
+ resolved.text_record)
128
+ addresses << dns
129
+ end
130
+ end
131
+ end
132
+ end
133
+ addresses
134
+ end
135
+
136
+ def self.browse(type, timeout)
137
+ domain = nil
138
+ flags = 0
139
+ interface = ::DNSSD::InterfaceAny
140
+ service = ::DNSSD::Service.browse(type, domain, flags, interface)
141
+ service.each(timeout) { |r| yield r }
142
+ ensure
143
+ service.stop if service
144
+ end
145
+
146
+ end
147
+ end
148
+
@@ -0,0 +1,87 @@
1
+ # A module for managing the ~/.run-loop directory.
2
+ module RunLoop::DotDir
3
+
4
+ def self.directory
5
+ home = RunLoop::Environment.user_home_directory
6
+ dir = File.join(home, ".run-loop")
7
+ if !File.exist?(dir)
8
+ FileUtils.mkdir_p(dir)
9
+ end
10
+ dir
11
+ end
12
+
13
+ def self.make_results_dir
14
+ if RunLoop::Environment.xtc?
15
+ next_results_dir = Dir.mktmpdir("run_loop")
16
+ else
17
+ results_dir = File.join(self.directory, 'results')
18
+ next_results_dir = self.next_timestamped_dirname(results_dir)
19
+ FileUtils.mkdir_p(next_results_dir)
20
+
21
+ current = File.join(self.directory, "results", "current")
22
+ FileUtils.rm_rf(current)
23
+ FileUtils.ln_s(next_results_dir, current)
24
+ end
25
+
26
+ next_results_dir
27
+ end
28
+
29
+ def self.rotate_result_directories
30
+ return :xtc if RunLoop::Environment.xtc?
31
+
32
+ start = Time.now
33
+
34
+ glob = "#{self.directory}/results/*"
35
+
36
+ RunLoop.log_debug("Searching for run-loop results with glob: #{glob}")
37
+
38
+ directories = Dir.glob(glob).select do |path|
39
+ File.directory?(path) && !File.symlink?(path)
40
+ end
41
+
42
+ oldest_first = directories.sort_by { |f| File.mtime(f) }
43
+
44
+ RunLoop.log_debug("Found #{oldest_first.count} previous run-loop results")
45
+ oldest_first.pop(5)
46
+
47
+ RunLoop.log_debug("Will delete #{oldest_first.count} previous run-loop results")
48
+
49
+ oldest_first.each do |path|
50
+ FileUtils.rm_rf(path)
51
+ end
52
+
53
+ elapsed = Time.now - start
54
+
55
+ RunLoop.log_debug("Deleted #{oldest_first.count} previous results in #{elapsed} seconds")
56
+ rescue StandardError => e
57
+ RunLoop.log_error("While rotating previous results, encounterd: #{e}")
58
+ end
59
+
60
+ private
61
+
62
+ def self.timestamped_dirname(plus_seconds = 0)
63
+ (Time.now + plus_seconds).strftime("%Y-%m-%d_%H-%M-%S")
64
+ end
65
+
66
+ def self.next_timestamped_dirname(base_dir)
67
+ dir = File.join(base_dir, self.timestamped_dirname)
68
+ return dir if !File.exist?(dir)
69
+
70
+ # Rather than wait, just increment the second. Per-second accuracy
71
+ # is not important; uniqueness is.
72
+ counter = 0
73
+ loop do
74
+ break if !File.exist?(dir)
75
+ break if counter == 4
76
+ counter = counter + 1
77
+ dir = File.join(base_dir, self.timestamped_dirname(counter))
78
+ end
79
+
80
+ # If all else fails, just return a unique UUID
81
+ if File.exist?(dir)
82
+ dir = File.join(base_dir, SecureRandom.uuid)
83
+ end
84
+ dir
85
+ end
86
+ end
87
+
@@ -0,0 +1,145 @@
1
+ module RunLoop
2
+
3
+ # @!visibility private
4
+ #
5
+ # This is experimental.
6
+ #
7
+ # Injects dylibs into running executables using lldb.
8
+ class DylibInjector
9
+
10
+ # Options for controlling how often to retry dylib injection.
11
+ #
12
+ # Try 3 times for 10 seconds each try with a sleep of 2 seconds
13
+ # between tries.
14
+ #
15
+ # You can override these values if they do not work in your environment.
16
+ #
17
+ # For cucumber users, the best place to override would be in your
18
+ # features/support/env.rb.
19
+ #
20
+ # For example:
21
+ #
22
+ # RunLoop::DylibInjector::RETRY_OPTIONS[:timeout] = 60
23
+ RETRY_OPTIONS = {
24
+ :tries => 3,
25
+ :interval => 2,
26
+ :timeout => RunLoop::Environment.ci? ? 40 : 20
27
+ }
28
+
29
+ # @!attribute [r] process_name
30
+ # The name of the process to inject the dylib into. This should be obtained
31
+ # by inspecting the Info.plist in the app bundle.
32
+ # @return [String] The process_name
33
+ attr_reader :process_name
34
+
35
+ # @!attribute [r] dylib_path
36
+ # The path to the dylib that is to be injected.
37
+ # @return [String] The dylib_path
38
+ attr_reader :dylib_path
39
+
40
+ # @!visibility private
41
+ attr_reader :xcrun
42
+
43
+ # Create a new dylib injector.
44
+ # @param [String] process_name The name of the process to inject the dylib
45
+ # into. This should be obtained by inspecting the Info.plist in the app
46
+ # bundle.
47
+ # @param [String] dylib_path The path the dylib to inject.
48
+ def initialize(process_name, dylib_path)
49
+ @process_name = process_name
50
+ @dylib_path = Shellwords.shellescape(dylib_path)
51
+ end
52
+
53
+ def xcrun
54
+ @xcrun ||= RunLoop::Xcrun.new
55
+ end
56
+
57
+ # Injects a dylib into a a currently running process.
58
+ def inject_dylib(timeout)
59
+ RunLoop.log_debug("Starting lldb injection with a timeout of #{timeout} seconds")
60
+
61
+ script_path = write_script
62
+
63
+ start = Time.now
64
+
65
+ options = {
66
+ :timeout => timeout,
67
+ :log_cmd => true
68
+ }
69
+
70
+ hash = nil
71
+ success = false
72
+ begin
73
+ hash = xcrun.run_command_in_context(["lldb", "--no-lldbinit", "--source", script_path], options)
74
+ pid = hash[:pid]
75
+ exit_status = hash[:exit_status]
76
+ success = exit_status == 0
77
+
78
+ RunLoop.log_debug("lldb '#{pid}' exited with value '#{exit_status}'.")
79
+
80
+ success = exit_status == 0
81
+ elapsed = Time.now - start
82
+
83
+ if success
84
+ RunLoop.log_debug("Took #{elapsed} seconds for lldb to inject calabash dylib.")
85
+ else
86
+ RunLoop.log_debug("Could not inject dylib after #{elapsed} seconds.")
87
+ if hash[:out]
88
+ hash[:out].split("\n").each do |line|
89
+ RunLoop.log_debug(line)
90
+ end
91
+ else
92
+ RunLoop.log_debug("lldb returned no output to stdout or stderr")
93
+ end
94
+ end
95
+ rescue RunLoop::Xcrun::TimeoutError
96
+ elapsed = Time.now - start
97
+ RunLoop.log_debug("lldb tried for #{elapsed} seconds to inject calabash dylib before giving up.")
98
+ end
99
+
100
+ success
101
+ end
102
+
103
+ def retriable_inject_dylib(options={})
104
+ merged_options = RETRY_OPTIONS.merge(options)
105
+
106
+ tries = merged_options[:tries]
107
+ timeout = merged_options[:timeout]
108
+ interval = merged_options[:interval]
109
+
110
+ success = false
111
+
112
+ tries.times do
113
+
114
+ success = inject_dylib(timeout)
115
+ break if success
116
+
117
+ sleep(interval)
118
+ end
119
+
120
+ if !success
121
+ raise RuntimeError, "Could not inject dylib"
122
+ end
123
+ success
124
+ end
125
+
126
+ private
127
+
128
+ def write_script
129
+ script = File.join(DotDir.directory, "inject-dylib.lldb")
130
+
131
+ if File.exist?(script)
132
+ FileUtils.rm_rf(script)
133
+ end
134
+
135
+ File.open(script, "w") do |file|
136
+ file.write("process attach -n \"#{process_name}\"\n")
137
+ file.write("expr (void*)dlopen(\"#{dylib_path}\", 0x2)\n")
138
+ file.write("detach\n")
139
+ file.write("exit\n")
140
+ end
141
+
142
+ script
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,56 @@
1
+
2
+ module RunLoop
3
+ module Encoding
4
+
5
+ # Removes diacritic markers from string.
6
+ #
7
+ # The ruby Encoding tools cannot perform this action, they can only change
8
+ # convert one encodign to another by substituting characters.
9
+ #
10
+ # In ruby 1.9.3 we would have used Iconv, but that does not exist in 2.0.
11
+ #
12
+ # The Encoding::Convert in 2.0 does not work on string with UTF-16 characters.
13
+ def transliterate(string)
14
+ require "i18n"
15
+ locales = I18n.available_locales
16
+ if !locales.include?(:en)
17
+ I18n.available_locales = locales + [:en]
18
+ end
19
+ I18n.transliterate(string)
20
+ end
21
+
22
+ # Raised when a string cannot be coerced to UTF8
23
+ class UTF8Error < RuntimeError; end
24
+
25
+ # @!visibility private
26
+ def ensure_command_output_utf8(string, command)
27
+ return '' if !string
28
+
29
+ utf8 = string.force_encoding("UTF-8").chomp
30
+
31
+ return utf8 if utf8.valid_encoding?
32
+
33
+ encoded = utf8.encode("UTF-8", "UTF-8",
34
+ invalid: :replace,
35
+ undef: :replace,
36
+ replace: "")
37
+
38
+ return encoded if encoded.valid_encoding?
39
+
40
+ raise UTF8Error, %Q{
41
+ Could not force UTF-8 encoding on this string:
42
+
43
+ #{string}
44
+
45
+ which is the output of this command:
46
+
47
+ #{command}
48
+
49
+ Please file an issue with a stacktrace and the text of this error.
50
+
51
+ https://github.com/calabash/run_loop/issues
52
+ }
53
+ end
54
+ end
55
+ end
56
+