parallel_report_portal 2.1.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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+