allure-ruby-adaptor-api 0.6.1
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 +7 -0
- data/.gitignore +14 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +42 -0
- data/README.md +44 -0
- data/allure-model-1.4.0.xsd +171 -0
- data/allure-ruby-adaptor-api.gemspec +28 -0
- data/lib/allure-ruby-adaptor-api.rb +23 -0
- data/lib/allure-ruby-adaptor-api/builder.rb +214 -0
- data/lib/allure-ruby-adaptor-api/dsl.rb +34 -0
- data/lib/allure-ruby-adaptor-api/version.rb +6 -0
- data/spec/extend_steps_spec.rb +27 -0
- data/spec/spec_helper.rb +6 -0
- metadata +141 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c36d33cd9e67daea76968933c33b97e647971470
|
4
|
+
data.tar.gz: 1be5d5c73d591282e08af3eeee25caef6f8341d8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a8a529ca1dfe5631a996e6b4ed4b9baeb3430e1e25911992247a85cf1ce402b8b885628e169b2e9f6238eec46704070ec8f0ebb2f09f2996b8dc01a0d4aea38b
|
7
|
+
data.tar.gz: 5f33469200b1a6d2a12a5cc521c49aa172f1fdca74cba720d556231e291237f59defbc77856ceefb4ed598911920f6ae0bf839984361221c18bb1dafb012fbaf
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
allure-ruby-adaptor-api (0.6.1)
|
5
|
+
mimemagic
|
6
|
+
nokogiri (~> 1.6.0)
|
7
|
+
rspec (~> 2.14.0)
|
8
|
+
uuid
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
diff-lcs (1.2.5)
|
14
|
+
macaddr (1.7.1)
|
15
|
+
systemu (~> 2.6.2)
|
16
|
+
mimemagic (0.2.1)
|
17
|
+
mini_portile (0.6.0)
|
18
|
+
nokogiri (1.6.3.1)
|
19
|
+
mini_portile (= 0.6.0)
|
20
|
+
rake (10.3.2)
|
21
|
+
rspec (2.14.1)
|
22
|
+
rspec-core (~> 2.14.0)
|
23
|
+
rspec-expectations (~> 2.14.0)
|
24
|
+
rspec-mocks (~> 2.14.0)
|
25
|
+
rspec-core (2.14.8)
|
26
|
+
rspec-expectations (2.14.5)
|
27
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
28
|
+
rspec-mocks (2.14.6)
|
29
|
+
systemu (2.6.4)
|
30
|
+
uuid (2.3.7)
|
31
|
+
macaddr (~> 1.0)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
ruby
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
allure-ruby-adaptor-api!
|
38
|
+
bundler
|
39
|
+
mimemagic
|
40
|
+
nokogiri (~> 1.6.0)
|
41
|
+
rake
|
42
|
+
rspec (~> 2.14.0)
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Allure Ruby API
|
2
|
+
|
3
|
+
This is a helper library containing the basics for any ruby-based Allure adaptor.
|
4
|
+
Using it you can easily implement the adaptor for your favourite ruby testing library or
|
5
|
+
you can just create the report of any other kind using the basic Allure terms.
|
6
|
+
|
7
|
+
## Setup
|
8
|
+
|
9
|
+
Add the dependency to your Gemfile
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'allure-ruby-api'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Advanced options
|
16
|
+
|
17
|
+
You can specify the directory where the Allure test results will appear. By default it would be 'allure/data' within
|
18
|
+
your current directory.
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
AllureRubyAdaptorApi.configure do |c|
|
22
|
+
c.output_dir = "/whatever/you/like"
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
## Usage examples
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
AllureRubyAdaptorApi::Builder.start_suite "some_suite", :severity => :normal
|
30
|
+
AllureRubyAdaptorApi::Builder.start_test "some_suite", "some_test", :feature => "Some feature", :severity => :critical
|
31
|
+
AllureRubyAdaptorApi::Builder.start_step "some_suite", "some_test", "first step"
|
32
|
+
AllureRubyAdaptorApi::Builder.add_attachment "some_suite", "some_test", :file => Tempfile.new("somefile")
|
33
|
+
AllureRubyAdaptorApi::Builder.stop_step "some_suite", "some_test", "first step"
|
34
|
+
AllureRubyAdaptorApi::Builder.start_step "some_suite", "some_test", "second step"
|
35
|
+
AllureRubyAdaptorApi::Builder.add_attachment "some_suite", "some_test", :step => "second step", :file => Tempfile.new("somefile")
|
36
|
+
AllureRubyAdaptorApi::Builder.stop_step "some_suite", "some_test", "second step"
|
37
|
+
AllureRubyAdaptorApi::Builder.start_step "some_suite", "some_test", "third step"
|
38
|
+
AllureRubyAdaptorApi::Builder.stop_step "some_suite", "some_test", "third step", :failed
|
39
|
+
AllureRubyAdaptorApi::Builder.stop_test "some_suite", "some_test", :status => :broken, :exception => Exception.new("some error")
|
40
|
+
AllureRubyAdaptorApi::Builder.stop_suite "some_suite"
|
41
|
+
|
42
|
+
# This will generate the results within your output directory
|
43
|
+
AllureRubyAdaptorApi::Builder.build!
|
44
|
+
```
|
@@ -0,0 +1,171 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
|
3
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
4
|
+
xmlns:qa="urn:model.allure.qatools.yandex.ru"
|
5
|
+
targetNamespace="urn:model.allure.qatools.yandex.ru">
|
6
|
+
|
7
|
+
<xs:element name="test-suite" type="qa:test-suite-result"/>
|
8
|
+
|
9
|
+
<xs:complexType name="test-suite-result">
|
10
|
+
<xs:all>
|
11
|
+
<xs:element name="name" type="xs:string"/>
|
12
|
+
<xs:element name="title" type="xs:string" minOccurs="0"/>
|
13
|
+
<xs:element name="description" type="qa:description" minOccurs="0"/>
|
14
|
+
<xs:element name="test-cases" type="qa:test-cases-result" minOccurs="0"/>
|
15
|
+
<xs:element name="labels" type="qa:labels" minOccurs="0"/>
|
16
|
+
</xs:all>
|
17
|
+
<xs:attribute name="start" type="xs:long" use="required"/>
|
18
|
+
<xs:attribute name="stop" type="xs:long" use="required"/>
|
19
|
+
<xs:attribute name="version" type="xs:string"/>
|
20
|
+
</xs:complexType>
|
21
|
+
|
22
|
+
<xs:complexType name="test-cases-result">
|
23
|
+
<xs:sequence>
|
24
|
+
<xs:element name="test-case" type="qa:test-case-result" maxOccurs="unbounded" minOccurs="0"/>
|
25
|
+
</xs:sequence>
|
26
|
+
</xs:complexType>
|
27
|
+
|
28
|
+
<xs:complexType name="test-case-result">
|
29
|
+
<xs:all>
|
30
|
+
<xs:element name="name" type="xs:string"/>
|
31
|
+
<xs:element name="title" type="xs:string" minOccurs="0"/>
|
32
|
+
<xs:element name="description" type="qa:description" minOccurs="0"/>
|
33
|
+
<xs:element name="failure" type="qa:failure" minOccurs="0"/>
|
34
|
+
<xs:element name="steps" type="qa:steps" minOccurs="0"/>
|
35
|
+
<xs:element name="attachments" type="qa:attachments" minOccurs="0"/>
|
36
|
+
<xs:element name="labels" type="qa:labels" minOccurs="0"/>
|
37
|
+
<xs:element name="parameters" type="qa:parameters" minOccurs="0"/>
|
38
|
+
</xs:all>
|
39
|
+
<xs:attribute name="start" type="xs:long" use="required"/>
|
40
|
+
<xs:attribute name="stop" type="xs:long" use="required"/>
|
41
|
+
<xs:attribute name="status" type="qa:status" use="required"/>
|
42
|
+
</xs:complexType>
|
43
|
+
|
44
|
+
<xs:complexType name="steps">
|
45
|
+
<xs:sequence>
|
46
|
+
<xs:element name="step" type="qa:step" minOccurs="0" maxOccurs="unbounded"/>
|
47
|
+
</xs:sequence>
|
48
|
+
</xs:complexType>
|
49
|
+
|
50
|
+
<xs:complexType name="step">
|
51
|
+
<xs:all>
|
52
|
+
<xs:element name="name" type="xs:string"/>
|
53
|
+
<xs:element name="title" type="xs:string" minOccurs="0"/>
|
54
|
+
<xs:element name="attachments" type="qa:attachments" minOccurs="0"/>
|
55
|
+
<xs:element name="steps" type="qa:steps" minOccurs="0"/>
|
56
|
+
</xs:all>
|
57
|
+
<xs:attribute name="start" type="xs:long" use="required"/>
|
58
|
+
<xs:attribute name="stop" type="xs:long" use="required"/>
|
59
|
+
<xs:attribute name="status" type="qa:status" use="required"/>
|
60
|
+
</xs:complexType>
|
61
|
+
|
62
|
+
<xs:complexType name="failure">
|
63
|
+
<xs:all>
|
64
|
+
<xs:element name="message" type="xs:string"/>
|
65
|
+
<xs:element name="stack-trace" type="xs:string" minOccurs="0"/>
|
66
|
+
</xs:all>
|
67
|
+
</xs:complexType>
|
68
|
+
|
69
|
+
<xs:complexType name="labels">
|
70
|
+
<xs:sequence>
|
71
|
+
<xs:element name="label" type="qa:label" minOccurs="0" maxOccurs="unbounded"/>
|
72
|
+
</xs:sequence>
|
73
|
+
</xs:complexType>
|
74
|
+
|
75
|
+
<xs:complexType name="label">
|
76
|
+
<xs:attribute name="name" type="xs:string" use="required"/>
|
77
|
+
<xs:attribute name="value" type="xs:string" use="required"/>
|
78
|
+
</xs:complexType>
|
79
|
+
|
80
|
+
<xs:complexType name="parameters">
|
81
|
+
<xs:sequence>
|
82
|
+
<xs:element name="parameter" type="qa:parameter" minOccurs="0" maxOccurs="unbounded"/>
|
83
|
+
</xs:sequence>
|
84
|
+
</xs:complexType>
|
85
|
+
|
86
|
+
<xs:complexType name="parameter">
|
87
|
+
<xs:attribute name="name" type="xs:string" use="required"/>
|
88
|
+
<xs:attribute name="value" type="xs:string" use="required"/>
|
89
|
+
<xs:attribute name="kind" type="qa:parameter-kind" use="required"/>
|
90
|
+
</xs:complexType>
|
91
|
+
|
92
|
+
<xs:simpleType name="parameter-kind">
|
93
|
+
<xs:restriction base="xs:string">
|
94
|
+
<xs:enumeration value="argument"/>
|
95
|
+
<xs:enumeration value="system-property"/>
|
96
|
+
<xs:enumeration value="environment-variable"/>
|
97
|
+
</xs:restriction>
|
98
|
+
</xs:simpleType>
|
99
|
+
|
100
|
+
<xs:complexType name="attachments">
|
101
|
+
<xs:sequence>
|
102
|
+
<xs:element name="attachment" type="qa:attachment" minOccurs="0" maxOccurs="unbounded"/>
|
103
|
+
</xs:sequence>
|
104
|
+
</xs:complexType>
|
105
|
+
|
106
|
+
<xs:complexType name="attachment">
|
107
|
+
<xs:attribute name="title" type="xs:string" use="required"/>
|
108
|
+
<xs:attribute name="source" type="xs:string" use="required"/>
|
109
|
+
<xs:attribute name="type" type="xs:string" use="required"/>
|
110
|
+
<xs:attribute name="size" type="xs:int"/>
|
111
|
+
</xs:complexType>
|
112
|
+
|
113
|
+
<!--Deprecated, will be removed in 1.4.0-->
|
114
|
+
<xs:simpleType name="attachment-type">
|
115
|
+
<xs:restriction base="xs:string">
|
116
|
+
<xs:enumeration value="txt"/>
|
117
|
+
<xs:enumeration value="html"/>
|
118
|
+
<xs:enumeration value="xml"/>
|
119
|
+
<xs:enumeration value="png"/>
|
120
|
+
<xs:enumeration value="jpg"/>
|
121
|
+
<xs:enumeration value="json"/>
|
122
|
+
<xs:enumeration value="other"/>
|
123
|
+
</xs:restriction>
|
124
|
+
</xs:simpleType>
|
125
|
+
|
126
|
+
<xs:simpleType name="status">
|
127
|
+
<xs:restriction base="xs:string">
|
128
|
+
<xs:enumeration value="failed"/>
|
129
|
+
<xs:enumeration value="broken"/>
|
130
|
+
<xs:enumeration value="passed"/>
|
131
|
+
<xs:enumeration value="canceled"/>
|
132
|
+
<xs:enumeration value="pending"/>
|
133
|
+
</xs:restriction>
|
134
|
+
</xs:simpleType>
|
135
|
+
|
136
|
+
<xs:simpleType name="label-name">
|
137
|
+
<xs:restriction base="xs:string">
|
138
|
+
<xs:enumeration value="feature"/>
|
139
|
+
<xs:enumeration value="story"/>
|
140
|
+
<xs:enumeration value="severity"/>
|
141
|
+
<xs:enumeration value="language"/>
|
142
|
+
<xs:enumeration value="framework"/>
|
143
|
+
</xs:restriction>
|
144
|
+
</xs:simpleType>
|
145
|
+
|
146
|
+
<xs:simpleType name="severity-level">
|
147
|
+
<xs:restriction base="xs:string">
|
148
|
+
<xs:enumeration value="blocker"/>
|
149
|
+
<xs:enumeration value="critical"/>
|
150
|
+
<xs:enumeration value="normal"/>
|
151
|
+
<xs:enumeration value="minor"/>
|
152
|
+
<xs:enumeration value="trivial"/>
|
153
|
+
</xs:restriction>
|
154
|
+
</xs:simpleType>
|
155
|
+
|
156
|
+
<xs:complexType name="description">
|
157
|
+
<xs:simpleContent>
|
158
|
+
<xs:extension base="xs:string">
|
159
|
+
<xs:attribute name="type" type="qa:description-type" default="text"/>
|
160
|
+
</xs:extension>
|
161
|
+
</xs:simpleContent>
|
162
|
+
</xs:complexType>
|
163
|
+
|
164
|
+
<xs:simpleType name="description-type">
|
165
|
+
<xs:restriction base="xs:string">
|
166
|
+
<xs:enumeration value="markdown"/>
|
167
|
+
<xs:enumeration value="text"/>
|
168
|
+
<xs:enumeration value="html"/>
|
169
|
+
</xs:restriction>
|
170
|
+
</xs:simpleType>
|
171
|
+
</xs:schema>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require "allure-ruby-adaptor-api/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'allure-ruby-adaptor-api'
|
7
|
+
s.version = AllureRubyAdaptorApi::Version::STRING
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Ilya Sadykov']
|
10
|
+
s.email = ['smecsia@yandex-team.ru']
|
11
|
+
s.description = %q{This is a helper library containing the basics for any ruby-based Allure adaptor.}
|
12
|
+
s.summary = "allure-ruby-adaptor-api-#{AllureRubyAdaptorApi::Version::STRING}"
|
13
|
+
s.homepage = 'http://allure.qatools.ru'
|
14
|
+
s.license = 'Apache2'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_dependency 'rspec', '~> 2.14.0'
|
22
|
+
s.add_dependency 'nokogiri', '~> 1.6.0'
|
23
|
+
s.add_dependency 'uuid'
|
24
|
+
s.add_dependency 'mimemagic'
|
25
|
+
|
26
|
+
s.add_development_dependency 'bundler'
|
27
|
+
s.add_development_dependency 'rake'
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'allure-ruby-adaptor-api/version'
|
2
|
+
require 'allure-ruby-adaptor-api/builder'
|
3
|
+
|
4
|
+
module AllureRubyAdaptorApi
|
5
|
+
module Config
|
6
|
+
class << self
|
7
|
+
attr_accessor :output_dir
|
8
|
+
|
9
|
+
DEFAULT_OUTPUT_DIR = 'allure/data'
|
10
|
+
|
11
|
+
def output_dir
|
12
|
+
@output_dir || DEFAULT_OUTPUT_DIR
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def configure(&block)
|
19
|
+
yield Config
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'mimemagic'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'uuid'
|
5
|
+
|
6
|
+
module AllureRubyAdaptorApi
|
7
|
+
|
8
|
+
class Builder
|
9
|
+
class << self
|
10
|
+
attr_accessor :suites
|
11
|
+
MUTEX = Mutex.new
|
12
|
+
|
13
|
+
def start_suite(suite, labels = {:severity => :normal})
|
14
|
+
init_suites
|
15
|
+
MUTEX.synchronize do
|
16
|
+
puts "Starting case_or_suite #{suite} with labels #{labels}"
|
17
|
+
self.suites[suite] = {
|
18
|
+
:title => suite,
|
19
|
+
:start => timestamp,
|
20
|
+
:tests => {},
|
21
|
+
:labels => labels
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def start_test(suite, test, labels = {:severity => :normal})
|
27
|
+
MUTEX.synchronize do
|
28
|
+
puts "Starting test #{suite}.#{test} with labels #{labels}"
|
29
|
+
self.suites[suite][:tests][test] = {
|
30
|
+
:title => test,
|
31
|
+
:start => timestamp,
|
32
|
+
:failure => nil,
|
33
|
+
:steps => {},
|
34
|
+
:attachments => [],
|
35
|
+
:labels => labels,
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def stop_test(suite, test, result = {})
|
41
|
+
self.suites[suite][:tests][test][:steps].each do |step_title, step|
|
42
|
+
if step[:stop].nil? || step[:stop] == 0
|
43
|
+
stop_step(suite, test, step_title, result[:status])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
MUTEX.synchronize do
|
47
|
+
puts "Stopping test #{suite}.#{test}"
|
48
|
+
self.suites[suite][:tests][test][:stop] = timestamp(result[:finished_at])
|
49
|
+
self.suites[suite][:tests][test][:start] = timestamp(result[:started_at])
|
50
|
+
self.suites[suite][:tests][test][:status] = result[:status]
|
51
|
+
if (result[:status].to_sym != :passed)
|
52
|
+
self.suites[suite][:tests][test][:failure] = {
|
53
|
+
:stacktrace => ((result[:exception] && result[:exception].backtrace) || []).map { |s| s.to_s }.join("\r\n"),
|
54
|
+
:message => result[:exception].to_s,
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def start_step(suite, test, step)
|
62
|
+
MUTEX.synchronize do
|
63
|
+
puts "Starting step #{suite}.#{test}.#{step}"
|
64
|
+
self.suites[suite][:tests][test][:steps][step] = {
|
65
|
+
:title => step,
|
66
|
+
:start => timestamp,
|
67
|
+
:attachments => []
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_attachment(suite, test, opts = {:step => nil, :file => nil, :mime_type => nil})
|
73
|
+
raise "File cannot be nil!" if opts[:file].nil?
|
74
|
+
step = opts[:step]
|
75
|
+
file = opts[:file]
|
76
|
+
title = opts[:title] || file.basename
|
77
|
+
puts "Adding attachment #{opts[:title]} to #{suite}.#{test}#{step.nil? ? "" : ".#{step}"}"
|
78
|
+
dir = Pathname.new(Dir.pwd).join(config.output_dir)
|
79
|
+
FileUtils.mkdir_p(dir)
|
80
|
+
file_extname = File.extname(file.path.downcase)
|
81
|
+
mime_type = opts[:mime_type] || MimeMagic.by_path(file.path) || "text/plain"
|
82
|
+
attachment = dir.join("#{Digest::SHA256.file(file.path).hexdigest}-attachment#{(file_extname.empty?) ? '' : file_extname}")
|
83
|
+
FileUtils.cp(file.path, attachment)
|
84
|
+
attach = {
|
85
|
+
:type => mime_type,
|
86
|
+
:title => title,
|
87
|
+
:source => attachment.basename,
|
88
|
+
:file => attachment.basename,
|
89
|
+
:target => attachment.basename,
|
90
|
+
:size => File.stat(attachment).size
|
91
|
+
}
|
92
|
+
if step.nil?
|
93
|
+
self.suites[suite][:tests][test][:attachments] << attach
|
94
|
+
else
|
95
|
+
self.suites[suite][:tests][test][:steps][step][:attachments] << attach
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def stop_step(suite, test, step, status = :passed)
|
100
|
+
MUTEX.synchronize do
|
101
|
+
puts "Stopping step #{suite}.#{test}.#{step}"
|
102
|
+
self.suites[suite][:tests][test][:steps][step][:stop] = timestamp
|
103
|
+
self.suites[suite][:tests][test][:steps][step][:status] = status
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def stop_suite(title)
|
108
|
+
init_suites
|
109
|
+
MUTEX.synchronize do
|
110
|
+
puts "Stopping case_or_suite #{title}"
|
111
|
+
self.suites[title][:stop] = timestamp
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def build!(opts = {}, &block)
|
116
|
+
suites_xml = []
|
117
|
+
self.suites.each do |suite_title, suite|
|
118
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
119
|
+
xml.send "ns2:test-suite", :start => suite[:start] || 0, :stop => suite[:stop] || 0, 'xmlns' => '', "xmlns:ns2" => "urn:model.allure.qatools.yandex.ru" do
|
120
|
+
xml.send :name, suite_title
|
121
|
+
xml.send :title, suite_title
|
122
|
+
xml.send "test-cases" do
|
123
|
+
suite[:tests].each do |test_title, test|
|
124
|
+
xml.send "test-case", :start => test[:start] || 0, :stop => test[:stop] || 0, :status => test[:status] do
|
125
|
+
xml.send :name, test_title
|
126
|
+
xml.send :title, test_title
|
127
|
+
unless test[:failure].nil?
|
128
|
+
xml.failure do
|
129
|
+
xml.message test[:failure][:message]
|
130
|
+
xml.send "stack-trace", test[:failure][:stacktrace]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
xml.steps do
|
134
|
+
test[:steps].each do |step_title, step_obj|
|
135
|
+
xml.step(:start => step_obj[:start] || 0, :stop => step_obj[:stop] || 0, :status => step_obj[:status]) do
|
136
|
+
xml.send :name, step_title
|
137
|
+
xml.send :title, step_title
|
138
|
+
xml_attachments(xml, step_obj[:attachments])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
xml_attachments(xml, test[:attachments])
|
143
|
+
xml_labels(xml, suite[:labels].merge(test[:labels]))
|
144
|
+
xml.parameters
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
xml_labels(xml, suite[:labels])
|
149
|
+
end
|
150
|
+
end
|
151
|
+
xml = builder.to_xml
|
152
|
+
xml = yield suite, xml if block_given?
|
153
|
+
dir = Pathname.new(config.output_dir)
|
154
|
+
FileUtils.mkdir_p(dir)
|
155
|
+
out_file = dir.join("#{UUID.new.generate}-testsuite.xml")
|
156
|
+
File.open(out_file, 'w+') do |file|
|
157
|
+
file.write(validate_xml(xml))
|
158
|
+
end
|
159
|
+
suites_xml << xml
|
160
|
+
end
|
161
|
+
suites_xml
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def config
|
167
|
+
AllureRubyAdaptorApi::Config
|
168
|
+
end
|
169
|
+
|
170
|
+
def init_suites
|
171
|
+
MUTEX.synchronize {
|
172
|
+
self.suites ||= {}
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
def timestamp(time = nil)
|
177
|
+
((time || Time.now).to_f * 1000).to_i
|
178
|
+
end
|
179
|
+
|
180
|
+
def validate_xml(xml)
|
181
|
+
xsd = Nokogiri::XML::Schema(File.read(Pathname.new(File.dirname(__FILE__)).join("../../allure-model-#{AllureRubyAdaptorApi::Version::ALLURE}.xsd")))
|
182
|
+
doc = Nokogiri::XML(xml)
|
183
|
+
|
184
|
+
xsd.validate(doc).each do |error|
|
185
|
+
$stderr.puts error.message
|
186
|
+
end
|
187
|
+
xml
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
def xml_attachments(xml, attachments)
|
192
|
+
xml.attachments do
|
193
|
+
attachments.each do |attach|
|
194
|
+
xml.attachment :source => attach[:source], :title => attach[:title], :size => attach[:size], :type => attach[:type]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def xml_labels(xml, labels)
|
200
|
+
xml.labels do
|
201
|
+
labels.each do |name, value|
|
202
|
+
if value.is_a?(Array)
|
203
|
+
value.each do |v|
|
204
|
+
xml.label :name => name, :value => v
|
205
|
+
end
|
206
|
+
else
|
207
|
+
xml.label :name => name, :value => value
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'mimemagic'
|
3
|
+
module AllureRubyAdaptorApi
|
4
|
+
module DSL
|
5
|
+
|
6
|
+
|
7
|
+
def step(step, &block)
|
8
|
+
suite = self.example.metadata[:example_group][:description_args].first
|
9
|
+
test = self.example.metadata[:description]
|
10
|
+
AllureRSpec::Builder.start_step(suite, test, step)
|
11
|
+
__with_step step, &block
|
12
|
+
AllureRSpec::Builder.stop_step(suite, test, step)
|
13
|
+
end
|
14
|
+
|
15
|
+
def attach_file(title, file, mime_type = nil)
|
16
|
+
step = current_step
|
17
|
+
dir = Pathname.new(AllureRSpec::Config.output_dir)
|
18
|
+
FileUtils.mkdir_p(dir)
|
19
|
+
file_extname = File.extname(file.path.downcase)
|
20
|
+
mime_type ||= MimeMagic.by_path(file.path) || "text/plain"
|
21
|
+
attachment = dir.join("#{Digest::SHA256.file(file.path).hexdigest}-attachment#{(file_extname.empty?) ? '' : file_extname}")
|
22
|
+
FileUtils.cp(file.path, attachment)
|
23
|
+
suite = self.example.metadata[:example_group][:description_args].first
|
24
|
+
test = self.example.metadata[:description]
|
25
|
+
AllureRubyAdaptorApi::Builder.add_attachment(suite, test, {
|
26
|
+
:type => type,
|
27
|
+
:title => title,
|
28
|
+
:source => attachment.basename,
|
29
|
+
:size => File.stat(attachment).size
|
30
|
+
}, step)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
describe AllureRubyAdaptorApi do
|
5
|
+
let(:builder) { AllureRubyAdaptorApi::Builder }
|
6
|
+
|
7
|
+
it "should build xml report" do
|
8
|
+
|
9
|
+
builder.start_suite "some_suite", :severity => :normal
|
10
|
+
builder.start_test "some_suite", "some_test", :feature => "Some feature"
|
11
|
+
builder.start_step "some_suite", "some_test", "first step"
|
12
|
+
builder.stop_step "some_suite", "some_test", "first step"
|
13
|
+
builder.start_step "some_suite", "some_test", "second step"
|
14
|
+
builder.stop_step "some_suite", "some_test", "second step"
|
15
|
+
builder.start_step "some_suite", "some_test", "third step"
|
16
|
+
builder.stop_step "some_suite", "some_test", "third step", :failed
|
17
|
+
builder.stop_test "some_suite", "some_test", :status => :broken, :exception => Exception.new("some error")
|
18
|
+
builder.stop_suite "some_suite"
|
19
|
+
|
20
|
+
builder.build! {|suite, xml|
|
21
|
+
xml.should_not be_empty
|
22
|
+
xml.should include("<ns2:test-suite")
|
23
|
+
xml.should include("<title>some_suite</title>")
|
24
|
+
xml
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: allure-ruby-adaptor-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ilya Sadykov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.14.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.14.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.6.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: uuid
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mimemagic
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: This is a helper library containing the basics for any ruby-based Allure
|
98
|
+
adaptor.
|
99
|
+
email:
|
100
|
+
- smecsia@yandex-team.ru
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- Gemfile
|
107
|
+
- Gemfile.lock
|
108
|
+
- README.md
|
109
|
+
- allure-model-1.4.0.xsd
|
110
|
+
- allure-ruby-adaptor-api.gemspec
|
111
|
+
- lib/allure-ruby-adaptor-api.rb
|
112
|
+
- lib/allure-ruby-adaptor-api/builder.rb
|
113
|
+
- lib/allure-ruby-adaptor-api/dsl.rb
|
114
|
+
- lib/allure-ruby-adaptor-api/version.rb
|
115
|
+
- spec/extend_steps_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
homepage: http://allure.qatools.ru
|
118
|
+
licenses:
|
119
|
+
- Apache2
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 2.0.3
|
138
|
+
signing_key:
|
139
|
+
specification_version: 4
|
140
|
+
summary: allure-ruby-adaptor-api-0.6.1
|
141
|
+
test_files: []
|