allure-ruby-commons 2.13.1 → 2.14.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 +4 -4
- data/README.md +40 -7
- data/lib/allure-ruby-commons.rb +172 -133
- data/lib/allure_ruby_commons/allure_lifecycle.rb +43 -46
- data/lib/allure_ruby_commons/config.rb +33 -16
- data/lib/allure_ruby_commons/file_writer.rb +36 -3
- data/lib/allure_ruby_commons/model/{jsonable.rb → 01_jsonable.rb} +14 -6
- data/lib/allure_ruby_commons/model/attachment.rb +2 -2
- data/lib/allure_ruby_commons/model/category.rb +19 -0
- data/lib/allure_ruby_commons/model/executable_item.rb +13 -6
- data/lib/allure_ruby_commons/model/label.rb +2 -2
- data/lib/allure_ruby_commons/model/link.rb +2 -2
- data/lib/allure_ruby_commons/model/parameter.rb +2 -2
- data/lib/allure_ruby_commons/model/status.rb +1 -0
- data/lib/allure_ruby_commons/model/status_details.rb +2 -0
- data/lib/allure_ruby_commons/model/test_result.rb +22 -2
- data/lib/allure_ruby_commons/model/test_result_container.rb +2 -1
- data/lib/allure_ruby_commons/result_utils.rb +37 -22
- data/lib/allure_ruby_commons/step_annotation.rb +39 -0
- data/lib/allure_ruby_commons/testplan.rb +35 -0
- metadata +45 -24
@@ -1,26 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "logger"
|
4
|
+
require "singleton"
|
4
5
|
|
5
6
|
module Allure
|
6
7
|
# Allure configuration class
|
7
8
|
class Config
|
8
|
-
|
9
|
-
|
10
|
-
# @return [String]
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
# @return [Array<String>] valid log levels
|
12
|
+
LOGLEVELS = %w[DEBUG INFO WARN ERROR FATAL UNKNOWN].freeze
|
13
|
+
|
14
|
+
attr_writer :environment, :logger
|
15
|
+
|
16
|
+
attr_accessor :results_directory,
|
17
|
+
:logging_level,
|
18
|
+
:link_tms_pattern,
|
19
|
+
:link_issue_pattern,
|
20
|
+
:clean_results_directory
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@results_directory = "reports/allure-results"
|
24
|
+
@logging_level = LOGLEVELS.index(ENV.fetch("ALLURE_LOG_LEVEL", "INFO")) || Logger::INFO
|
25
|
+
end
|
26
|
+
|
27
|
+
# Allure environment
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
def environment
|
31
|
+
return(@environment) if defined?(@environment)
|
32
|
+
|
33
|
+
@environment ||= ENV["ALLURE_ENVIRONMENT"]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Logger instance
|
37
|
+
#
|
38
|
+
# @return [Logger]
|
39
|
+
def logger
|
40
|
+
@logger ||= Logger.new($stdout, level: logging_level)
|
24
41
|
end
|
25
42
|
end
|
26
43
|
end
|
@@ -9,19 +9,30 @@ module Allure
|
|
9
9
|
TEST_RESULT_CONTAINER_SUFFIX = "-container.json"
|
10
10
|
# @return [String] attachment file suffix
|
11
11
|
ATTACHMENT_FILE_SUFFIX = "-attachment"
|
12
|
+
# @return [String] environment info file
|
13
|
+
ENVIRONMENT_FILE = "environment.properties"
|
14
|
+
# @return [String] categories definition json
|
15
|
+
CATEGORIES_FILE = "categories.json"
|
16
|
+
|
17
|
+
# File writer instance
|
18
|
+
#
|
19
|
+
# @param [String] results_directory
|
20
|
+
def initialize(results_directory)
|
21
|
+
@results_directory = results_directory
|
22
|
+
end
|
12
23
|
|
13
24
|
# Write test result
|
14
25
|
# @param [Allure::TestResult] test_result
|
15
26
|
# @return [void]
|
16
27
|
def write_test_result(test_result)
|
17
|
-
write("#{test_result.uuid}#{TEST_RESULT_SUFFIX}", test_result
|
28
|
+
write("#{test_result.uuid}#{TEST_RESULT_SUFFIX}", Oj.dump(test_result))
|
18
29
|
end
|
19
30
|
|
20
31
|
# Write test result container
|
21
32
|
# @param [Allure::TestResultContainer] test_container_result
|
22
33
|
# @return [void]
|
23
34
|
def write_test_result_container(test_container_result)
|
24
|
-
write("#{test_container_result.uuid}#{TEST_RESULT_CONTAINER_SUFFIX}", test_container_result
|
35
|
+
write("#{test_container_result.uuid}#{TEST_RESULT_CONTAINER_SUFFIX}", Oj.dump(test_container_result))
|
25
36
|
end
|
26
37
|
|
27
38
|
# Write allure attachment file
|
@@ -32,10 +43,32 @@ module Allure
|
|
32
43
|
source.is_a?(File) ? copy(source.path, attachment.source) : write(attachment.source, source)
|
33
44
|
end
|
34
45
|
|
46
|
+
# Write allure report environment info
|
47
|
+
# @param [Hash<Symbol, String>] environment
|
48
|
+
# @return [void]
|
49
|
+
def write_environment(environment)
|
50
|
+
environment.reduce("") { |e, (k, v)| e + "#{k}=#{v}\n" }.tap do |env|
|
51
|
+
write(ENVIRONMENT_FILE, env)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Write categories info
|
56
|
+
# @param [File, Array<Allure::Category>] categories
|
57
|
+
# @return [void]
|
58
|
+
def write_categories(categories)
|
59
|
+
if categories.is_a?(File)
|
60
|
+
copy(categories.path, CATEGORIES_FILE)
|
61
|
+
else
|
62
|
+
write(CATEGORIES_FILE, Oj.dump(categories))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
35
66
|
private
|
36
67
|
|
68
|
+
attr_reader :results_directory
|
69
|
+
|
37
70
|
def output_dir
|
38
|
-
@output_dir ||= FileUtils.mkpath(
|
71
|
+
@output_dir ||= FileUtils.mkpath(results_directory).first
|
39
72
|
end
|
40
73
|
|
41
74
|
def write(name, source)
|
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "oj"
|
4
4
|
|
5
5
|
module Allure
|
6
6
|
# General jsonable object implementation
|
7
7
|
class JSONable
|
8
|
-
|
8
|
+
Oj.default_options = { mode: :custom, use_to_hash: true, ascii_only: true }
|
9
|
+
|
10
|
+
# Return object hash represantation
|
11
|
+
# @return [Hash]
|
12
|
+
def to_hash
|
9
13
|
instance_variables.each_with_object({}) do |var, map|
|
10
14
|
key = camelcase(var.to_s.delete_prefix("@"))
|
11
15
|
value = instance_variable_get(var)
|
@@ -13,22 +17,26 @@ module Allure
|
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
# Object comparator
|
21
|
+
# @param [JSONable] other
|
22
|
+
# @return [Booelan]
|
20
23
|
def ==(other)
|
21
24
|
self.class == other.class && state == other.state
|
22
25
|
end
|
23
26
|
|
24
27
|
protected
|
25
28
|
|
29
|
+
# Object state
|
30
|
+
# @return [Array]
|
26
31
|
def state
|
27
32
|
instance_variables.map { |var| instance_variable_get(var) }
|
28
33
|
end
|
29
34
|
|
30
35
|
private
|
31
36
|
|
37
|
+
# Covert string to camelcase
|
38
|
+
# @param [String] str
|
39
|
+
# @return [String]
|
32
40
|
def camelcase(str)
|
33
41
|
str = str.gsub(/(?:_+)([a-z])/) { Regexp.last_match(1).upcase }
|
34
42
|
str.gsub(/(\A|\s)([A-Z])/) { Regexp.last_match(1) + Regexp.last_match(2).downcase }
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "jsonable"
|
4
|
-
|
5
3
|
module Allure
|
6
4
|
# Allure model attachment object
|
7
5
|
class Attachment < JSONable
|
@@ -9,6 +7,8 @@ module Allure
|
|
9
7
|
# @param [String] type attachment type, {Allure::ContentType}
|
10
8
|
# @param [String] source attachment file name
|
11
9
|
def initialize(name:, type:, source:)
|
10
|
+
super()
|
11
|
+
|
12
12
|
@name = name
|
13
13
|
@type = type
|
14
14
|
@source = source
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
# Defects category
|
5
|
+
class Category < JSONable
|
6
|
+
# @param [String] name
|
7
|
+
# @param [Array<Allure::Status>] matched_statuses
|
8
|
+
# @param [String, Regexp] message_regex
|
9
|
+
# @param [String, Regexp] trace_regex
|
10
|
+
def initialize(name:, matched_statuses: nil, message_regex: nil, trace_regex: nil)
|
11
|
+
super()
|
12
|
+
|
13
|
+
@name = name
|
14
|
+
@matched_statuses = matched_statuses
|
15
|
+
@message_regex = message_regex
|
16
|
+
@trace_regex = trace_regex
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "jsonable"
|
4
|
-
|
5
3
|
module Allure
|
6
4
|
# Allure model executable item
|
7
5
|
class ExecutableItem < JSONable
|
@@ -16,6 +14,8 @@ module Allure
|
|
16
14
|
# @option options [Array<Allure::Attachment>] :attachments ([])
|
17
15
|
# @option options [Array<Allure::Parameter>] :parameters ([])
|
18
16
|
def initialize(**options)
|
17
|
+
super()
|
18
|
+
|
19
19
|
@name = options[:name]
|
20
20
|
@description = options[:description]
|
21
21
|
@description_html = options[:description_html]
|
@@ -27,9 +27,16 @@ module Allure
|
|
27
27
|
@parameters = options[:parameters] || []
|
28
28
|
end
|
29
29
|
|
30
|
-
attr_accessor
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
attr_accessor :name,
|
31
|
+
:status,
|
32
|
+
:status_details,
|
33
|
+
:stage,
|
34
|
+
:description,
|
35
|
+
:description_html,
|
36
|
+
:steps,
|
37
|
+
:attachments,
|
38
|
+
:parameters,
|
39
|
+
:start,
|
40
|
+
:stop
|
34
41
|
end
|
35
42
|
end
|
@@ -5,6 +5,7 @@ module Allure
|
|
5
5
|
class TestResult < ExecutableItem
|
6
6
|
# @param [String] uuid
|
7
7
|
# @param [String] history_id
|
8
|
+
# @param [String] environment
|
8
9
|
# @param [Hash] options
|
9
10
|
# @option options [String] :name
|
10
11
|
# @option options [String] :full_name
|
@@ -18,8 +19,10 @@ module Allure
|
|
18
19
|
# @option options [Array<Allure::Link>] :links ([])
|
19
20
|
# @option options [Array<Allure::Attachment>] :attachments ([])
|
20
21
|
# @option options [Array<Allure::Parameter>] :parameters ([])
|
21
|
-
def initialize(uuid: UUID.generate, history_id: UUID.generate, **options)
|
22
|
+
def initialize(uuid: UUID.generate, history_id: UUID.generate, environment: nil, **options)
|
22
23
|
super
|
24
|
+
|
25
|
+
@name = test_name(options[:name], environment)
|
23
26
|
@uuid = uuid
|
24
27
|
@history_id = history_id
|
25
28
|
@full_name = options[:full_name] || "Unnamed"
|
@@ -27,6 +30,23 @@ module Allure
|
|
27
30
|
@links = options[:links] || []
|
28
31
|
end
|
29
32
|
|
30
|
-
attr_accessor :uuid,
|
33
|
+
attr_accessor :uuid,
|
34
|
+
:history_id,
|
35
|
+
:full_name,
|
36
|
+
:labels,
|
37
|
+
:links
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Test name prefixed with allure environment
|
42
|
+
#
|
43
|
+
# @param [String] name
|
44
|
+
# @param [String] environment
|
45
|
+
# @return [String]
|
46
|
+
def test_name(name, environment)
|
47
|
+
return name unless environment
|
48
|
+
|
49
|
+
"#{environment}: #{name}"
|
50
|
+
end
|
31
51
|
end
|
32
52
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "jsonable"
|
4
3
|
module Allure
|
5
4
|
# Allure model step result container
|
6
5
|
class TestResultContainer < JSONable
|
7
6
|
def initialize(uuid: UUID.generate, name: "Unnamed")
|
7
|
+
super()
|
8
|
+
|
8
9
|
@uuid = uuid
|
9
10
|
@name = name
|
10
11
|
@children = []
|
@@ -46,14 +46,26 @@ module Allure
|
|
46
46
|
Label.new(HOST_LABEL_NAME, Socket.gethostname)
|
47
47
|
end
|
48
48
|
|
49
|
+
# Language label
|
50
|
+
# @return [Allure::Label]
|
49
51
|
def language_label
|
50
52
|
Label.new(LANGUAGE_LABEL_NAME, "ruby")
|
51
53
|
end
|
52
54
|
|
55
|
+
# Framework label
|
56
|
+
# @param [String] value
|
57
|
+
# @return [Allure::Label]
|
53
58
|
def framework_label(value)
|
54
59
|
Label.new(FRAMEWORK_LABEL_NAME, value)
|
55
60
|
end
|
56
61
|
|
62
|
+
# Epic label
|
63
|
+
# @param [String] value
|
64
|
+
# @return [Allure::Label]
|
65
|
+
def epic_label(value)
|
66
|
+
Label.new(EPIC_LABEL_NAME, value)
|
67
|
+
end
|
68
|
+
|
57
69
|
# Feature label
|
58
70
|
# @param [String] value
|
59
71
|
# @return [Allure::Label]
|
@@ -61,6 +73,13 @@ module Allure
|
|
61
73
|
Label.new(FEATURE_LABEL_NAME, value)
|
62
74
|
end
|
63
75
|
|
76
|
+
# Story label
|
77
|
+
# @param [String] value
|
78
|
+
# @return [Allure::Label]
|
79
|
+
def story_label(value)
|
80
|
+
Label.new(STORY_LABEL_NAME, value)
|
81
|
+
end
|
82
|
+
|
64
83
|
# Package label
|
65
84
|
# @param [String] value
|
66
85
|
# @return [Allure::Label]
|
@@ -89,13 +108,6 @@ module Allure
|
|
89
108
|
Label.new(SUB_SUITE_LABEL_NAME, value)
|
90
109
|
end
|
91
110
|
|
92
|
-
# Story label
|
93
|
-
# @param [String] value
|
94
|
-
# @return [Allure::Label]
|
95
|
-
def story_label(value)
|
96
|
-
Label.new(STORY_LABEL_NAME, value)
|
97
|
-
end
|
98
|
-
|
99
111
|
# Test case label
|
100
112
|
# @param [String] value
|
101
113
|
# @return [Allure::Label]
|
@@ -119,23 +131,25 @@ module Allure
|
|
119
131
|
|
120
132
|
# TMS link
|
121
133
|
# @param [String] value
|
134
|
+
# @param [String] link_pattern
|
122
135
|
# @return [Allure::Link]
|
123
|
-
def tms_link(value)
|
124
|
-
Link.new(TMS_LINK_TYPE, value,
|
136
|
+
def tms_link(value, link_pattern)
|
137
|
+
Link.new(TMS_LINK_TYPE, value, url(value, link_pattern))
|
125
138
|
end
|
126
139
|
|
127
140
|
# Issue link
|
128
141
|
# @param [String] value
|
142
|
+
# @param [String] link_pattern
|
129
143
|
# @return [Allure::Link]
|
130
|
-
def issue_link(value)
|
131
|
-
Link.new(ISSUE_LINK_TYPE, value,
|
144
|
+
def issue_link(value, link_pattern)
|
145
|
+
Link.new(ISSUE_LINK_TYPE, value, url(value, link_pattern))
|
132
146
|
end
|
133
147
|
|
134
148
|
# Get status based on exception type
|
135
149
|
# @param [Exception] exception
|
136
150
|
# @return [Symbol]
|
137
151
|
def status(exception)
|
138
|
-
|
152
|
+
exception.is_a?(RSpec::Expectations::ExpectationNotMetError) ? Status::FAILED : Status::BROKEN
|
139
153
|
end
|
140
154
|
|
141
155
|
# Get exception status detail
|
@@ -145,19 +159,20 @@ module Allure
|
|
145
159
|
StatusDetails.new(message: exception&.message, trace: exception&.backtrace&.join("\n"))
|
146
160
|
end
|
147
161
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
162
|
+
# Allure attachment object
|
163
|
+
# @param [String] name
|
164
|
+
# @param [String] type
|
165
|
+
# @return [Allure::Attachment]
|
166
|
+
def prepare_attachment(name, type)
|
167
|
+
extension = ContentType.to_extension(type) || return
|
168
|
+
file_name = "#{UUID.generate}-attachment.#{extension}"
|
169
|
+
Attachment.new(name: name, source: file_name, type: type)
|
152
170
|
end
|
153
171
|
|
154
|
-
|
155
|
-
Allure.configuration.link_issue_pattern.sub("{}", value)
|
156
|
-
end
|
172
|
+
private
|
157
173
|
|
158
|
-
def
|
159
|
-
|
160
|
-
exception.instance_of?(RSpec::Expectations::MultipleExpectationsNotMetError)
|
174
|
+
def url(value, link_pattern)
|
175
|
+
link_pattern.sub("{}", value)
|
161
176
|
end
|
162
177
|
end
|
163
178
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Adds support for annotating methods as allure steps
|
4
|
+
#
|
5
|
+
module AllureStepAnnotation
|
6
|
+
# Mark method definition as allure step
|
7
|
+
#
|
8
|
+
# @param [String] step_name
|
9
|
+
# @return [void]
|
10
|
+
def step(step_name = "")
|
11
|
+
@allure_step = step_name
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def singleton_method_added(method_name)
|
17
|
+
return super unless @allure_step
|
18
|
+
|
19
|
+
original_method = singleton_method(method_name)
|
20
|
+
step_name = @allure_step.empty? ? method_name.to_s : @allure_step
|
21
|
+
@allure_step = nil
|
22
|
+
|
23
|
+
define_singleton_method(method_name) do |*args, &block|
|
24
|
+
Allure.run_step(step_name) { original_method.call(*args, &block) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_added(method_name)
|
29
|
+
return super unless @allure_step
|
30
|
+
|
31
|
+
original_method = instance_method(method_name)
|
32
|
+
step_name = @allure_step.empty? ? method_name.to_s : @allure_step
|
33
|
+
@allure_step = nil
|
34
|
+
|
35
|
+
define_method(method_name) do |*args, &block|
|
36
|
+
Allure.run_step(step_name) { original_method.bind(self).call(*args, &block) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Allure
|
4
|
+
class TestPlan
|
5
|
+
# @return [String] test plan path env var name
|
6
|
+
TESTPLAN_PATH = "ALLURE_TESTPLAN_PATH"
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Allure id's of executable tests
|
10
|
+
#
|
11
|
+
# @return [Array]
|
12
|
+
def test_ids
|
13
|
+
@test_ids ||= tests&.map { |test| test[:id] }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Test names of executable tests
|
17
|
+
#
|
18
|
+
# @return [Array]
|
19
|
+
def test_names
|
20
|
+
@test_names ||= tests&.map { |test| test[:selector] }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Tests to execute from allure testplan.json
|
26
|
+
#
|
27
|
+
# @return [Array<Hash>]
|
28
|
+
def tests
|
29
|
+
@tests ||= Oj.load_file(ENV[TESTPLAN_PATH], symbol_keys: true)&.fetch(:tests) if ENV[TESTPLAN_PATH]
|
30
|
+
rescue Oj::ParseError
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|