class Cukerail::JsonSender

Attributes

results[R]
testrail_api_client[R]

Public Class Methods

new(json_file) click to toggle source
# File lib/json_sender.rb, line 9
def initialize(json_file)
  if %w(BASE_URL USER PASSWORD).map{|e| ENV["TESTRAIL_#{e}"]}.any?{|e| e=='' || !e}
    raise 'You need to setup Testrail environment parameters see https://bbcworldwide.atlassian.net/wiki/display/BAR/Installing+and+Running+Cukerail' 
  end
  @testrail_api_client = TestRail::APIClient.new(ENV['TESTRAIL_BASE_URL'],ENV['TESTRAIL_USER'],ENV['TESTRAIL_PASSWORD'])
  @results = JSON.parse(File.read(json_file)).select{|f| f['tags']}
end

Public Instance Methods

add_case_to_test_run(testcase_id,run_id) click to toggle source
# File lib/json_sender.rb, line 206
def add_case_to_test_run(testcase_id,run_id)
  run = get_run(run_id)
  unless run['include_all']
    puts "add testcase #{testcase_id} to run #{run_id}"
    case_ids = get_tests_in_a_run(run_id).map{|h| h['case_id']} + [testcase_id]
    update_run(run_id,{'case_ids'=>case_ids})
  end
end
create_new_case(scenario,background_steps,project_id,suite_id,sub_section_id) click to toggle source
# File lib/json_sender.rb, line 82
def create_new_case(scenario,background_steps,project_id,suite_id,sub_section_id)
  data = prepare_data(scenario,background_steps)
  testrail_api_client.send_post("add_case/#{sub_section_id || suite_id}", data)
rescue StandardError => e
  puts "#{e.message} in #{get_name(scenario)}"
  return nil
end
defects(scenario) click to toggle source
# File lib/json_sender.rb, line 113
def defects(scenario)
  if scenario['tags']
    tags = [scenario['tags']].flatten.compact
    tags.select{|tag| tag['name'] =~/(?:jira|defect)_/}.map{|ticket| /(?:jira|defect)_(\w+-\d+)$/.match(ticket['name'])[1]}.uniq.join(",")
  end
end
each_feature() { |scenarios,project_id,suite_id,sub_section_id,background_steps| ... } click to toggle source
# File lib/json_sender.rb, line 17
def each_feature
  results.each do |feature|
    scenarios = feature['elements'].reject{|e| e['keyword']=='Background'}.select{|e| e['type'] == 'scenario'}
    project_id,suite_id,sub_section_id,background_steps = extract_top_level_data(feature)
    yield scenarios,project_id,suite_id,sub_section_id,background_steps
  end
end
extract_top_level_data(feature) click to toggle source
# File lib/json_sender.rb, line 44
def extract_top_level_data(feature)
  puts "feature file #{feature['uri']}"
  project_id = feature['tags'].select{|j| j['name']=~/project_\d+/}.map{|j| /project_(\d+)/.match(j['name'])[1].to_i}.first
  suite_id = feature['tags'].select{|j| j['name']=~/suite_\d+/}.map{|j| /suite_(\d+)/.match(j['name'])[1].to_i}.first
  sub_section_id = feature['tags'].select{|j| j['name']=~/sub_section_\d+/}.map{|j| /sub_section_(\d+)/.match(j['name'])[1].to_i}.first
  background=feature['elements'].select{|e| e['keyword']=='Background'}.first
  background_steps = background ? background['steps'].map{|s| s['keyword']+s['name']}.join("\n") : ''
  return project_id,suite_id,sub_section_id,background_steps
