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
Public Class Methods
# 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
# 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
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
# 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
# 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
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
# File lib/reportportal.rb, line 46 def now (Time.now.to_f * 1000).to_i end
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
# 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
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
# 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
# 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
# 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
# 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
# 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