Class: TestCenter::Helper::MultiScanManager::RetryingScanHelper

Inherits:
Object
  • Object
show all
Defined in:
lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ RetryingScanHelper

Returns a new instance of RetryingScanHelper.

Raises:

  • (ArgumentError)


8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 8

def initialize(options)
  raise ArgumentError, 'Do not use the :device or :devices option. Instead use the :destination option.' if (options.key?(:device) or options.key?(:devices))

  @options = options
  @testrun_count = 0
  @xcpretty_json_file_output = ENV['XCPRETTY_JSON_FILE_OUTPUT']
  @reportnamer = ReportNameHelper.new(
    @options[:output_types],
    @options[:output_files],
    @options[:custom_report_file_name]
  )
  @callback_overrides_only_testing = false
end

Instance Attribute Details

#testrun_countObject (readonly)

Returns the value of attribute testrun_count.



6
7
8
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 6

def testrun_count
  @testrun_count
end

Instance Method Details

#after_testrun(exception = nil) ⇒ Object

after_testrun methods



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 190

def after_testrun(exception = nil)
  move_simulator_logs_for_next_run

  @testrun_count = @testrun_count + 1
  FastlaneCore::UI.verbose("Batch ##{@options[:batch]} incrementing retry count to #{@testrun_count}")
  if exception.kind_of?(FastlaneCore::Interface::FastlaneTestFailure)
    after_testrun_message = "Scan found failing tests"
    after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
    FastlaneCore::UI.verbose(after_testrun_message)

    handle_test_failure
  elsif exception.kind_of?(FastlaneCore::Interface::FastlaneBuildFailure)
    after_testrun_message = "Scan unable to test"
    after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
    FastlaneCore::UI.verbose(after_testrun_message)

    if @options[:retry_test_runner_failures]
      continue_with_build_failure(exception)
    else
      handle_build_failure(exception)
    end
  else
    after_testrun_message = "Scan passed the tests"
    after_testrun_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
    FastlaneCore::UI.verbose(after_testrun_message)

    handle_success
  end
  collate_reports
end

#before_testrunObject



22
23
24
25
26
27
28
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 22

def before_testrun
  delete_xcresults # has to be performed _after_ moving a *.test_result
  quit_simulator
  set_json_env
  set_scan_config
  print_starting_scan_message
end

#collate_reportsObject



227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 227

def collate_reports
  return unless @options[:collate_reports]

  report_collator_options = {
    source_reports_directory_glob: output_directory,
    output_directory: output_directory,
    reportnamer: @reportnamer,
    scheme: @options[:scheme],
    result_bundle: @options[:result_bundle]
  }
  TestCenter::Helper::MultiScanManager::ReportCollator.new(report_collator_options).collate
end

#continue_with_build_failure(exception) ⇒ Object



352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 352

def continue_with_build_failure(exception)
  test_session_last_messages = last_lines_of_test_session_log
  failure = retrieve_test_operation_failure(test_session_last_messages)
  case failure
  when /Lost connection to testmanagerd/
    FastlaneCore::UI.important("com.apple.CoreSimulator.CoreSimulatorService may have become corrupt, consider quitting it")
    if @options[:quit_core_simulator_service]
      Fastlane::Actions::RestartCoreSimulatorServiceAction.run
    end
  else
    FastlaneCore::UI.important(test_session_last_messages)
  end
  send_callback_testrun_info(test_operation_failure: failure)
end

#delete_xcresultsObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 110

def delete_xcresults
  if @reportnamer.includes_xcresult?
    FileUtils.rm_rf(File.join(output_directory, @reportnamer.xcresult_last_bundlename))
    return
  end

  derived_data_path = File.expand_path(@options[:derived_data_path] || Scan.config[:derived_data_path])
  xcresults = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult")
  if FastlaneCore::Helper.xcode_at_least?('11')
    xcresults += Dir.glob("#{output_directory}/*.xcresult")
  end
  FastlaneCore::UI.verbose("Deleting xcresults:")
  xcresults.each do |xcresult|
    FastlaneCore::UI.verbose("  #{xcresult}")
  end
  FileUtils.rm_rf(xcresults)
end

#failure_details(additional_info) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 287

def failure_details(additional_info)
  return [{}, nil] if additional_info.key?(:test_operation_failure)

  report_filepath = File.join(output_directory, @reportnamer.junit_last_reportname)
  config = FastlaneCore::Configuration.create(
    Fastlane::Actions::TestsFromJunitAction.available_options,
    {
      junit: File.absolute_path(report_filepath)
    }
  )
  junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)

  [junit_results, report_filepath]
end

#handle_build_failure(exception) ⇒ Object



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 367