end
get_id(scenario,background_steps,project_id,suite_id,sub_section_id) click to toggle source
# File lib/json_sender.rb, line 26
def get_id(scenario,background_steps,project_id,suite_id,sub_section_id)
  title = get_name(scenario)
  scenario_level_sub_section = scenario['tags'].select{|j| j['name']=~/sub_section_\d+/}.last
  if scenario_level_sub_section
    sub_section_id_override = /sub_section_(\d+)/.match(scenario_level_sub_section['name'])[1]
  else
    sub_section_id_override=sub_section_id
  end
  found_case = testrail_api_client.send_get("get_cases/#{project_id}&suite_id=#{suite_id}&section_id=#{sub_section_id_override}").select{|c| c['title'] == title}.first
  if found_case
    result= found_case['id']
  else
    test_case = create_new_case(scenario,background_steps,project_id,suite_id,sub_section_id_override)
    result = test_case ? test_case['id'] : nil
  end
  return result
end
get_name(scenario) click to toggle source
# File lib/json_sender.rb, line 54
def get_name(scenario)
  base_name = scenario['name']
  # We only extrapolate example data for scenario outlines
  is_scenario_outline = scenario['keyword'].downcase == 'scenario outline' ? true : false
  if is_scenario_outline
    # if we have scenario number then we assume this is just a JSON output without our id patch
    outline_number_str = scenario['id'].split(';').select{|e| e =~/^\d+$/}.first
    if outline_number_str
      outline_number = (outline_number_str.to_i) -1
    else
      # If we do not find an outline number, then we attempt to extrapolate the example data from the
      # id if there is any and append to the base name. note: _ before variable means it is not going
      # to be used
      _feature, _scenario, example_data = scenario['id'].split(';')
      unless example_data.nil? && example_data.strip.empty?
        base_name = if ENV['OLD_STYLE_OUTLINE_NAMES']
                      "#{base_name} :: #{example_data}"
                    else
                      "#{base_name} #{example_data}"
                    end
      end
    end
  end
  tags = [scenario['tags']].flatten.compact
  requirement = tags.select{|t| t['name'] =~/@req/}.map{|t| /@req_(\w+)/.match(t['name'])[1]}.first unless tags.empty?
  [requirement, base_name, outline_number].join(' ').strip
end
get_run(run_id) click to toggle source
# File lib/json_sender.rb, line 170
def get_run(run_id)
  testrail_api_client.send_get("get_run/#{run_id}")
end
get_tests_in_a_run(run_id) click to toggle source
# File lib/json_sender.rb, line 174
def get_tests_in_a_run(run_id)
  testrail_api_client.send_get("get_tests/#{run_id}")
end
prepare_data(scenario,background_steps) click to toggle source
# File lib/json_sender.rb, line 98
def prepare_data(scenario,background_steps)
  steps = background_steps + "\n" + scenario['steps'].map{|s| s['keyword']+s['name']}.join("\n")
  type_ids = [1]
  type_ids << 7  if scenario['tags'].any?{|tag| tag['name'] =~/manual/}
  type_ids << 13 if scenario['tags'].any?{|tag| tag['name'] =~/on_hold/}
  #get the highest precedence type found in the tags. E.g. if it's @on_hold and @manual it selects 13 for on hold
  type_id = ([13,7,1] & type_ids).first

  data = {'title'=>get_name(scenario),
          'type_id'=>type_id,
          'custom_steps'=>steps,
          'refs'=>refs(scenario)
  }
end
refs(scenario) click to toggle source
# File lib/json_sender.rb, line 120
def refs(scenario)
  if scenario['tags']
    tags = [scenario['tags']].flatten.compact
    tags.select{|tag| tag['name'] =~/(?:jira|ref)_/}.map{|ticket| /(?:jira|ref)_(\w+-\d+)$/.match(ticket['name'])[1]}.uniq.join(",")
  end
end
remove_all_except_these_cases_from_suite(testcases,project_id,suite_id) click to toggle source
# File lib/json_sender.rb, line 223
def remove_all_except_these_cases_from_suite(testcases,project_id,suite_id)
  puts '=== testcases === '
  puts testcases
  # get a list of automated tests, ignore manual or on hold tests
  existing_cases = testrail_api_client.send_get("get_cases/#{project_id}&suite_id=#{suite_id}").select{|t| t['type_id']==1}.map{|m| m['id']}
  puts '===== existing_cases === '
  puts existing_cases
  (existing_cases - testcases).each do |case_to_remove|
    puts "case_to_remove #{case_to_remove}"
    testrail_api_client.send_post("delete_case/#{case_to_remove}",nil)
  end
