parallel_report_portal 2.1.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10a0ede4e1da6f5fc4788775483996e7ecf4a21009b06bfbbec5b49593c623bc
4
- data.tar.gz: 8a0f3966ac4134f96e4a18e42e4b779943425d5d7cf9947dfc6afa10ee376859
3
+ metadata.gz: 6eac77f10cdc4ca803b014029883de0cc28439fe645547190ff1022878f430c5
4
+ data.tar.gz: 1e50abb80970dfcab716abe749b554b6622209ac55a51c207b4bbc7e3201d078
5
5
  SHA512:
6
- metadata.gz: 380772393a3450a86df43444caa69e09b93d5b9b88a66ea658adc0baac40b064fe74e299cdec0dbf99c299a295c2d550914040ae87a65d82458c801e9f94ca2d
7
- data.tar.gz: 5950fe72eb47bf2c195621d94faac14cfbb7a17b73aeae16f02a952b01a475f86e6a0901a8113ad7f00dd9d5081f5b162fd51266424cf5b7d6070b65162d3a5c
6
+ metadata.gz: 9e3b3b267691986d4e98051be3fc2027cfff873a3cb69de2ce1d5e18df435b769bf8bc94ace5f03b436d285f28b121b0986056cfc3f909aaa94c7931b96f6210
7
+ data.tar.gz: '068c14c09b3b8c47da4b6bf2a5513316f66ecc8893bca4ff112787bc6f2db1582198d042f6cbc35357adcc23136bd4215ecddc84c50988bf22efbac94471c469'
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --require spec_helper
2
+ --format documentation
@@ -0,0 +1,13 @@
1
+ module ParallelReportPortal
2
+ # Handle post launch hooks
3
+ module AfterLaunch
4
+
5
+ attr_accessor :launch_finished_block
6
+ attr_accessor :report_url
7
+
8
+ def after_launch(&block)
9
+ @launch_finished_block = block
10
+ end
11
+
12
+ end
13
+ end
@@ -1,23 +1,23 @@
1
1
  module ParallelReportPortal
2
2
  # The Configuration class holds the connection properties to communicate with
3
3
  # Report Portal and to identify the user and project for reporting.
4
- #
4
+ #
5
5
  # It attempts to load a configuration file called +report_portal.yml+ first in a
6
6
  # local directory called +config+ and if that's not found in the current directory.
7
7
  # (Report Portal actually tells you to create a files called +REPORT_PORTAL.YML+ in
8
- # uppercase -- for this reason the initializer is case insensitive with regards to
8
+ # uppercase -- for this reason the initializer is case insensitive with regards to
9
9
  # the file name)
10
- #
10
+ #
11
11
  # It will then try an apply the following environment variables, if present (these
12
12
  # can be specified in either lowercase for backwards compatibility with the official
13
13
  # gem or in uppercase for reasons of sanity)
14
- #
14
+ #
15
15
  # == Environment variables
16
- #
16
+ #
17
17
  # RP_UUID:: The UUID of the user associated with this launch
18
18
  # RP_ENDPOINT:: the URL of the Report Portal API endpoint
19
19
  # RP_PROJECT:: the Report Portal project name -- this must already exist within Report Port and this user must be a member of the project
20
- # RP_LAUNCH:: The name of this launch
20
+ # RP_LAUNCH:: The name of this launch
21
21
  # RP_DESCRIPTION:: A textual string describing this launch
22
22
  # RP_TAGS:: A set of tags to pass to Report Portal for this launch. If these are set via an environment variable, provide a comma-separated string of tags
23
23
  # RP_ATTRIBUTES:: A set of attribute tags to pass to Report Portal for this launch. If these are set via an environment variable, provide a comma-separated string of attributes
@@ -52,7 +52,6 @@ module ParallelReportPortal
52
52
  # @return [Integer] the number of seconds for the read connection to timeout
53
53
  attr_accessor :read_timeout
54
54
 
55
-
56
55
  # Create an instance of Configuration.
57
56
  #
58
57
  # The initializer will first attempt to load a configuration files called
@@ -101,6 +100,7 @@ module ParallelReportPortal
101
100
  end
102
101
  end
103
102
 
103
+
104
104
  # Simple method to obtain an attribute from this class or set default value
105
105
  # param [symbol] a symbol version of the attribute
106
106
  def fetch(key, default_value)
@@ -4,39 +4,39 @@ require 'tree'
4
4
  module ParallelReportPortal
