rpruby 1.2 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'pathname'
3
+ require 'tempfile'
4
+ require_relative '../rpruby'
5
+
6
+ namespace :rpruby do
7
+ desc 'Start launch in Report Portal and print its id to $stdout (for use with attach_to_launch formatter mode)'
8
+ task :start_launch do
9
+ description = ENV['description'] || Rpruby::Settings.instance.description
10
+ file_to_write_launch_id = ENV['file_for_launch_id'] || Rpruby::Settings.instance.file_with_launch_id
11
+ file_to_write_launch_id ||= Pathname(Dir.tmpdir) + 'rp_launch_id.tmp'
12
+ launch_id = Rpruby.start_launch(description)
13
+ File.write(file_to_write_launch_id, launch_id)
14
+ puts launch_id
15
+ end
16
+
17
+ desc 'Finish launch in Report Portal (for use with attach_to_launch formatter mode)'
18
+ task :finish_launch do
19
+ launch_id = ENV['launch_id'] || Rpruby::Settings.instance.launch_id
20
+ file_with_launch_id = ENV['file_with_launch_id'] || Rpruby::Settings.instance.file_with_launch_id
21
+ puts "Launch id isn't provided. Provide it either via RP_LAUNCH_ID or RP_FILE_WITH_LAUNCH_ID environment variables" if !launch_id && !file_with_launch_id
22
+ puts 'Both RP_LAUNCH_ID and RP_FILE_WITH_LAUNCH_ID are provided via environment variables' if launch_id && file_with_launch_id
23
+ Rpruby.launch_id = launch_id || File.read(file_with_launch_id)
24
+ Rpruby.close_child_items(nil)
25
+ Rpruby.finish_launch
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rpruby
4
+ VERSION = '1.2.1'.freeze
5
+ end
data/lib/rpruby.rb ADDED
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+ require 'base64'
3
+ require 'cgi'
4
+ require 'http'
5
+ require 'json'
6
+ require 'mime/types'
7
+ require 'pathname'
8
+ require 'tempfile'
9
+ require 'uri'
10
+
11
+ require_relative 'rpruby/event_bus'
12
+ require_relative 'rpruby/models/item_search_options'
13
+ require_relative 'rpruby/models/test_item'
14
+ require_relative 'rpruby/settings'
15
+ require_relative 'rpruby/http_client'
16
+ require_relative "rpruby/version"
17
+
18
+ module Rpruby
19
+ class Error < StandardError; end
20
+ LOG_LEVELS = { error: 'ERROR', warn: 'WARN', info: 'INFO', debug: 'DEBUG', trace: 'TRACE', fatal: 'FATAL', unknown: 'UNKNOWN' }.freeze
21
+
22
+ class << self
23
+ attr_accessor :launch_id, :current_scenario
24
+
25
+ def now
26
+ (current_time.to_f * 1000).to_i
27
+ end
28
+
29
+ def status_to_level(status)
30
+ case status
31
+ when :passed
32
+ LOG_LEVELS[:info]
33
+ when :failed, :undefined, :pending, :error
34
+ LOG_LEVELS[:error]
35
+ when :skipped
36
+ LOG_LEVELS[:warn]
37
+ else
38
+ LOG_LEVELS.fetch(status, LOG_LEVELS[:info])
39
+ end
40
+ end
41
+
42
+ def start_launch(description, start_time = now)
43
+ required_data = { name: Settings.instance.launch, start_time: start_time, description:
44
+ description, mode: Settings.instance.launch_mode }
45
+ data = prepare_options(required_data, Settings.instance)
46
+ @launch_id = send_request(:post, 'launch', json: data)['id']
47
+ end
48
+
49
+ def finish_launch(end_time = now)
50
+ data = { end_time: end_time }
51
+ send_request(:put, "launch/#{@launch_id}/finish", json: data)
52
+ end
53
+
54
+ def start_item(item_node)
55
+ path = 'item'
56
+ path += "/#{item_node.parent.content.id}" unless item_node.parent&.is_root?
57
+ item = item_node.content
58
+ data = { start_time: item.start_time, name: item.name[0, 255], type: item.type.to_s, launch_id: @launch_id, description: item.description }
59
+ data[:tags] = item.tags unless item.tags.empty?
60
+ event_bus.broadcast(:prepare_start_item_request, request_data: data)
61
+ send_request(:post, path, json: data)['id']
62
+ end
63
+
64
+ def finish_item(item, status = nil, end_time = nil, force_issue = nil)
65
+ unless item.nil? || item.id.nil? || item.closed
66
+ data = { end_time: end_time.nil? ? now : end_time }
67
+ data[:status] = status unless status.nil?
68
+ if force_issue && status != :passed # TODO: check for :passed status is probably not needed
69
+ data[:issue] = { issue_type: 'AUTOMATION_BUG', comment: force_issue.to_s }
70
+ elsif status == :skipped
71
+ data[:issue] = { issue_type: 'NOT_ISSUE' }
72
+ end
73
+ send_request(:put, "item/#{item.id}", json: data)
74
+ item.closed = true
75
+ end
76
+ end
77
+
78
+ # TODO: implement force finish
79
+
80
+ def send_log(status, message, time)
81
+ unless @current_scenario.nil? || @current_scenario.closed # it can be nil if scenario outline in expand mode is executed
82
+ data = { item_id: @current_scenario.id, time: time, level: status_to_level(status), message: message.to_s }
83
+ send_request(:post, 'log', json: data)
84
+ end
85
+ end
86
+
87
+ def send_file(status, path_or_src, label = nil, time = now, mime_type = 'image/png')
88
+ str_without_nils = path_or_src.to_s.gsub("\0", '') # file? does not allow NULLs inside the string
89
+ if File.file?(str_without_nils)
90
+ send_file_from_path(status, path_or_src, label, time, mime_type)
91
+ else
92
+ if mime_type =~ /;base64$/
93
+ mime_type = mime_type[0..-8]
94
+ path_or_src = Base64.decode64(path_or_src)
95
+ end
96
+ extension = ".#{MIME::Types[mime_type].first.extensions.first}"
97
+ Tempfile.open(['report_portal', extension]) do |tempfile|
98
+ tempfile.binmode
99
+ tempfile.write(path_or_src)
100
+ tempfile.rewind
101
+ send_file_from_path(status, tempfile.path, label, time, mime_type)
102
+ end
103
+ end
104
+ end
105
+
106
+ # @option options [Hash] options, see ReportPortal::ItemSearchOptions
107
+ def get_items(filter_options = {})
108
+ page_size = 100
109
+ max_pages = 100
110
+ all_items = []
111
+ 1.step.each do |page_number|
112
+ raise 'Too many pages with the results were returned' if page_number > max_pages
113
+
114
+ options = ItemSearchOptions.new({ page_size: page_size, page_number: page_number }.merge(filter_options))
115
+ page_items = send_request(:get, 'item', params: options.query_params)['content'].map do |item_params|
116
+ TestItem.new(item_params)
117
+ end
118
+ all_items += page_items
119
+ break if page_items.size < page_size
120
+ end
121
+ all_items
122
+ end
123
+
124
+ # @param item_ids [Array<String>] an array of items to remove (represented by ids)
125
+ def delete_items(item_ids)
126
+ send_request(:delete, 'item', params: { ids: item_ids })
127
+ end
128
+
129
+ # needed for parallel formatter
130
+ def item_id_of(name, parent_node)
131
+ path = if parent_node.is_root? # folder without parent folder
132
+ "item?filter.eq.launch=#{@launch_id}&filter.eq.name=#{CGI.escape(name)}&filter.size.path=0"
133
+ else
134
+ "item?filter.eq.parent=#{parent_node.content.id}&filter.eq.name=#{CGI.escape(name)}"
135
+ end
136
+ data = send_request(:get, path)
137
+ if data.key? 'content'
138
+ data['content'].empty? ? nil : data['content'][0]['id']
139
+ end
140
+ end
141
+
142
+ # needed for parallel formatter
143
+ def launch_id_to_number()
144
+ path = "launch/#{@launch_id}"
145
+ data = send_request(:get, path)
146
+ data['id']
147
+ end
148
+
149
+ # needed for parallel formatter
150
+ def close_child_items(parent_id)
151
+ path = if parent_id.nil?
152
+ "item?filter.eq.launchId=#{launch_id_to_number}"
153
+ else
154
+ "item?filter.eq.parent=#{parent_id}&page.page=1&page.size=100"
155
+ end
156
+ ids = []
157
+ loop do
158
+ data = send_request(:get, path)
159
+ if data.key?('links')
160
+ link = data['links'].find { |i| i['rel'] == 'next' }
161
+ url = link.nil? ? nil : link['href']
162
+ else
163
+ url = nil
164
+ end
165
+ data['content'].each do |i|
166
+ ids << i['id'] if i['has_childs'] && i['status'] == 'IN_PROGRESS'
167
+ end
168
+ break if url.nil?
169
+ end
170
+
171
+ ids.each do |id|
172
+ close_child_items(id)
173
+ finish_item(TestItem.new(id: id))
174
+ end
175
+ end
176
+
177
+ # Registers an event. The proc will be called back with the event object.
178
+ def on_event(name, &proc)
179
+ event_bus.on(name, &proc)
180
+ end
181
+
182
+ private
183
+
184
+ def send_file_from_path(status, path, label, time, mime_type)
185
+ File.open(File.realpath(path), 'rb') do |file|
186
+ filename = File.basename(file)
187
+ json = [{ level: status_to_level(status), message: label || filename, item_id: @current_scenario.id, time: time, file: { name: filename } }]
188
+ form = {
189
+ json_request_part: HTTP::FormData::Part.new(JSON.dump(json), content_type: 'application/json'),
190
+ binary_part: HTTP::FormData::File.new(file, filename: filename, content_type: MIME::Types[mime_type].first.to_s)
191
+ }
192
+ send_request(:post, 'log', form: form)
193
+ end
194
+ end
195
+
196
+ def send_request(verb, path, options = {})
197
+ http_client.send_request(verb, path, options)
198
+ end
199
+
200
+ def http_client
201
+ @http_client ||= HttpClient.new
202
+ end
203
+
204
+ def current_time
205
+ # `now_without_mock_time` is provided by Timecop and returns a real, not mocked time
206
+ return Time.now_without_mock_time if Time.respond_to?(:now_without_mock_time)
207
+
208
+ Time.now
209
+ end
210
+
211
+ def event_bus
212
+ @event_bus ||= EventBus.new
213
+ end
214
+
215
+ def prepare_options(data, config = {})
216
+ if config.attributes
217
+ data[:attributes] = config.attributes
218
+ elsif (data[:tags] = config.tags)
219
+ end
220
+ data
221
+ end
222
+ end
223
+ end
data/rpruby.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ # lib = File.expand_path('lib', __dir__)
3
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require_relative "lib/rpruby/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "rpruby"
9
+ spec.version = Rpruby::VERSION
10
+ spec.authors = ["Jayachandra Konduru(JC)"]
11
+ spec.email = ["jayak8390@gmail.com"]
12
+
13
+ spec.summary = 'ReportPortal Ruby Client'
14
+ spec.description = 'Cucumber and RSpec clients for EPAM ReportPortal system'
15
+ spec.homepage = 'https://github.com/jaya-konduru/rpruby'
16
+ spec.license = "MIT"
17
+ spec.required_ruby_version = ">= 2.4.0"
18
+
19
+ #spec.metadata["allowed_push_host"] = "TODO: Set to 'https://mygemserver.com'"
20
+
21
+ #spec.metadata["homepage_uri"] = spec.homepage
22
+ #spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
23
+ #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
29
+ end
30
+ spec.bindir = "bin"
31
+ spec.executables = spec.files.grep(%r{\Abin/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ # spec.add_dependency "example-gem", "~> 1.0"
36
+
37
+ spec.add_dependency('http')
38
+ spec.add_dependency('mime-types')
39
+ spec.add_dependency('rubytree')
40
+ spec.add_development_dependency('rubocop')
41
+
42
+ # For more information and examples about making a new gem, checkout our
43
+ # guide at: https://bundler.io/guides/creating_gem.html
44
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpruby
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.2'
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jayachandra Konduru(JC)
@@ -69,10 +69,45 @@ dependencies:
69
69
  description: Cucumber and RSpec clients for EPAM ReportPortal system
70
70
  email:
71
71
  - jayak8390@gmail.com
72
- executables: []
72
+ executables:
73
+ - console
74
+ - setup
73
75
  extensions: []
74
76
  extra_rdoc_files: []
75
- files: []
77
+ files:
78
+ - ".DS_Store"
79
+ - ".github/workflows/main.yml"
80
+ - ".gitignore"
81
+ - ".rspec"
82
+ - ".rubocop.yml"
83
+ - CHANGELOG.md
84
+ - CODE_OF_CONDUCT.md
85
+ - Gemfile
86
+ - LICENSE.txt
87
+ - README.md
88
+ - Rakefile
89
+ - bin/console
90
+ - bin/setup
91
+ - config/report_portal.yaml.example
92
+ - lib/rpruby.rb
93
+ - lib/rpruby/cucumber/formatter.rb
94
+ - lib/rpruby/cucumber/messagereport.rb
95
+ - lib/rpruby/cucumber/parallel_formatter.rb
96
+ - lib/rpruby/cucumber/parallel_report.rb
97
+ - lib/rpruby/cucumber/report.rb
98
+ - lib/rpruby/event_bus.rb
99
+ - lib/rpruby/events/prepare_start_item_request.rb
100
+ - lib/rpruby/http_client.rb
101
+ - lib/rpruby/logging/log4r_outputter.rb
102
+ - lib/rpruby/logging/logger.rb
103
+ - lib/rpruby/logging/logging_appender.rb
104
+ - lib/rpruby/models/item_search_options.rb
105
+ - lib/rpruby/models/test_item.rb
106
+ - lib/rpruby/rspec/formatter.rb
107
+ - lib/rpruby/settings.rb
108
+ - lib/rpruby/tasks.rb
109
+ - lib/rpruby/version.rb
110
+ - rpruby.gemspec
76
111
  homepage: https://github.com/jaya-konduru/rpruby
77
112
  licenses:
78
113
  - MIT