end
remove_all_except_these_cases_from_testrun(testcases,run_id) click to toggle source
# File lib/json_sender.rb, line 215
def remove_all_except_these_cases_from_testrun(testcases,run_id)
  run = get_run(run_id)
  unless run['include_all']
    case_ids = get_tests_in_a_run(run_id).map{|h| h['case_id']} & testcases
    update_run(run_id,{'case_ids'=>case_ids})
  end
end
remove_case_from_test_run(testcase,run_id) click to toggle source
# File lib/json_sender.rb, line 197
def remove_case_from_test_run(testcase,run_id)
  testcase_id = get_id(testcase)
  run = get_run(run_id)
  unless run['include_all']
    case_ids = get_tests_in_a_run(run_id).map{|h| h['case_id']} - [testcase_id]
    update_run(run_id,{'case_ids'=>case_ids})
  end
end
send_result(scenario,id,run_id) click to toggle source
# File lib/json_sender.rb, line 127
    def send_result(scenario,id,run_id)
      error_line = scenario['steps'].select{|s| s['result']['status'] != 'passed'}.first 
      if error_line
        #puts error_line['result']
        testrail_status = case error_line['result']['status']
                          when 'failed'
                            {id:5,comment: 'failed'}
                          when 'undefined'
                            {id:7,comment: 'undefined step'}
                          when  'pending'
                            {id:6,comment: 'pending step'}
                          when  'skipped'
                            {id:5,comment: 'failed in before hook'}
                          end
        error_result = error_line['error_message']
        failure_message = <<-FAILURE
        Error message: #{testrail_status[:comment]} #{error_result}
        Step: #{error_line['keyword']} #{error_line['name']}
        Location: #{error_line['match']['location']}
        FAILURE
      else
        testrail_status = {id:1,comment: 'passed'}
        failure_message = nil
      end
      report_on_result =  {status_id:testrail_status[:id],comment:failure_message,defects:defects(scenario)}
      tries = 3
      begin
        testrail_api_client.send_post("add_result_for_case/#{run_id}/#{id}",report_on_result)
      rescue => e
        if e.message =~ /No \(active\) test found for the run\/case combination/
          tries -= 1
          add_case_to_test_run(id,run_id)
          if tries > 0
            retry
          else
            puts "#{e.message} testrun=#{run_id} test case id=#{id}"
          end
        else
          puts "#{e.message} testrun=#{run_id} test case id=#{id}"
        end
      end
    end
send_steps(scenario,background_steps,testcase_id) click to toggle source
# File lib/json_sender.rb, line 90
def send_steps(scenario,background_steps,testcase_id)
  data = prepare_data(scenario,background_steps)
  testrail_api_client.send_post("update_case/#{testcase_id}",data)
rescue StandardError => e
  puts "#{e.message} in #{get_name(scenario)}"
  return nil
end
update_plan(plan_id,run_id,case_ids) click to toggle source
# File lib/json_sender.rb, line 191
def update_plan(plan_id,run_id,case_ids)
  test_plan = testrail_api_client.send_get("get_plan/#{plan_id}")
  entry_id = test_plan['entries'].select{|e| e['runs'].any?{|r| r['id']==run_id}}.first['id']
  testrail_api_client.send_post("update_plan_entry/#{plan_id}/#{entry_id}",case_ids)
end
update_run(run_id,case_ids) click to toggle source
# File lib/json_sender.rb, line 178
def update_run(run_id,case_ids)
  run = get_run(run_id)
  begin
    if run['plan_id']
      update_plan(run['plan_id'],run_id,case_ids)
    else
      testrail_api_client.send_post("update_run/#{run_id}",case_ids)
    end
  rescue => e
    puts "#{e.message} testrun=#{run_id} test case ids=#{case_ids}"
  end
end