Class: UIAutoMonkey::MonkeyRunner
- Inherits:
-
Object
- Object
- UIAutoMonkey::MonkeyRunner
show all
- Includes:
- CommandHelper
- Defined in:
- lib/crash_monkey/monkey_runner.rb
Constant Summary
collapse
- TRACE_TEMPLATE =
'/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate'
- RESULT_BASE_PATH =
File.expand_path('crash_monkey_result')
- RESULT_DETAIL_EVENT_NUM =
20
- TIME_LIMIT_SEC =
100
Instance Method Summary
collapse
#kill_all, #run_process, #shell, #xcode_path
Instance Method Details
#all_tests_ok?(result_list) ⇒ Boolean
116
117
118
|
# File 'lib/crash_monkey/monkey_runner.rb', line 116
def all_tests_ok?(result_list)
result_list.select {|r| !r[:ok]}.empty?
end
|
#app_name ⇒ Object
152
153
154
|
# File 'lib/crash_monkey/monkey_runner.rb', line 152
def app_name
File.basename(app_path).gsub(/\.app$/, '')
end
|
#app_path ⇒ Object
148
149
150
|
# File 'lib/crash_monkey/monkey_runner.rb', line 148
def app_path
@app_path ||= find_app_path(@options)
end
|
#config_json_path ⇒ Object
235
236
237
|
# File 'lib/crash_monkey/monkey_runner.rb', line 235
def config_json_path
@options[:config_path] || template_path('config.json')
end
|
#console_log_path ⇒ Object
215
216
217
|
# File 'lib/crash_monkey/monkey_runner.rb', line 215
def console_log_path
"#{result_dir}/console.log"
end
|
#copy_html_resources ⇒ Object
110
111
112
113
114
|
# File 'lib/crash_monkey/monkey_runner.rb', line 110
def copy_html_resources
bootstrap_dir = File.expand_path('../../bootstrap', __FILE__)
FileUtils.copy("#{bootstrap_dir}/css/bootstrap.css", result_base_dir)
FileUtils.copy("#{bootstrap_dir}/js/bootstrap.js", result_base_dir)
end
|
#crash_report_dir ⇒ Object
203
204
205
|
# File 'lib/crash_monkey/monkey_runner.rb', line 203
def crash_report_dir
"#{ENV['HOME']}/Library/Logs/DiagnosticReports"
end
|
#crash_report_list ⇒ Object
207
208
209
|
# File 'lib/crash_monkey/monkey_runner.rb', line 207
def crash_report_list
`ls -t #{crash_report_dir}/#{app_name}_*.crash`.strip.split(/\n/)
end
|
#create_index_html(result_hash) ⇒ Object
101
102
103
104
105
106
107
108
|
# File 'lib/crash_monkey/monkey_runner.rb', line 101
def create_index_html(result_hash)
er = Erubis::Eruby.new(File.read(template_path('index.html.erb')))
result_hash[:test_count] = result_hash[:result_list].size
result_hash[:ok_count] = result_hash[:result_list].select {|r| r[:ok]}.size
result_hash[:ng_count] = result_hash[:test_count] - result_hash[:ok_count]
open("#{result_base_dir}/index.html", 'w') {|f| f.write er.result(result_hash)}
copy_html_resources
end
|
#create_result_html(log_list) ⇒ Object
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
|
# File 'lib/crash_monkey/monkey_runner.rb', line 269
def create_result_html(log_list)
latest_list = LogDecoder.new(log_list).decode_latest(RESULT_DETAIL_EVENT_NUM)
hash = {}
hash[:log_list] = latest_list.reverse
hash[:log_list_json] = JSON.dump(hash[:log_list])
crash_report = Dir.glob("#{result_dir}/*.crash")[0]
hash[:crash_report] = crash_report ? File.basename(crash_report) : nil
hash[:crashed] = @crashed
er = Erubis::Eruby.new(File.read(template_path('result.html.erb')))
open("#{result_dir}/result.html", 'w') do |f|
f.write(er.result(hash))
end
FileUtils.copy(template_path('result_view.js'), "#{result_dir}/result_view.js")
end
|
#find_app_path(opts) ⇒ Object
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
# File 'lib/crash_monkey/monkey_runner.rb', line 160
def find_app_path(opts)
app_path = nil
if opts[:app_path].include?('/')
app_path = File.expand_path(opts[:app_path])
elsif opts[:app_path] =~ /\.app$/
apps = find_apps(opts[:app_path])
app_path = apps[0]
log "#{apps.size} apps are found, USE NEWEST APP: #{app_path}" if apps.size > 1
end
unless app_path
raise 'Invalid AppName'
end
app_path
end
|
#find_apps(app) ⇒ Object
156
157
158
|
# File 'lib/crash_monkey/monkey_runner.rb', line 156
def find_apps(app)
`"ls" -dt #{ENV['HOME']}/Library/Developer/Xcode/DerivedData/*/Build/Products/*/#{app}`.strip.split(/\n/)
end
|
#finish_running(result) ⇒ Object
95
96
97
98
99
|
# File 'lib/crash_monkey/monkey_runner.rb', line 95
def finish_running(result)
FileUtils.remove_dir(result_history_dir(@times), true)
FileUtils.move(result_dir, result_history_dir(@times))
kill_all('iPhone Simulator')
end
|
#generate_ui_auto_monkey ⇒ Object
223
224
225
226
227
228
229
230
231
232
233
|
# File 'lib/crash_monkey/monkey_runner.rb', line 223
def generate_ui_auto_monkey
extend_javascript_flag, extend_javascript_path = show_extend_javascript
orig = File.read(ui_auto_monkey_original_path)
config = JSON.parse(File.read(config_json_path))
replace_str = " this.config = #{JSON.pretty_generate(config, :indent => ' '*6)}; \n"
js = replace_text(orig, replace_str, '__UIAutoMonkey Configuration Begin__', '__UIAutoMonkey Configuration End__')
if extend_javascript_flag
js = File.read(extend_javascript_path) + "\n" + js
end
File.open(ui_auto_monkey_path, 'w') {|f| f.write(js)}
end
|
#grep_syslog ⇒ Object
211
212
213
|
# File 'lib/crash_monkey/monkey_runner.rb', line 211
def grep_syslog
'tail -n 0 -f /var/log/system.log'
end
|
#list_app ⇒ Object
131
132
133
|
# File 'lib/crash_monkey/monkey_runner.rb', line 131
def list_app
puts find_apps('*.app').map{|n| File.basename n}.uniq.sort.join("\n")
end
|
#log(msg) ⇒ Object
135
136
137
|
# File 'lib/crash_monkey/monkey_runner.rb', line 135
def log(msg)
puts msg
end
|
#parse_results ⇒ Object
255
256
257
258
259
260
261
262
263
264
265
266
267
|
# File 'lib/crash_monkey/monkey_runner.rb', line 255
def parse_results
filename = "#{result_dir}/Automation Results.plist"
log_list = []
if File.exists?(filename)
doc = REXML::Document.new(open(filename))
doc.elements.each('plist/dict/array/dict') do |record|
ary = record.elements.to_a.map{|a| a.text}
log_list << Hash[*ary]
end
@crashed = true if log_list[-1][LOG_TYPE] == 'Fail'
end
log_list
end
|
#replace_text(orig, replace_str, marker_begin_line, marker_end_line) ⇒ Object
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
# File 'lib/crash_monkey/monkey_runner.rb', line 239
def replace_text(orig, replace_str, marker_begin_line, marker_end_line)
results = []
status = 1
orig.each_line do |line|
if status == 1 && line =~ /#{marker_begin_line}/
status = 2
results << line
results << replace_str
elsif status == 2 && line =~/#{marker_end_line}/
status = 3
end
results << line unless status == 2
end
results.join('')
end
|
#reset_iphone_simulator ⇒ Object
139
140
141
142
|
# File 'lib/crash_monkey/monkey_runner.rb', line 139
def reset_iphone_simulator
FileUtils.rm_rf("#{Dir.home}/Library/Application\ Support/iPhone\ Simulator/")
puts 'reset iPhone Simulator successful'
end
|
#result_base_dir ⇒ Object
191
192
193
|
# File 'lib/crash_monkey/monkey_runner.rb', line 191
def result_base_dir
@options[:result_base_dir] || RESULT_BASE_PATH
end
|
#result_dir ⇒ Object
195
196
197
|
# File 'lib/crash_monkey/monkey_runner.rb', line 195
def result_dir
"#{result_base_dir}/Run 1"
end
|
#result_history_dir(times) ⇒ Object
199
200
201
|
# File 'lib/crash_monkey/monkey_runner.rb', line 199
def result_history_dir(times)
"#{result_base_dir}/result_#{sprintf('%03d', times)}"
end
|
#run(opts) ⇒ Object
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
# File 'lib/crash_monkey/monkey_runner.rb', line 18
def run(opts)
@options = opts
if @options[:show_config]
show_config
return true
elsif @options[:list_app]
list_app
return true
elsif @options[:reset_iphone_simulator]
reset_iphone_simulator
return true
end
log @options.inspect
FileUtils.remove_dir(result_base_dir, true)
FileUtils.makedirs(result_base_dir)
generate_ui_auto_monkey
start_time = Time.now
result_list = []
total_test_count.times do |times|
@times = times
setup_running
result = run_a_case
finish_running(result)
result_list << result
end
create_index_html({
:start_time => start_time,
:end_time => Time.now,
:result_list => result_list,
})
all_tests_ok?(result_list)
end
|
#run_a_case ⇒ Object
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
# File 'lib/crash_monkey/monkey_runner.rb', line 61
def run_a_case
log "=================================== Start Test (#{@times+1}/#{total_test_count}) ======================================="
cr_list = crash_report_list
start_time = Time.now
watch_syslog do
begin
Timeout.timeout(time_limit_sec + 5) do
run_process(%W(instruments -l #{time_limit} -t #{TRACE_TEMPLATE} #{app_path} -e UIASCRIPT #{ui_auto_monkey_path} -e UIARESULTSPATH #{result_base_dir}))
end
rescue Timeout::Error
log 'killall -9 instruments'
kill_all('instruments', '9')
end
end
new_cr_list = crash_report_list
unless cr_list[0] == new_cr_list[0]
@crashed = true
log "Find new crash report: #{new_cr_list[0]}"
FileUtils.copy(new_cr_list[0], result_dir)
end
create_result_html(parse_results)
{
:start_time => start_time,
:end_time => Time.now,
:times => @times,
:ok => !@crashed,
:result_dir => File.basename(result_history_dir(@times)),
:message => nil
}
end
|
#setup_running ⇒ Object
54
55
56
57
58
59
|
# File 'lib/crash_monkey/monkey_runner.rb', line 54
def setup_running
FileUtils.remove_dir(result_dir, true)
ENV['UIARESULTSPATH'] = result_dir
@crashed = false
end
|
#show_config ⇒ Object
120
121
122
|
# File 'lib/crash_monkey/monkey_runner.rb', line 120
def show_config
puts File.read(config_json_path)
end
|
#show_extend_javascript ⇒ Object
124
125
126
127
128
129
|
# File 'lib/crash_monkey/monkey_runner.rb', line 124
def show_extend_javascript
if @options[:extend_javascript_path]
filename = @options[:extend_javascript_path]
return File.exist?(filename), filename
end
end
|
#template_path(name) ⇒ Object
219
220
221
|
# File 'lib/crash_monkey/monkey_runner.rb', line 219
def template_path(name)
File.expand_path("../templates/#{name}", __FILE__)
end
|
#time_limit ⇒ Object
175
176
177
|
# File 'lib/crash_monkey/monkey_runner.rb', line 175
def time_limit
time_limit_sec * 1000
end
|
#time_limit_sec ⇒ Object
179
180
181
|
# File 'lib/crash_monkey/monkey_runner.rb', line 179
def time_limit_sec
(@options[:time_limit_sec] || TIME_LIMIT_SEC).to_i
end
|
#total_test_count ⇒ Object
144
145
146
|
# File 'lib/crash_monkey/monkey_runner.rb', line 144
def total_test_count
(@options[:run_count] || 2)
end
|
#ui_auto_monkey_original_path ⇒ Object
183
184
185
|
# File 'lib/crash_monkey/monkey_runner.rb', line 183
def ui_auto_monkey_original_path
File.expand_path('../../ui-auto-monkey/UIAutoMonkey.js', __FILE__)
end
|
#ui_auto_monkey_path ⇒ Object
187
188
189
|
# File 'lib/crash_monkey/monkey_runner.rb', line 187
def ui_auto_monkey_path
"#{result_base_dir}/UIAutoMonkey.js"
end
|
#watch_syslog ⇒ Object
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
# File 'lib/crash_monkey/monkey_runner.rb', line 285
def watch_syslog
STDOUT.sync = true
stdin, stdout, stderr = Open3.popen3(grep_syslog)
log_filename = "#{result_base_dir}/console.log"
thread = Thread.new do
File.open(log_filename, 'a') do |output|
begin
while true
line = stdout.readline
output.write(line) if line.include?(app_name)
end
rescue IOError
log 'tail finished: system.log'
end
end
end
yield
sleep 3
stdout.close; stderr.close; stdin.close
thread.join
FileUtils.makedirs(result_dir) unless File.exists?(result_dir)
if File.exists?(log_filename)
FileUtils.move(log_filename, console_log_path)
end
end
|