5
5
  module Cucumber
6
6
  # Report object. This handles the management of the state hierarchy and
7
- # the issuing of the requests to the HTTP module.
7
+ # the issuing of the requests to the HTTP module.
8
8
  class Report
9
-
9
+
10
10
  attr_reader :launch_id
11
-
11
+
12
12
  Feature = Struct.new(:feature, :id)
13
-
14
- LOG_LEVELS = {
15
- error: 'ERROR',
16
- warn: 'WARN',
17
- info: 'INFO',
18
- debug: 'DEBUG',
19
- trace: 'TRACE',
20
- fatal: 'FATAL',
21
- unknown: 'UNKNOWN'
13
+
14
+ LOG_LEVELS = {
15
+ error: 'ERROR',
16
+ warn: 'WARN',
17
+ info: 'INFO',
18
+ debug: 'DEBUG',
19
+ trace: 'TRACE',
20
+ fatal: 'FATAL',
21
+ unknown: 'UNKNOWN'
22
22
  }
23
23
 
24
-
24
+
25
25
  # Create a new instance of the report
26
26
  def initialize(ast_lookup = nil)
27
27
  @feature = nil
28
- @tree = Tree::TreeNode.new( 'root' )
28
+ @tree = Tree::TreeNode.new( 'root' )
29
29
  @ast_lookup = ast_lookup
30
30
  end
31
-
31
+
32
32
  # Issued to start a launch. It is possilbe that this method could be called
33
33
  # from multiple processes for the same launch if this is being run with
34
34
  # parallel tests enabled. A temporary launch file will be created (using
35
35
  # exclusive locking). The first time this method is called it will write the
36
36
  # launch id to the launch file, subsequent calls by other processes will read
37
37
  # this launch id and use that.
38
- #
39
- # @param start_time [Integer] the millis from the epoch
38
+ #
39
+ # @param start_time [Integer] the millis from the epoch
40
40
  # @return [String] the UUID of this launch
41
41
  def launch_started(start_time)
42
42
  ParallelReportPortal.file_open_exlock_and_block(ParallelReportPortal.launch_id_file, 'a+' ) do |file|
@@ -50,39 +50,42 @@ module ParallelReportPortal
50
50
  @launch_id
51
51
  end
52
52
  end
53
-
53
+
54
54
  # Called to finish a launch. Any open children items will be closed in the process.
55
- #
55
+ #
56
56
  # @param clock [Integer] the millis from the epoch
57
57
  def launch_finished(clock)
58
58
  @tree.postordered_each do |node|
59
- ParallelReportPortal.req_feature_finished(node.content, clock) unless node.is_root?
59
+ response = ParallelReportPortal.req_feature_finished(node.content, clock) unless node.is_root?
60
+ parse_report_link_from_response(response)
60
61
  end
61
- ParallelReportPortal.req_launch_finished(launch_id, clock)
62
+ response = ParallelReportPortal.req_launch_finished(launch_id, clock)
63
+ parse_report_link_from_response(response)
64
+ ParallelReportPortal.launch_finished_block.call if ParallelReportPortal.launch_finished_block
62
65
  end
63
-
66
+
64
67
  # Called to indicate that a feature has started.
65
- #
66
- # @param
68
+ #
69
+ # @param
67
70
  def feature_started(feature, clock)
68
71
  parent_id = hierarchy(feature, clock)
69
72
  feature = feature.feature if using_cucumber_messages?
70
73
  ParallelReportPortal.req_feature_started(launch_id, parent_id, feature, clock)
71
74
  end
72
-
75
+
73
76
  def feature_finished(clock)
74
77
  if @feature
75
78
  resp = ParallelReportPortal.req_feature_finished(@feature.id, clock)
76
79
  end
77
80
  end
78
-
81
+
79
82
  def test_case_started(event, clock)
80
83
  test_case = lookup_test_case(event.test_case)
81
84
  feature = lookup_feature(event.test_case)
82
85
  feature = current_feature(feature, clock)
83
86
  @test_case_id = ParallelReportPortal.req_test_case_started(launch_id, feature.id, test_case, clock)
84
87
  end
85
-
88
+
86
89
  def test_case_finished(event, clock)
87
90
  result = event.result
88
91
  status = result.to_sym
@@ -93,7 +96,7 @@ module ParallelReportPortal
93
96
  end
94
97
  resp = ParallelReportPortal.req_test_case_finished(@test_case_id, status, clock)
95
98
  end
96
-
99
+
97
100
  def test_step_started(event, clock)
98
101
  test_step = event.test_step
99
102
  if !hook?(test_step)
@@ -104,11 +107,11 @@ module ParallelReportPortal
104
107
  elsif (using_cucumber_messages? ? test_step : step_source).multiline_arg.data_table?
105
108
  detail << (using_cucumber_messages? ? test_step : step_source).multiline_arg.raw.reduce("\n") {|acc, row| acc << "| #{row.join(' | ')} |\n"}
106
109
  end
107
-
110
+
108
111
  ParallelReportPortal.req_log(@test_case_id, detail, status_to_level(:trace), clock)
109
112
  end
110
113
  end
111
-
114
+
112
115
  def test_step_finished(event, clock)
113
116
  test_step = event.test_step
114
117
  result = event.result
@@ -129,13 +132,13 @@ module ParallelReportPortal
129
132
  ParallelReportPortal.req_log(@test_case_id, detail, status_to_level(status), clock) if detail
130
133
 
131
134
  end
132
-
135
+
133
136
  private
134
137
 
135
138
  def using_cucumber_messages?
136
139
  @ast_lookup != nil
137
140
  end
138
-
141
+
139
142
  def hierarchy(feature, clock)
140
143
  node = nil
141
144
  path_components = if using_cucumber_messages?
@@ -144,7 +147,7 @@ module ParallelReportPortal
144
147
  feature.location.file.split(File::SEPARATOR)
145
148
  end
146
149
  ParallelReportPortal.file_open_exlock_and_block(ParallelReportPortal.hierarchy_file, 'a+b' ) do |file|
147
- @tree = Marshal.load(File.read(file)) if file.size > 0
150
+ @tree = Marshal.load(File.read(file)) if file.size > 0
148
151
  node = @tree.root
149
152
  path_components[0..-2].each do |component|
150
153
  next_node = node[component]
@@ -161,7 +164,7 @@ module ParallelReportPortal
161
164
  file.write(Marshal.dump(@tree))
162
165
  file.flush
163
166
  end
164
-
167
+
165
168
  node.content
166
169
  end
167
170
 
@@ -193,7 +196,7 @@ module ParallelReportPortal
193
196
  step.source.last
194
197
  end
195
198
  end
196
-
199
+
197
200
  def current_feature(feature, clock)
198
201
  if @feature&.feature == feature
199
202
  @feature
@@ -202,7 +205,7 @@ module ParallelReportPortal
202
205
  @feature = Feature.new(feature, feature_started(feature, clock))
203
206
  end
204
207
  end
205
-
208
+
206
209
  def hook?(test_step)
207
210
  if using_cucumber_messages?
208
211
  test_step.hook?
@@ -210,7 +213,7 @@ module ParallelReportPortal
210
213
  ! test_step.source.last.respond_to?(:keyword)
211
214
  end
212
215
  end
213
-
216
+
214
217
  def status_to_level(status)
215
218
  case status
216
219
  when :passed
@@ -223,8 +226,13 @@ module ParallelReportPortal
223
226
  LOG_LEVELS.fetch(status, LOG_LEVELS[:info])
224
227
  end
225
228
  end
226
-
227
-
229
+
230
+ def parse_report_link_from_response(response)
231
+ if response
232
+ json = JSON.parse(response.body)
233
+ ParallelReportPortal.report_url = json['link'] if json['link']
234
+ end
235
+ end
228
236
  end
229
237
  end
230
238
  end
@@ -2,7 +2,7 @@ require 'logger'
2
2
  require 'tempfile'
3
3
 
4
4
  module ParallelReportPortal
5
- # A collection of methods for communicating with the ReportPortal
5
+ # A collection of methods for communicating with the ReportPortal
6
6
  # REST interface.
7
7
  module HTTP
8
8
 
@@ -10,16 +10,16 @@ module ParallelReportPortal
10
10
  @@logger = Logger.new(STDOUT)
11
11
  @@logger.level = Logger::ERROR
12
12
 
13
- # Construct the Report Portal project URL (as a string) based
13
+ # Construct the Report Portal project URL (as a string) based
14
14
  # on the config settings.
15
- #
15
+ #
16
16
  # @return [String] URL the report portal base URL
17
17
  def url
18
18
  "#{ParallelReportPortal.configuration.endpoint}/#{ParallelReportPortal.configuration.project}"
19
19
  end
20
20
 
21
21
  # Helper method for constructing the +Bearer+ header
22
- #
22
+ #
23
23
  # @return [String] header the bearer header value
24
24
  def authorization_header
25
25
  "Bearer #{ParallelReportPortal.configuration.uuid}"
@@ -28,7 +28,7 @@ module ParallelReportPortal
28
28
  # Get a preconstructed Faraday HTTP connection
29
29
  # which has the endpont and headers ready populated.
30
30
  # This object is memoized.
31
- #
31
+ #
32
32
  # @return [Faraday::Connection] connection the HTTP connection object
33
33
  def http_connection
34
34
  @http_connection ||= Faraday.new(
@@ -49,7 +49,7 @@ module ParallelReportPortal
49
49
  # Get a preconstructed Faraday HTTP multipart connection
50
50
  # which has the endpont and headers ready populated.
51
51
  # This object is memoized.
52
- #
52
+ #
53
53
  # @return [Faraday::Connection] connection the HTTP connection object
54
54
  def http_multipart_connection
55
55
  @http_multipart_connection ||= Faraday.new(
@@ -74,10 +74,10 @@ module ParallelReportPortal
74
74
  def req_launch_started(time)
75
75
  resp = http_connection.post('launch') do |req|
76
76
  req.body = {
77
- name: ParallelReportPortal.configuration.launch,
78
- start_time: time,
79
- tags: ParallelReportPortal.configuration.tags,
80
- description: ParallelReportPortal.configuration.description,
77
+ name: ParallelReportPortal.configuration.launch,
78
+ start_time: time,
79
+ tags: ParallelReportPortal.configuration.tags,
80
+ description: ParallelReportPortal.configuration.description,
81
81
  mode: (ParallelReportPortal.configuration.debug ? 'DEBUG' : 'DEFAULT' ),
82
82
  attributes: ParallelReportPortal.configuration.attributes
83
83
  }.to_json
@@ -88,7 +88,7 @@ module ParallelReportPortal
88
88
  @@logger.error("Launch failed with response code #{resp.status} -- message #{resp.body}")
89
89
  end
90
90
  end
91
-
91
+
92
92
  # Send a request to Report Portal to finish a launch.
93
93
  # It will bubble up any Faraday connection exceptions.
94
94
  def req_launch_finished(launch_id, time)
@@ -96,10 +96,10 @@ module ParallelReportPortal
96
96
  req.body = { end_time: time }.to_json
97
97
  end
98
98
  end
99
-
99
+
100
100
  # Send a request to ReportPortal to start a feature.
101
101
  # It will bubble up any Faraday connection exceptions.
102
- #
102
+ #
103
103
  # @return [String] id the UUID of the feature
104
104
  def req_feature_started(launch_id, parent_id, feature, time)
105
105
  description = if feature.description
@@ -116,9 +116,9 @@ module ParallelReportPortal
116
116
  description,
117
117
  time )
118
118
  end
119
-
119
+
120
120
  # Sends a request to Report Portal to add an item into its hierarchy.
121
- #
121
+ #
122
122
  # @return [String] uuid the UUID of the newly created child
123
123
  def req_hierarchy(launch_id, name, parent, type, tags, description, time )
124
124
  resource = 'item'
@@ -134,23 +134,23 @@ module ParallelReportPortal
134
134
  attributes: tags
135
135
  }.to_json
136
136
  end
137
-
137
+
138
138
  if resp.success?
139
139
  JSON.parse(resp.body)['id']
140
140
  else
141
141
  @@logger.warn("Starting a heirarchy failed with response code #{resp.status} -- message #{resp.body}")
142
142
  end
143
143
  end
144
-
144
+
145
145
  # Send a request to Report Portal that a feature has completed.
146
146
  def req_feature_finished(feature_id, time)
147
147
  ParallelReportPortal.http_connection.put("item/#{feature_id}") do |req|
148
148
  req.body = { end_time: time }.to_json
149
149
  end
150
150
  end
151
-
151
+
152
152
  # Send a request to ReportPortal to start a test case.
153
- #
153
+ #
154
154
  # @return [String] uuid the UUID of the test case
155
155
  def req_test_case_started(launch_id, feature_id, test_case, time)
156
156
  resp = ParallelReportPortal.http_connection.post("item/#{feature_id}") do |req|
@@ -176,7 +176,7 @@ module ParallelReportPortal
176
176
  @@logger.warn("Starting a test case failed with response code #{resp.status} -- message #{resp.body}")
177
177
  end
178
178
  end
179
-
179
+
180
180
  # Request that the test case be finished
181
181
  def req_test_case_finished(test_case_id, status, time)
182
182
  resp = ParallelReportPortal.http_connection.put("item/#{test_case_id}") do |req|
@@ -186,8 +186,8 @@ module ParallelReportPortal
186
186
  }.to_json
