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
21
# 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
  FastlaneCore::UI.verbose("RetryingScanHelper.initialize with ':output' as \"#{@options[:output_directory]}\"")
  @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



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
220
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 191

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



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

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



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

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



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

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



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

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



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

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



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

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



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

def handle_success
  send_callback_testrun_info
  move_test_result_bundle_for_next_run
  reset_json_env
end

#handle_test_failureObject



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

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



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

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



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

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



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

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



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

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

#prepare_scan_configObject

:nocov:



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

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


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

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



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

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



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

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



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

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



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

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



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

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



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

def scan_cache
  Scan.cache
end

#scan_configObject

:nocov:



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

def scan_config
  Scan.config
end

#scan_optionsObject



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
187
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 160

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



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

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



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
286
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 248

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



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

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



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
62
# File 'lib/fastlane/plugin/test_center/helper/multi_scan_manager/retrying_scan_helper.rb', line 31

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



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

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



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

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



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

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



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

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



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

def update_scan_options
  update_only_testing
  turn_off_code_coverage
end

#update_test_result_bundle_details(info) ⇒ Object



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

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