module ReportPortal

TODO: Screenshots TODO: Logs

Copyright 2015 EPAM Systems

This file is part of Report Portal.

Report Portal is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

ReportPortal is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with Report Portal. If not, see <www.gnu.org/licenses/>.

Constants

LOG_LEVELS
TestItem
VERSION

Attributes

current_scenario[RW]
launch_id[RW]

Public Class Methods

<<(msg) click to toggle source
# File lib/report_portal/logging/logger.rb, line 46
def <<(msg)
  ret = orig_write(msg)
  ReportPortal.send_log(ReportPortal::LOG_LEVELS[:unknown], msg.to_s, ReportPortal.now)
  ret
end
add(severity, message = nil, progname = nil) { || ... } click to toggle source
# File lib/report_portal/logging/logger.rb, line 28
def add(severity, message = nil, progname = nil, &block)
  ret = orig_add(severity, message, progname, &block)

  unless severity < @level
    progname ||= @progname
    if message.nil?
      if block_given?
        message = yield
      else
        message = progname
        progname = @progname
      end
    end
    ReportPortal.send_log(format_severity(severity), format_message(format_severity(severity), Time.now, progname, message.to_s), ReportPortal.now)
  end
  ret
end
close_child_items(parent_id) click to toggle source

needed for parallel formatter

# File lib/reportportal.rb, line 157
def close_child_items(parent_id)
  if parent_id.nil?
    url = "#{Settings.instance.project_url}/item?filter.eq.launch=#{@launch_id}&filter.size.path=0&page.page=1&page.size=100"
  else
    url = "#{Settings.instance.project_url}/item?filter.eq.parent=#{parent_id}&page.page=1&page.size=100"
  end
  ids = []
  loop do
    response = do_request(url) { |r| JSON.parse(r.get) }
    if response.key?('links')
      link = response['links'].find { |i| i['rel'] == 'next' }
      url = link.nil? ? nil : link['href']
    else
      url = nil
    end
    response['content'].each do |i|
      ids << i['id'] if i['has_childs'] && i['status'] == 'IN_PROGRESS'
    end
    break if url.nil?
  end

  ids.each do |id|
    close_child_items(id)
    # temporary, we actually only need the id
    finish_item(TestItem.new(nil, nil, id, nil, nil, nil, nil))
  end
end
finish_item(item, status = nil, end_time = nil, force_issue = nil) click to toggle source
# File lib/reportportal.rb, line 90
def finish_item(item, status = nil, end_time = nil, force_issue = nil)
  unless item.nil? || item.id.nil? || item.closed
    url = "#{Settings.instance.project_url}/item/#{item.id}"
    data = { end_time: end_time.nil? ? now : end_time }
    data[:status] = status unless status.nil?
    if force_issue && status != :passed # TODO: check for :passed status is probably not needed
      data[:issue] = { issue_type: 'AUTOMATION_BUG', comment: force_issue.to_s }
    elsif status == :skipped
      data[:issue] = { issue_type: 'NOT_ISSUE' }
    end
    do_request(url) do |resource|
      resource.put data.to_json, content_type: :json, &@response_handler
    end
    item.closed = true
  end
end
finish_launch(end_time = now) click to toggle source
# File lib/reportportal.rb, line 71
def finish_launch(end_time = now)
  url = "#{Settings.instance.project_url}/launch/#{@launch_id}/finish"
  data = { end_time: end_time }
  do_request(url) do |resource|
    resource.put data.to_json, content_type: :json, &@response_handler
  end
end
item_id_of(name, parent_node) click to toggle source

needed for parallel formatter

# File lib/reportportal.rb, line 140
def item_id_of(name, parent_node)
  if parent_node.is_root? # folder without parent folder
    url = "#{Settings.instance.project_url}/item?filter.eq.launch=#{@launch_id}&filter.eq.name=#{URI.escape(name)}&filter.size.path=0"
  else
    url = "#{Settings.instance.project_url}/item?filter.eq.parent=#{parent_node.content.id}&filter.eq.name=#{URI.escape(name)}"
  end
  do_request(url) do |resource|
    data = JSON.parse(resource.get)
    if data.key? 'content'
      data['content'].empty? ? nil : data['content'][0]['id']
    else
      nil # item isn't started yet
    end
  end
end
now() click to toggle source
# File lib/reportportal.rb, line 46
def now
  (Time.now.to_f * 1000).to_i
end
patch_logger() click to toggle source

Monkey-patch for built-in Logger class

