spectre-reporter-vstest 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/spectre/reporter/vstest.rb +171 -0
  3. metadata +62 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e2969162357e6157b01601d284fceeefc6a591de2c258fb58733bf187424868b
4
+ data.tar.gz: 2bf7a9b613612ae4da62a679ee3710260a35632cfd44ebe3fd309f62ce948c50
5
+ SHA512:
6
+ metadata.gz: aad6bb9b517d459de91aa2931b7414ea3057567a8b865d83fec4cfcc2a1ba5a8eb41b45fa06101a97e433b8d57fc7b7910d78bdab74c2dfe9759c1cb77baadb8
7
+ data.tar.gz: 5e3e6c1eec598c2d0e987589539676c6e580877755c314770dc9931c5f3be494fe5b0af0b30f61371a0ef05b4f119787024683e42b38c20f9da47e2dbfb921a6
@@ -0,0 +1,171 @@
1
+ require 'cgi'
2
+ require 'socket'
3
+ require 'securerandom'
4
+
5
+ # Azure mappings: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=trx%2Cyaml
6
+
7
+ module Spectre
8
+ module Reporter
9
+ class VSTest
10
+ VERSION = '1.0.0'
11
+
12
+ def initialize config
13
+ @config = config
14
+ @date_format = '%FT%T.%L'
15
+ end
16
+
17
+ def report run_infos
18
+ now = Time.now.getutc
19
+
20
+ xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
21
+ xml_str += %{<TestRun xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">}
22
+
23
+ started = run_infos[0].started
24
+ finished = run_infos[-1].finished
25
+
26
+ computer_name = Socket.gethostname
27
+
28
+ xml_str += %{<Times start="#{started.strftime(@date_format)}" finish="#{finished.strftime(@date_format)}" />}
29
+
30
+
31
+ # Write summary with file attachments
32
+ xml_str += '<ResultSummary>'
33
+ xml_str += '<ResultFiles>'
34
+ xml_str += %{<ResultFile path="#{File.absolute_path(@config['log_file'])}"></ResultFile>} if File.exists? @config['log_file']
35
+
36
+ report_files = Dir[File.join(@config['out_path'], '*')]
37
+
38
+ if report_files.any?
39
+ report_files.each do |report_file|
40
+ xml_str += %{<ResultFile path="#{File.absolute_path(report_file)}"></ResultFile>}
41
+ end
42
+ end
43
+
44
+ xml_str += '</ResultFiles>'
45
+ xml_str += '</ResultSummary>'
46
+
47
+
48
+ # Write test definitions
49
+ test_definitions = run_infos
50
+ .sort_by { |x| x.spec.name }
51
+ .map { |x| [SecureRandom.uuid(), SecureRandom.uuid(), x] }
52
+
53
+ xml_str += '<TestDefinitions>'
54
+ test_definitions.each do |test_id, execution_id, run_info|
55
+ xml_str += %{<UnitTest name="#{CGI::escapeHTML get_name(run_info)}" storage="#{CGI::escapeHTML(run_info.spec.file.to_s)}" id="#{test_id}">}
56
+ xml_str += %{<Execution id="#{execution_id}" />}
57
+ xml_str += '</UnitTest>'
58
+ end
59
+ xml_str += '</TestDefinitions>'
60
+
61
+
62
+ # Write test results
63
+ xml_str += '<Results>'
64
+ test_definitions.each do |test_id, execution_id, run_info|
65
+ duration_str = Time.at(run_info.duration).gmtime.strftime('%T.%L')
66
+
67
+ if run_info.failed?
68
+ outcome = 'Failed'
69
+ elsif run_info.error?
70
+ outcome = 'Error'
71
+ elsif run_info.skipped?
72
+ outcome = 'Skipped'
73
+ else
74
+ outcome = 'Passed'
75
+ end
76
+
77
+ xml_str += %{<UnitTestResult executionId="#{execution_id}" testId="#{test_id}" testName="#{CGI::escapeHTML get_name(run_info)}" computerName="#{computer_name}" duration="#{duration_str}" startTime="#{run_info.started.strftime(@date_format)}" endTime="#{run_info.finished.strftime(@date_format)}" outcome="#{outcome}">}
78
+
79
+ if run_info.log.any? or run_info.failed? or run_info.error?
80
+ xml_str += '<Output>'
81
+
82
+ # Write log entries
83
+ xml_str += '<StdOut>'
84
+ log_str = ''
85
+
86
+ if run_info.properties.count > 0
87
+ run_info.properties.each do |key, val|
88
+ log_str += "#{key}: #{val}\n"
89
+ end
90
+ end
91
+
92
+ if run_info.data
93
+ data_str = run_info.data
94
+ data_str = run_info.data.to_json unless run_info.data.is_a? String or run_info.data.is_a? Integer
95
+ log_str += "data: #{data_str}\n"
96
+ end
97
+
98
+ run_info.log.each do |timestamp, message, level, name|
99
+ log_str += %{#{timestamp.strftime(@date_format)} #{level.to_s.upcase} -- #{name}: #{CGI::escapeHTML(message.to_s)}\n}
100
+ end
101
+
102
+ xml_str += log_str
103
+ xml_str += '</StdOut>'
104
+
105
+ # Write error information
106
+ if run_info.failed? or run_info.error?
107
+ xml_str += '<ErrorInfo>'
108
+
109
+ if run_info.failed? and not run_info.failure.cause
110
+ xml_str += '<Message>'
111
+
112
+ failure_message = "Expected #{run_info.failure.expectation}"
113
+ failure_message += " with #{run_info.data}" if run_info.data
114
+ failure_message += " but it failed"
115
+ failure_message += " with message: #{run_info.failure.message}" if run_info.failure.message
116
+
117
+ xml_str += CGI::escapeHTML(failure_message)
118
+
119
+ xml_str += '</Message>'
120
+ end
121
+
122
+ if run_info.error or (run_info.failed? and run_info.failure.cause)
123
+ error = run_info.error || run_info.failure.cause
124
+
125
+ failure_message = error.message
126
+
127
+ xml_str += '<Message>'
128
+ xml_str += CGI::escapeHTML(failure_message)
129
+ xml_str += '</Message>'
130
+
131
+ stack_trace = error.backtrace.join "\n"
132
+
133
+ xml_str += '<StackTrace>'
134
+ xml_str += CGI::escapeHTML(stack_trace)
135
+ xml_str += '</StackTrace>'
136
+ end
137
+
138
+ xml_str += '</ErrorInfo>'
139
+ end
140
+
141
+ xml_str += '</Output>'
142
+ end
143
+
144
+
145
+ xml_str += '</UnitTestResult>'
146
+ end
147
+ xml_str += '</Results>'
148
+
149
+
150
+ # End report
151
+ xml_str += '</TestRun>'
152
+
153
+
154
+ Dir.mkdir(@config['out_path']) unless Dir.exists? @config['out_path']
155
+
156
+ file_path = File.join(@config['out_path'], "spectre-vstest_#{now.strftime('%s')}.trx")
157
+
158
+ File.write(file_path, xml_str)
159
+ end
160
+
161
+ private
162
+
163
+ def get_name run_info
164
+ run_name = "[#{run_info.spec.name}] #{run_info.spec.subject.desc}"
165
+ run_name += " - #{run_info.spec.context.__desc} -" unless run_info.spec.context.__desc.nil?
166
+ run_name += " #{run_info.spec.desc}"
167
+ run_name
168
+ end
169
+ end
170
+ end
171
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spectre-reporter-vstest
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Christian Neubauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-08-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: spectre-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ description: Writes a VSTest report for spectre test run, which can be used in Azure
28
+ DevOps
29
+ email:
30
+ - christian.neubauer@ionos.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/spectre/reporter/vstest.rb
36
+ homepage: https://github.com/ionos-spectre/spectre-reporter-vstest
37
+ licenses:
38
+ - GPL-3.0-or-later
39
+ metadata:
40
+ homepage_uri: https://github.com/ionos-spectre/spectre-reporter-vstest
41
+ source_code_uri: https://github.com/ionos-spectre/spectre-reporter-vstest
42
+ changelog_uri: https://github.com/ionos-spectre/spectre-reporter-vstest/blob/master/CHANGELOG.md
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 3.0.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.3.7
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: A VSTest reporter for spectre
62
+ test_files: []