187
187
  end
188
188
  end
189
-
190
-
189
+
190
+
191
191
  # Request that Report Portal records a log record
192
192
  def req_log(test_case_id, detail, level, time)
193
193
  resp = ParallelReportPortal.http_connection.post('log') do |req|
@@ -202,19 +202,26 @@ module ParallelReportPortal
202
202
 
203
203
 
204
204
  # Request that Report Portal attach a file to the test case.
205
- #
205
+ #
206
206
  # @param status [String] the status level of the log, e.g. info, warn
207
207
  # @param path [String] the fully qualified path of the file to attach
208
208
  # @param label [String] a label to add to the attachment, defaults to the filename
209
209
  # @param time [Integer] the time in milliseconds for the attachment
210
210
  # @param mime_type [String] the mimetype of the attachment
211
- def send_file(status, path, label = nil, time = ParallelReportPortal.clock, mime_type = 'image/png')
211
+ def send_file(
212
+ status,
213
+ path,
214
+ label = nil,
215
+ time = ParallelReportPortal.clock,
216
+ mime_type = 'image/png',
217
+ scenario_id = nil
218
+ )
212
219
  File.open(File.realpath(path), 'rb') do |file|
213
220
  label ||= File.basename(file)
214
221
 
215
- # where did @test_case_id come from? ok, I know where it came from but this
222
+ # where did @test_case_id come from? ok, I know where it came from but this
216
223
  # really should be factored out of here and state handled better