# File lib/report_portal/logging/logger.rb, line 24
def patch_logger
  Logger.class_eval do
    alias_method :orig_add, :add
    alias_method :orig_write, :<<
    def add(severity, message = nil, progname = nil, &block)
      ret = orig_add(severity, message, progname, &block)

      unless severity < @level
        progname ||= @progname
        if message.nil?
          if block_given?
            message = yield
          else
            message = progname
            progname = @progname
          end
        end
        ReportPortal.send_log(format_severity(severity), format_message(format_severity(severity), Time.now, progname, message.to_s), ReportPortal.now)
      end
      ret
    end

    def <<(msg)
      ret = orig_write(msg)
      ReportPortal.send_log(ReportPortal::LOG_LEVELS[:unknown], msg.to_s, ReportPortal.now)
      ret
    end
  end
end
send_file(status, path, label = nil, time = now, mime_type='image/png') click to toggle source
# File lib/reportportal.rb, line 119
def send_file(status, path, label = nil, time = now, mime_type='image/png')
  url = "#{Settings.instance.project_url}/log"
  unless File.file?(path)
    extension = ".#{MIME::Types[mime_type].first.extensions.first}"
    temp = Tempfile.open(['file',extension])
    temp.binmode
    temp.write(Base64.decode64(path))
    temp.rewind
    path = temp
  end
  File.open(File.realpath(path), 'rb') do |file|
    label ||= File.basename(file)
    json = { level: status_to_level(status), message: label, item_id: @current_scenario.id, time: time, file: { name: File.basename(file) } }
    data = { :json_request_part => [json].to_json, label => file, :multipart => true, :content_type => 'application/json' }
    do_request(url) do |resource|
      resource.post(data, { content_type: 'multipart/form-data' }, &@response_handler)
    end
  end
end
send_log(status, message, time) click to toggle source

TODO: implement force finish

# File lib/reportportal.rb, line 109
def send_log(status, message, time)
  unless @current_scenario.nil? || @current_scenario.closed # it can be nil if scenario outline in expand mode is executed
    url = "#{Settings.instance.project_url}/log"
    data = { item_id: @current_scenario.id, time: time, level: status_to_level(status), message: message.to_s }
    do_request(url) do |resource|
      resource.post(data.to_json, content_type: :json, &@response_handler)
    end
  end
end
start_item(item_node) click to toggle source
# File lib/reportportal.rb, line 79
def start_item(item_node)
  url = "#{Settings.instance.project_url}/item"
  url += "/#{item_node.parent.content.id}" unless item_node.parent && item_node.parent.is_root?
  item = item_node.content
  data = { start_time: item.start_time, name: item.name[0, 255], type: item.type.to_s, launch_id: @launch_id, description: item.description }
  data[:tags] = item.tags unless item.tags.empty?
  do_request(url) do |resource|
    JSON.parse(resource.post(data.to_json, content_type: :json, &@response_handler))['id']
  end
end
start_launch(description, start_time = now) click to toggle source
# File lib/reportportal.rb, line 63
def start_launch(description, start_time = now)
  url = "#{Settings.instance.project_url}/launch"
  data = { name: Settings.instance.launch, start_time: start_time, tags: Settings.instance.tags, description: description, mode: Settings.instance.launch_mode }
  @launch_id = do_request(url) do |resource|
    JSON.parse(resource.post(data.to_json, content_type: :json, &@response_handler))['id']
  end
end
status_to_level(status) click to toggle source
# File lib/reportportal.rb, line 50
def status_to_level(status)
  case status
  when :passed
    LOG_LEVELS[:info]
  when :failed, :undefined, :pending, :error
    LOG_LEVELS[:error]
  when :skipped
    LOG_LEVELS[:warn]
  else
    LOG_LEVELS.fetch(status, LOG_LEVELS[:info])
  end
end

Private Class Methods

create_resource(url) click to toggle source
# File lib/reportportal.rb, line 187
def create_resource(url)
  props = { :headers => {:Authorization => "Bearer #{Settings.instance.uuid}"}}
  verify_ssl = Settings.instance.disable_ssl_verification
  props[:verify_ssl] = !verify_ssl unless verify_ssl.nil?
  RestClient::Resource.new url, props
end
do_request(url) { |resource| ... } click to toggle source
# File lib/reportportal.rb, line 194
def do_request(url)
  resource = create_resource(url)
  tries = 3
  begin
    yield resource
  rescue
    p "Request to #{url} produced an exception: #{$!.class}: #{$!}"
    $!.backtrace.each { |l| p l }
    retry unless (tries -= 1).zero?
    p "Failed to execute request to #{url} after 3 attempts."
    nil
  end
end