def handle_build_failure(exception)
  test_session_last_messages = last_lines_of_test_session_log
  failure = retrieve_test_operation_failure(test_session_last_messages)
  case failure
  when /Test runner exited before starting test execution/
    FastlaneCore::UI.error(failure)
  when /Lost connection to testmanagerd/
    FastlaneCore::UI.error(failure)
    FastlaneCore::UI.important("com.apple.CoreSimulator.CoreSimulatorService may have become corrupt, consider quitting it")
    if @options[:quit_core_simulator_service]
      Fastlane::Actions::RestartCoreSimulatorServiceAction.run
    end
  else
    FastlaneCore::UI.error(test_session_last_messages)
    send_callback_testrun_info(test_operation_failure: failure)
    raise exception
    FastlaneCore::UI.important(test_session_last_messages)
  end
  send_callback_testrun_info(test_operation_failure: failure)
end

#handle_successObject



221
222
223
224
225
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 221

def handle_success
  send_callback_testrun_info
  move_test_result_bundle_for_next_run
  reset_json_env
end

#handle_test_failureObject



240
241
242
243
244
245
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 240

def handle_test_failure
  send_callback_testrun_info
  move_test_result_bundle_for_next_run
  update_scan_options
  @reportnamer.increment
end

#last_lines_of_test_session_logObject



417
418
419
420
421
422
423
424
425
426
427
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 417

def last_lines_of_test_session_log
  derived_data_path = File.expand_path(@options[:derived_data_path])
  test_session_logs = Dir.glob("#{derived_data_path}/Logs/Test/*.xcresult/*_Test/Diagnostics/**/Session-*.log")
  return '' if test_session_logs.empty?

  test_session_logs.sort! { |logfile1, logfile2| File.mtime(logfile1) <=> File.mtime(logfile2) }
  test_session = File.open(test_session_logs.last)
  backwards_seek_offset = -1 * [1000, test_session.stat.size].min
  test_session.seek(backwards_seek_offset, IO::SEEK_END)
  test_session_last_messages = test_session.read
end

#move_simulator_logs_for_next_runObject



429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 429

def move_simulator_logs_for_next_run
  return unless @options[:include_simulator_logs]

  glob_pattern = "#{output_directory}/system_logs-*.{log,logarchive}"
  logs = Dir.glob(glob_pattern)
  batch_prefix = ''
  if @options[:batch]
    batch_prefix = "batch-#{@options[:batch]}-"
  end
  logs.each do |log_filepath|
    new_logname = "#{batch_prefix}try-#{testrun_count}-#{File.basename(log_filepath)}"
    new_log_filepath = "#{File.dirname(log_filepath)}/#{new_logname}"
    FastlaneCore::UI.verbose("Moving simulator log '#{log_filepath}' to '#{new_log_filepath}'")
    FileUtils.mv(log_filepath, new_log_filepath, force: true)
  end
end

#move_test_result_bundle_for_next_runObject



446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 446

def move_test_result_bundle_for_next_run
  return unless @options[:result_bundle]

  result_extension = FastlaneCore::Helper.xcode_at_least?('11') ? '.xcresult' : '.test_result'
  
  glob_pattern = "#{output_directory}/*#{result_extension}"
  preexisting_test_result_bundles = Dir.glob(glob_pattern)
  unnumbered_test_result_bundles = preexisting_test_result_bundles.reject do |test_result|
    test_result =~ /.*-\d+\#{result_extension}/
  end
  src_test_bundle = unnumbered_test_result_bundles.first
  dst_test_bundle_parent_dir = File.dirname(src_test_bundle)
  dst_test_bundle_basename = File.basename(src_test_bundle, result_extension)
  dst_test_bundle = "#{dst_test_bundle_parent_dir}/#{dst_test_bundle_basename}-#{@testrun_count}#{result_extension}"
  FastlaneCore::UI.verbose("Moving test_result '#{src_test_bundle}' to '#{dst_test_bundle}'")
  File.rename(src_test_bundle, dst_test_bundle)
end

#output_directoryObject



128
129
130
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 128

def output_directory
  @options.fetch(:output_directory, 'test_results')
end

#prepare_scan_configObject

:nocov:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 73

def prepare_scan_config
  # this allows multi_scan's `destination` option to be picked up by `scan`
  scan_config._values.delete(:device)
  ENV.delete('SCAN_DEVICE')
  scan_config._values.delete(:devices)
  ENV.delete('SCAN_DEVICES')
  # this prevents double -resultBundlePath args to xcodebuild
  if ReportNameHelper.includes_xcresult?(@options[:output_types])
    scan_config._values.delete(:result_bundle)
    ENV.delete('SCAN_RESULT_BUNDLE')
  end
  scan_config._values.delete(:skip_testing)
  scan_cache.clear
end


132
133
134
135
136
137
138
139
140
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 132