217
- json = { level: status, message: label, item_id: @test_case_id, time: time, file: { name: File.basename(file) } }
224
+ json = { level: status, message: label, item_id: scenario_id || @test_case_id, time: time, file: { name: File.basename(file) } }
218
225
 
219
226
  json_file = Tempfile.new
220
227
  json_file << [json].to_json
@@ -1,3 +1,3 @@
1
1
  module ParallelReportPortal
2
- VERSION = "2.1.1"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -1,3 +1,4 @@
1
+ require 'parallel_report_portal/after_launch'
1
2
  require "parallel_report_portal/clock"
2
3
  require "parallel_report_portal/configuration"
3
4
  require "parallel_report_portal/file_utils"
@@ -8,19 +9,20 @@ require 'parallel_tests'
8
9
  module ParallelReportPortal
9
10
  class Error < StandardError; end
10
11
 
12
+ extend ParallelReportPortal::AfterLaunch
11
13
  extend ParallelReportPortal::HTTP
12
14
  extend ParallelReportPortal::FileUtils
13
15
  extend ParallelReportPortal::Clock
14
16
 
15
17
  # Returns the configuration object, initializing it if necessary.
16
- #
18
+ #
17
19
  # @return [Configuration] the configuration object
18
20
  def self.configuration
19
21
  @configuration ||= Configuration.new
20
22
  end
21
23
 
22
24
  # Configures the Report Portal environment.
23
- #
25
+ #
24
26
  # @yieldparam [Configuration] config the configuration object yielded to the block
25
27
  def self.configure(&block)
26
28
  yield configuration
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_report_portal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nigel Brookes-Thomas
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-03-01 00:00:00.000000000 Z
12
+ date: 2023-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: appraisal
@@ -205,6 +205,7 @@ files:
205
205
  - gemfiles/cucumber_6.0.gemfile
206
206
  - lib/parallel_report_portal.rb
207
207
  - lib/parallel_report_portal/.DS_Store
208
+ - lib/parallel_report_portal/after_launch.rb
208
209
  - lib/parallel_report_portal/clock.rb
209
210
  - lib/parallel_report_portal/configuration.rb
210
211
  - lib/parallel_report_portal/cucumber/formatter.rb
@@ -234,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
235
  - !ruby/object:Gem::Version
235
236
  version: '0'
236
237
  requirements: []
237
- rubygems_version: 3.2.3
238
+ rubygems_version: 3.3.7
238
239
  signing_key:
239
240
  specification_version: 4
240
241
  summary: Run Cucumber Tests in parallel and with Cucumber 3 and 4+