def print_starting_scan_message
  if @options[:only_testing]
    scan_message = "Starting scan ##{@testrun_count + 1} with #{@options.fetch(:only_testing, []).size} tests"
  else
    scan_message = "Starting scan ##{@testrun_count + 1}"
  end
  scan_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
  FastlaneCore::UI.message("#{scan_message}.")
end

#quit_simulatorObject



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 98

def quit_simulator
  return unless @options[:quit_simulators]

  @options.fetch(:destination).each do |destination|
    if /id=(?<udid>[^,$]+)/ =~ destination
      FastlaneCore::UI.verbose("Restarting Simulator #{udid}")
      `xcrun simctl shutdown #{udid} 2>/dev/null`
      `xcrun simctl boot #{udid} 2>/dev/null`
    end
  end
end

#reset_json_envObject



153
154
155
156
157
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 153

def reset_json_env
  return unless @reportnamer.includes_json?

  ENV['XCPRETTY_JSON_FILE_OUTPUT'] = @xcpretty_json_file_output
end

#retrieve_test_operation_failure(test_session_last_messages) ⇒ Object



388
389
390
391
392
393
394
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 388

def retrieve_test_operation_failure(test_session_last_messages)
  if FastlaneCore::Helper.xcode_at_least?('11')
    retrieve_test_operation_failure_post_xcode11(test_session_last_messages)
  else
    retrieve_test_operation_failure_pre_xcode11(test_session_last_messages)
  end
end

#retrieve_test_operation_failure_post_xcode11(test_session_last_messages) ⇒ Object



396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 396

def retrieve_test_operation_failure_post_xcode11(test_session_last_messages)
  if /Connection peer refused channel request/ =~ test_session_last_messages
    test_operation_failure = 'Lost connection to testmanagerd'
  elsif /Please unlock your device and reattach/ =~ test_session_last_messages
    test_operation_failure = 'Test device locked'
  elsif /Test runner exited before starting test execution/ =~ test_session_last_messages
    test_operation_failure = 'Test runner exited before starting test execution'
  else
    test_operation_failure = 'Unknown test operation failure'
  end
  test_operation_failure
end

#retrieve_test_operation_failure_pre_xcode11(test_session_last_messages) ⇒ Object



409
410
411
412
413
414
415
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 409

def retrieve_test_operation_failure_pre_xcode11(test_session_last_messages)
  test_operation_failure_match = /Test operation failure: (?<test_operation_failure>.*)$/ =~ test_session_last_messages
  if test_operation_failure_match.nil?
    test_operation_failure = 'Unknown test operation failure'
  end
  test_operation_failure
end

#scan_cacheObject



68
69
70
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 68

def scan_cache
  Scan.cache
end

#scan_configObject

:nocov:



64
65
66
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 64

def scan_config
  Scan.config
end

#scan_optionsObject



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 159

def scan_options
  valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
  xcargs = @options[:xcargs] || ''
  if xcargs&.include?('build-for-testing')
    FastlaneCore::UI.important(":xcargs, #{xcargs}, contained 'build-for-testing', removing it")
    xcargs.slice!('build-for-testing')
  end
  if xcargs.include?('-quiet')
    FastlaneCore::UI.important('Disabling -quiet as failing tests cannot be found with it enabled.')
    xcargs.gsub!('-quiet', '')
  end
  if FastlaneCore::Helper.xcode_at_least?(10)
    xcargs.gsub!(/-parallel-testing-enabled(=|\s+)(YES|NO)/, '')
    xcargs << " -parallel-testing-enabled NO "
  end
  retrying_scan_options = @reportnamer.scan_options.merge(
    {
      output_directory: output_directory,
      xcargs: xcargs
    }
  )
  if @reportnamer.includes_xcresult?
    retrying_scan_options[:xcargs] += "-resultBundlePath '#{File.join(output_directory, @reportnamer.xcresult_last_bundlename)}' "
  end

  @options.select { |k,v| valid_scan_keys.include?(k) }
    .merge(retrying_scan_options)
end

#send_callback_override_scan_options_block(new_scan_options) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 88

def send_callback_override_scan_options_block(new_scan_options)
  return new_scan_options unless @options[:override_scan_options_block]

  callback_result = @options[:override_scan_options_block].call(new_scan_options)
  if callback_result.kind_of?(Hash)
    return callback_result
  end
  new_scan_options
end

#send_callback_testrun_info(additional_info = {}) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 247

def send_callback_testrun_info(additional_info = {})
  return unless @options[:testrun_completed_block]

  report_filepath = nil
  junit_results, report_filepath = failure_details(additional_info)

  info = {
    failed: junit_results.fetch(:failed, []),
    passing: junit_results.fetch(:passing, []),
    batch: @options[:batch] || 1,
    try_count: @testrun_count,
    report_filepath: report_filepath
  }.merge(additional_info)

  update_html_failure_details(info)
  update_json_failure_details(info)
  update_test_result_bundle_details(info)

  @callback_overrides_only_testing = false
  callback_result = @options[:testrun_completed_block].call(info)
  if callback_result.kind_of?(Hash)
    should_continue = callback_result.fetch(:continue, true)
    if !should_continue
      discontinue_message = 'Following testrun_completed_block\'s request to discontinue testing'
      discontinue_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
      FastlaneCore::UI.verbose(discontinue_message)
      @testrun_count = options[:try_count]
    end
    overridden_only_testing = callback_result.fetch(:only_testing, nil)
    if overridden_only_testing && should_continue
      override_only_testing_message = 'Following testrun_completed_block\'s request to change :only_testing to '
      override_only_testing_message << overridden_only_testing.to_s
      override_only_testing_message << " for batch ##{@options[:batch]}" unless @options[:batch].nil?
      FastlaneCore::UI.verbose(override_only_testing_message)
      @callback_overrides_only_testing = true
      @options[:only_testing] = overridden_only_testing
    end
  end
end

#set_json_envObject



142
143
144
145
146
147
148
149
150
151
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 142

def set_json_env
  return unless @reportnamer.includes_json?

  xcpretty_json_file_output = File.join(
    output_directory,
    @reportnamer.json_last_reportname
  )
  FastlaneCore::UI.verbose("Setting the XCPRETTY_JSON_FILE_OUTPUT to #{xcpretty_json_file_output}")
  ENV['XCPRETTY_JSON_FILE_OUTPUT'] = xcpretty_json_file_output
end

#set_scan_configObject



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 30

def set_scan_config
  valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
  new_scan_options = @options.select { |k,v| valid_scan_keys.include?(k) }
                         .merge(scan_options)

  prepare_scan_config
  new_scan_options[:build_for_testing] = false
  new_scan_options.delete(:skip_testing)

  new_scan_options = send_callback_override_scan_options_block(new_scan_options)

  FastlaneCore::UI.verbose("retrying_scan #update_scan_options")
  new_scan_options.each do |k,v|
    next if v.nil?

    scan_config.set(k,v) unless v.nil?
    FastlaneCore::UI.verbose("\tSetting #{k.to_s} to #{v}")
  end
  if @options[:scan_devices_override]
    scan_device_names = @options[:scan_devices_override].map { |device| device.name }
    FastlaneCore::UI.verbose("\tSetting Scan.devices to #{scan_device_names}")
    if Scan.devices
      Scan.devices.replace(@options[:scan_devices_override])
    else
      Scan.devices = @options[:scan_devices_override]
    end
  end
 
  values = scan_config.values(ask: false)
  values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
  ScanHelper.print_scan_parameters(values)
end

#turn_off_code_coverageObject



330
331
332
333
334
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 330

def turn_off_code_coverage
  # Turn off code coverage as code coverage reports are not merged and
  # the first, more valuable, report will be overwritten
  @options.delete(:code_coverage)
end

#update_html_failure_details(info) ⇒ Object



302
303
304
305
306
307
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 302

def update_html_failure_details(info)
  return unless @reportnamer.includes_html?

  html_report_filepath = File.join(output_directory, @reportnamer.html_last_reportname)
  info[:html_report_filepath] = html_report_filepath
end

#update_json_failure_details(info) ⇒ Object



309
310
311
312
313
314
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 309

def update_json_failure_details(info)
  return unless @reportnamer.includes_json?

  json_report_filepath = File.join(output_directory, @reportnamer.json_last_reportname)
  info[:json_report_filepath] = json_report_filepath
end

#update_only_testingObject



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 336

def update_only_testing
  return if @callback_overrides_only_testing

  report_filepath = File.join(output_directory, @reportnamer.junit_last_reportname)
  config = FastlaneCore::Configuration.create(
    Fastlane::Actions::TestsFromJunitAction.available_options,
    {
      junit: File.absolute_path(report_filepath)
    }
  )
  @options[:only_testing] = (@options[:only_testing] || []) - Fastlane::Actions::TestsFromJunitAction.run(config).fetch(:passing, Hash.new).map(&:shellsafe_testidentifier)
  if @options[:invocation_based_tests]
    @options[:only_testing] = @options[:only_testing].map(&:strip_testcase).uniq
  end
end

#update_scan_optionsObject



325
326
327
328
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 325

def update_scan_options
  update_only_testing
  turn_off_code_coverage
end

#update_test_result_bundle_details(info) ⇒ Object



316
317
318
319
320
321
322
323
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 316

def update_test_result_bundle_details(info)
  return unless @options[:result_bundle]

  test_result_suffix = '.test_result'
  test_result_suffix.prepend("-#{@reportnamer.report_count}") unless @reportnamer.report_count.zero?
  test_result_bundlepath = File.join(output_directory, @options[:scheme]) + test_result_suffix
  info[:test_result_bundlepath] = test_result_bundlepath
end