meson-junit 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 14fb11afe0ddfca3654a9d4e9603072b30a4b39448156140691ed49247e2cd4b
4
+ data.tar.gz: 4fa62e089335d45d9127cf0efc3169a0078363bc9fe3e01d2eb52dec05ad384a
5
+ SHA512:
6
+ metadata.gz: 6c8b2efa2b3f70624ed8e20fb77185bae8acecd2c1fb6d337425c34bbc24468f939e1a792298010c5fc61cb4d6d78ca394f2d54cbfa79789e1f9c7045d2a13ce
7
+ data.tar.gz: 82caabd3b3a07102cf54decdf54a3553d01acaecdefbcdc196ad8861f1c4e17adbdfc99a194e719edf85ea2937dccf5461319b3ca5e5bca69c50fbb8ad5eebac
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ meson-junit
2
+ ===========
3
+
4
+ Overview
5
+ --------
6
+ Command-line tool to convert [Meson][] test results to a
7
+ [Jenkins][]-compatible [JUnit][] [XML][].
8
+
9
+ Usage:
10
+
11
+ #
12
+ # This command does the following:
13
+ #
14
+ # - Read Meson test results in JSON format from the file
15
+ # "meson-logs/testlog.json".
16
+ #
17
+ # - Convert the input from JSON to Jenkins-friendly, JUnit XML.
18
+ #
19
+ # - Write the generated XML to "junit.xml".
20
+ #
21
+ meson-junit < meson-logs/testlog.json > junit.xml
22
+
23
+ If you are running your [Meson][] tests via [Jenkins Pipeline][], you
24
+ would include `meson-junit` in your `steps` like this:
25
+
26
+ steps {
27
+ // run tests, generate output in build-dir/meson-logs/testlog.json
28
+ sh 'cd build && meson test || true'
29
+
30
+ // generate build/testlog.xml
31
+ sh 'cd build && meson-junit < meson-logs/testlog.json > testlog.xml'
32
+
33
+ // read junit results
34
+ junit 'build/testlog.xml'
35
+ }
36
+
37
+ Notes:
38
+
39
+ * [Meson][] test results are converted to [JUnit][] `<testsuite>`
40
+ elements, rather than `<testcase>` elements. This is so we can expose
41
+ the attributes of the [Meson][] test results (the test command,
42
+ return code, environment variables, etc) as `<property>` elements.
43
+ * The reference used to generate the [JUnit][] [XML][] is available here:
44
+ [JUnit XML reporting file format][junit-ref].
45
+
46
+ Installation
47
+ ------------
48
+ Install `meson-junit` via [RubyGems][], like so:
49
+
50
+ # install meson-junit using rubygems
51
+ gem install meson-junit
52
+
53
+ Documentation
54
+ -------------
55
+ You can generate the API documentation in the `docs/` directory via
56
+ [RDoc][], like so:
57
+
58
+ # generate API documentation in docs/ directory
59
+ rake docs
60
+
61
+ Tests
62
+ -----
63
+ You can run the [minitest][] test suite via [Rake][], like so:
64
+
65
+ # run the test suite
66
+ rake test
67
+
68
+ To generate a [JUnit][]-compatible XML report, install the
69
+ [minitest-junit][] gem and then do the following:
70
+
71
+ # run the test suite and generate a junit-compatible report.xml
72
+ rake test TESTOPTS=--junit
73
+
74
+ Author
75
+ ------
76
+ Paul Duncan ([pabs@pablotron.org][me])<br/>
77
+ <https://pablotron.org/>
78
+
79
+ License
80
+ -------
81
+ Copyright 2019 Paul Duncan ([pabs@pablotron.org][me])
82
+
83
+ Permission is hereby granted, free of charge, to any person obtaining a
84
+ copy of this software and associated documentation files (the
85
+ "Software"), to deal in the Software without restriction, including
86
+ without limitation the rights to use, copy, modify, merge, publish,
87
+ distribute, sublicense, and/or sell copies of the Software, and to
88
+ permit persons to whom the Software is furnished to do so, subject to
89
+ the following conditions:
90
+
91
+ The above copyright notice and this permission notice shall be included
92
+ in all copies or substantial portions of the Software.
93
+
94
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
95
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
96
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
97
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
98
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
99
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
100
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
101
+
102
+ [junit-ref]: https://llg.cubic.org/docs/junit/
103
+ [xml]: https://en.wikipedia.org/wiki/XML
104
+ [meson]: https://mesonbuild.com/
105
+ [jenkins]: https://jenkins-ci.org/
106
+ [jenkins pipeline]: https://jenkins.io/doc/book/pipeline/
107
+ [RubyGems]: https://rubygems.org/
108
+ [JUnit]: https://junit.org/
109
+ [me]: mailto:pabs@pablotron.org
110
+ [minitest]: https://github.com/seattlerb/minitest
111
+ [minitest-junit]: https://github.com/aespinosa/minitest-junit
112
+ [RDoc]: https://github.com/ruby/rdoc
113
+ [Rake]: https://github.com/ruby/rake
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'rake/testtask'
2
+ require 'rdoc/task'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ RDoc::Task.new :docs do |t|
9
+ t.main = "lib/meson-junit"
10
+ t.rdoc_files.include('lib/**/*.rb')
11
+ t.rdoc_dir = 'docs'
12
+ # t.options << "--all"
13
+ end
14
+
15
+ desc "Run tests"
16
+ task :default => :test
data/bin/meson-junit ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # load library
4
+ require_relative '../lib/meson-junit'
5
+
6
+ # invoke command-line interface
7
+ MesonJunit::CLI.run($0, ARGV)
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+ require 'nokogiri'
3
+
4
+ #
5
+ # Meson to JUnit test case generator.
6
+ #
7
+ module MesonJunit
8
+ VERSION = '0.1.0'
9
+
10
+ autoload :Meson, File.join(__dir__, 'meson-junit', 'meson.rb')
11
+ autoload :Junit, File.join(__dir__, 'meson-junit', 'junit.rb')
12
+ autoload :CLI, File.join(__dir__, 'meson-junit', 'cli.rb')
13
+ end
@@ -0,0 +1,20 @@
1
+ #
2
+ # Command-line interface.
3
+ #
4
+ module MesonJunit::CLI
5
+ #
6
+ # Allow command-line invocation.
7
+ #
8
+ def self.run(app, args)
9
+ # TODO: parse command-line arguments
10
+
11
+ # parse meson test log json from standard input
12
+ log = MesonJunit::Meson::TestLog.new(STDIN)
13
+
14
+ # build junit xml from meson testlog
15
+ xml = MesonJunit::Junit::XMLBuilder.build(log)
16
+
17
+ # write xml to standard output
18
+ puts xml
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ #
2
+ # JUnit XML builder namespace.
3
+ #
4
+ module MesonJunit::Junit
5
+ autoload :XMLBuilder, File.join(__dir__, 'junit', 'xml-builder.rb')
6
+ end
@@ -0,0 +1,173 @@
1
+ #
2
+ # Read parsed Meson test log and build JUnit-compatible XML.
3
+ #
4
+ class MesonJunit::Junit::XMLBuilder
5
+ def self.build(log)
6
+ new.build(log)
7
+ end
8
+
9
+ #
10
+ # Build JUnit-compatible XML from parsed Meson test log.
11
+ #
12
+ def build(log)
13
+ ::Nokogiri::XML::Builder.new do |xml|
14
+ xml.testsuites(**testsuites_el_attrs(log)) do
15
+ emit_testsuite_els(xml, log)
16
+ end
17
+ end.to_xml
18
+ end
19
+
20
+ private
21
+
22
+ #
23
+ # Convert Meson test log to a series of JUnit test suites.
24
+ #
25
+ # We map Meson tests to a series of JUnit test suites with a single
26
+ # test case because that allows us to map the per-test attributes and
27
+ # environment variables to JUnit test suite properties.
28
+ #
29
+ def emit_testsuite_els(xml, log)
30
+ log.tests.each_with_index do |test, test_num|
31
+ xml.testsuite(**testsuite_el_attrs(test, test_num)) do
32
+ # emit testsuite properties
33
+ emit_properties(xml, test)
34
+
35
+ # emit testcase
36
+ emit_testcase(xml, test)
37
+
38
+ # emit standard output and standard error
39
+ xml.send('system-out', test.data['stdout'])
40
+ xml.send('system-err', test.data['stderr'])
41
+ end
42
+ end
43
+ end
44
+
45
+ #
46
+ # Emit Meson test attributes as JUnit `testsuite` properties.
47
+ #
48
+ def emit_properties(xml, test)
49
+ xml.properties do
50
+ # convert all non-environment variable meson test attributes to
51
+ # junit test suite properties
52
+ test.data.each do |key, val|
53
+ unless key == 'env'
54
+ emit_property(xml, key, val)
55
+ end
56
+ end
57
+
58
+ # convert meson test environment variables to junit test suite
59
+ # properties
60
+ (test.data['env'] || {}).each do |key, val|
61
+ emit_property(xml, 'env.%s' % [key], val)
62
+ end
63
+ end
64
+ end
65
+
66
+ #
67
+ # Emit details of Meson test as a JUnit `testcase` element.
68
+ def emit_testcase(xml, test)
69
+ xml.testcase(**testcase_el_attrs(test)) do
70
+ if test.failed?
71
+ # emit a `failure` element with a body that contains the
72
+ # standard error output from the Meson test.
73
+ xml.failure(test.data['stderr'], message: 'Test failed.')
74
+ end
75
+
76
+ # emit standard io elements
77
+ emit_stdio(xml, test)
78
+ end
79
+ end
80
+
81
+ #
82
+ # Emit standard output and standard error from a Meson test case as
83
+ # JUnit-compatible `system-out` and `system-err` elements.
84
+ #
85
+ def emit_stdio(xml, test)
86
+ # emit standard output and standard error
87
+ xml.send('system-out', test.data['stdout'])
88
+ xml.send('system-err', test.data['stderr'])
89
+ end
90
+
91
+ #
92
+ # Emit a Meson test attribute as a JUnit test suite property.
93
+ #
94
+ def emit_property(xml, key, val)
95
+ case val
96
+ when Array, Hash
97
+ # serialize arrays and hashes as JSON
98
+ xml.property(name: key, value: ::JSON.unparse(val))
99
+ else
100
+ xml.property(name: key, value: val)
101
+ end
102
+ end
103
+
104
+ #
105
+ # Get hash of attributes for root JUnit `testsuites` element.
106
+ #
107
+ def testsuites_el_attrs(log)
108
+ {
109
+ # total number of tests
110
+ tests: log.tests.size,
111
+
112
+ # total number of failed tests
113
+ failures: log.tests.reduce(0) do |r, test|
114
+ r + (test.failed? ? 1 : 0)
115
+ end,
116
+
117
+ # total amount of time across all tests
118
+ time: log.tests.reduce(0) do |r, test|
119
+ r + test.duration
120
+ end,
121
+ }
122
+ end
123
+
124
+ #
125
+ # Get hash of attributes for JUnit `testsuite` element.
126
+ #
127
+ def testsuite_el_attrs(test, test_num)
128
+ {
129
+ # test number, starting from zero
130
+ id: test_num,
131
+
132
+ # junit-friendly class name
133
+ name: safe_name(test.name),
134
+
135
+ # total number of tests (always 1)
136
+ tests: 1,
137
+
138
+ # total number of errors (always either 0 or 1)
139
+ errors: test.failed? ? 1 : 0,
140
+
141
+ # total amount of time for this test
142
+ time: test.duration,
143
+ }
144
+ end
145
+
146
+ #
147
+ # Get hash of attributes for JUnit `testcase` element.
148
+ #
149
+ def testcase_el_attrs(test)
150
+ {
151
+ # test case name
152
+ name: 'main',
153
+
154
+ # test case class name
155
+ classname: safe_name(test.name),
156
+
157
+ # time taken (in seconds) to execute test.
158
+ time: test.duration,
159
+ }
160
+ end
161
+
162
+ #
163
+ # Invalid characters in JUnit class name.
164
+ #
165
+ BAD_CHARS = /[^a-z0-9_]+/
166
+
167
+ #
168
+ # Sanitize a Meson test name as a JUnit-friendly class name.
169
+ #
170
+ def safe_name(s)
171
+ s.gsub(BAD_CHARS, '_')
172
+ end
173
+ end
@@ -0,0 +1,7 @@
1
+ #
2
+ # Meson parsing namespace.
3
+ #
4
+ module MesonJunit::Meson
5
+ autoload :Test, File.join(__dir__, 'meson', 'test.rb')
6
+ autoload :TestLog, File.join(__dir__, 'meson', 'test-log.rb')
7
+ end
@@ -0,0 +1,18 @@
1
+ #
2
+ # Single Meson test result.
3
+ #
4
+ class MesonJunit::Meson::TestLog
5
+ #
6
+ # Individual Meson test results.
7
+ #
8
+ attr :tests
9
+
10
+ #
11
+ # Parse a testlog.json file.
12
+ #
13
+ def initialize(io)
14
+ @tests = io.readlines.map do |line|
15
+ ::MesonJunit::Meson::Test.new(::JSON.parse(line))
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,48 @@
1
+ #
2
+ # Single Meson test result.
3
+ #
4
+ class MesonJunit::Meson::Test
5
+ #
6
+ # Parsed JSON data.
7
+ #
8
+ attr :data
9
+
10
+ #
11
+ # Test name.
12
+ #
13
+ attr :name
14
+
15
+ #
16
+ # Duration of test run, in seconds.
17
+ #
18
+ attr :duration
19
+
20
+ #
21
+ # Test result (either :OK or :FAIL).
22
+ #
23
+ attr :result
24
+
25
+ #
26
+ # Create a test case from parsed Meson JSON data.
27
+ #
28
+ def initialize(data)
29
+ @data = data.freeze
30
+ @name = @data['name']
31
+ @duration = @data['duration'] || 0
32
+ @result = @data['result'].intern
33
+ end
34
+
35
+ #
36
+ # Did this test succeed?
37
+ #
38
+ def ok?
39
+ @result == :OK
40
+ end
41
+
42
+ #
43
+ # Did this test fail?
44
+ #
45
+ def failed?
46
+ @result == :FAIL
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ {"name": "test-io-logger", "stdout": "", "result": "OK", "duration": 0.017489910125732422, "returncode": 0, "command": ["/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-io-logger"], "env": {"GIT_PREVIOUS_SUCCESSFUL_COMMIT": "980602362882ea45fe08b67e01eecf8114e663b9", "HOSTNAME": "d38bcdc0a0f0", "RUN_CHANGES_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect?page=changes", "GIT_COMMIT": "0a342a9d5f2058e9f2872078c45d791cd62a3b61", "NODE_LABELS": "master", "HUDSON_URL": "http://hive:9090/", "HOME": "/", "OLDPWD": "/var/lib/jenkins/workspace/raggle_master", "BUILD_URL": "http://hive:9090/job/raggle/job/master/32/", "GIT_LOCAL_BRANCH": "master", "JENKINS_SERVER_COOKIE": "durable-a623a7ae73afbc86e3205e2d30ff0631", "LDFLAGS": "-lasan", "WORKSPACE": "/var/lib/jenkins/workspace/raggle_master", "NODE_NAME": "master", "EXECUTOR_NUMBER": "1", "GIT_BRANCH": "master", "STAGE_NAME": "address", "BUILD_DISPLAY_NAME": "#32", "HUDSON_HOME": "/var/lib/jenkins", "JOB_BASE_NAME": "master", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "BUILD_ID": "32", "CFLAGS": "-g", "BUILD_TAG": "jenkins-raggle-master-32", "JENKINS_URL": "http://hive:9090/", "JOB_URL": "http://hive:9090/job/raggle/job/master/", "GIT_URL": "git://u3/raggle.git", "BUILD_NUMBER": "32", "JENKINS_NODE_COOKIE": "5384bb4a-0b67-4e96-8d36-afa4e39e8bff", "RUN_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect", "HUDSON_SERVER_COOKIE": "44bd36d136089097", "JOB_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/display/redirect", "CLASSPATH": "", "JOB_NAME": "raggle/master", "PWD": "/var/lib/jenkins/workspace/raggle_master/build/sanitize/address", "GIT_PREVIOUS_COMMIT": "d1721a6594f2688dbac2be0c1142edf49ff634da", "CC": "clang-7", "BRANCH_NAME": "master", "LC_CTYPE": "C.UTF-8"}}
2
+ {"name": "test-file-logger", "stdout": "", "result": "OK", "duration": 0.027406692504882812, "returncode": 0, "command": ["/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-file-logger"], "env": {"GIT_PREVIOUS_SUCCESSFUL_COMMIT": "980602362882ea45fe08b67e01eecf8114e663b9", "HOSTNAME": "d38bcdc0a0f0", "RUN_CHANGES_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect?page=changes", "GIT_COMMIT": "0a342a9d5f2058e9f2872078c45d791cd62a3b61", "NODE_LABELS": "master", "HUDSON_URL": "http://hive:9090/", "HOME": "/", "OLDPWD": "/var/lib/jenkins/workspace/raggle_master", "BUILD_URL": "http://hive:9090/job/raggle/job/master/32/", "GIT_LOCAL_BRANCH": "master", "JENKINS_SERVER_COOKIE": "durable-a623a7ae73afbc86e3205e2d30ff0631", "LDFLAGS": "-lasan", "WORKSPACE": "/var/lib/jenkins/workspace/raggle_master", "NODE_NAME": "master", "EXECUTOR_NUMBER": "1", "GIT_BRANCH": "master", "STAGE_NAME": "address", "BUILD_DISPLAY_NAME": "#32", "HUDSON_HOME": "/var/lib/jenkins", "JOB_BASE_NAME": "master", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "BUILD_ID": "32", "CFLAGS": "-g", "BUILD_TAG": "jenkins-raggle-master-32", "JENKINS_URL": "http://hive:9090/", "JOB_URL": "http://hive:9090/job/raggle/job/master/", "GIT_URL": "git://u3/raggle.git", "BUILD_NUMBER": "32", "JENKINS_NODE_COOKIE": "5384bb4a-0b67-4e96-8d36-afa4e39e8bff", "RUN_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect", "HUDSON_SERVER_COOKIE": "44bd36d136089097", "JOB_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/display/redirect", "CLASSPATH": "", "JOB_NAME": "raggle/master", "PWD": "/var/lib/jenkins/workspace/raggle_master/build/sanitize/address", "GIT_PREVIOUS_COMMIT": "d1721a6594f2688dbac2be0c1142edf49ff634da", "CC": "clang-7", "BRANCH_NAME": "master", "LC_CTYPE": "C.UTF-8"}}
3
+ {"name": "test-mem-store", "stdout": "", "result": "FAIL", "duration": 0.3238527774810791, "returncode": 1, "command": ["/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store"], "env": {"GIT_PREVIOUS_SUCCESSFUL_COMMIT": "980602362882ea45fe08b67e01eecf8114e663b9", "HOSTNAME": "d38bcdc0a0f0", "RUN_CHANGES_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect?page=changes", "GIT_COMMIT": "0a342a9d5f2058e9f2872078c45d791cd62a3b61", "NODE_LABELS": "master", "HUDSON_URL": "http://hive:9090/", "HOME": "/", "OLDPWD": "/var/lib/jenkins/workspace/raggle_master", "BUILD_URL": "http://hive:9090/job/raggle/job/master/32/", "GIT_LOCAL_BRANCH": "master", "JENKINS_SERVER_COOKIE": "durable-a623a7ae73afbc86e3205e2d30ff0631", "LDFLAGS": "-lasan", "WORKSPACE": "/var/lib/jenkins/workspace/raggle_master", "NODE_NAME": "master", "EXECUTOR_NUMBER": "1", "GIT_BRANCH": "master", "STAGE_NAME": "address", "BUILD_DISPLAY_NAME": "#32", "HUDSON_HOME": "/var/lib/jenkins", "JOB_BASE_NAME": "master", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "BUILD_ID": "32", "CFLAGS": "-g", "BUILD_TAG": "jenkins-raggle-master-32", "JENKINS_URL": "http://hive:9090/", "JOB_URL": "http://hive:9090/job/raggle/job/master/", "GIT_URL": "git://u3/raggle.git", "BUILD_NUMBER": "32", "JENKINS_NODE_COOKIE": "5384bb4a-0b67-4e96-8d36-afa4e39e8bff", "RUN_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect", "HUDSON_SERVER_COOKIE": "44bd36d136089097", "JOB_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/display/redirect", "CLASSPATH": "", "JOB_NAME": "raggle/master", "PWD": "/var/lib/jenkins/workspace/raggle_master/build/sanitize/address", "GIT_PREVIOUS_COMMIT": "d1721a6594f2688dbac2be0c1142edf49ff634da", "CC": "clang-7", "BRANCH_NAME": "master", "LC_CTYPE": "C.UTF-8"}, "stderr": "\n=================================================================\n==305==ERROR: LeakSanitizer: detected memory leaks\n\nDirect leak of 384 byte(s) in 1 object(s) allocated from:\n #0 0x4c5552 in realloc (/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store+0x4c5552)\n #1 0x4f4759 in on_rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:27:26\n #2 0x4f4539 in rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:125:10\n #3 0x4f891f in rg_mem_store_resize_folders /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:43:37\n #4 0x4f8656 in rg_mem_store_init /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:377:8\n #5 0x4fb769 in mem_store_test_run /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/shared/mem-store-test.c:23:8\n #6 0x4fb8ce in main /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/mem-store/main.c:18:3\n #7 0x7f47cc22f09a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)\n\nSUMMARY: AddressSanitizer: 384 byte(s) leaked in 1 allocation(s).\n"}
4
+ {"name": "test-mem-store-add-feeds", "stdout": "", "result": "FAIL", "duration": 0.325427770614624, "returncode": 1, "command": ["/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store-add-feeds"], "env": {"GIT_PREVIOUS_SUCCESSFUL_COMMIT": "980602362882ea45fe08b67e01eecf8114e663b9", "HOSTNAME": "d38bcdc0a0f0", "RUN_CHANGES_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect?page=changes", "GIT_COMMIT": "0a342a9d5f2058e9f2872078c45d791cd62a3b61", "NODE_LABELS": "master", "HUDSON_URL": "http://hive:9090/", "HOME": "/", "OLDPWD": "/var/lib/jenkins/workspace/raggle_master", "BUILD_URL": "http://hive:9090/job/raggle/job/master/32/", "GIT_LOCAL_BRANCH": "master", "JENKINS_SERVER_COOKIE": "durable-a623a7ae73afbc86e3205e2d30ff0631", "LDFLAGS": "-lasan", "WORKSPACE": "/var/lib/jenkins/workspace/raggle_master", "NODE_NAME": "master", "EXECUTOR_NUMBER": "1", "GIT_BRANCH": "master", "STAGE_NAME": "address", "BUILD_DISPLAY_NAME": "#32", "HUDSON_HOME": "/var/lib/jenkins", "JOB_BASE_NAME": "master", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "BUILD_ID": "32", "CFLAGS": "-g", "BUILD_TAG": "jenkins-raggle-master-32", "JENKINS_URL": "http://hive:9090/", "JOB_URL": "http://hive:9090/job/raggle/job/master/", "GIT_URL": "git://u3/raggle.git", "BUILD_NUMBER": "32", "JENKINS_NODE_COOKIE": "5384bb4a-0b67-4e96-8d36-afa4e39e8bff", "RUN_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect", "HUDSON_SERVER_COOKIE": "44bd36d136089097", "JOB_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/display/redirect", "CLASSPATH": "", "JOB_NAME": "raggle/master", "PWD": "/var/lib/jenkins/workspace/raggle_master/build/sanitize/address", "GIT_PREVIOUS_COMMIT": "d1721a6594f2688dbac2be0c1142edf49ff634da", "CC": "clang-7", "BRANCH_NAME": "master", "LC_CTYPE": "C.UTF-8"}, "stderr": "\n=================================================================\n==307==ERROR: LeakSanitizer: detected memory leaks\n\nDirect leak of 384 byte(s) in 1 object(s) allocated from:\n #0 0x4c5552 in realloc (/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store-add-feeds+0x4c5552)\n #1 0x4f4759 in on_rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:27:26\n #2 0x4f4539 in rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:125:10\n #3 0x4f891f in rg_mem_store_resize_folders /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:43:37\n #4 0x4f8656 in rg_mem_store_init /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:377:8\n #5 0x4fb769 in mem_store_test_run /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/shared/mem-store-test.c:23:8\n #6 0x4fb8ce in main /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/mem-store-add-feeds/main.c:34:3\n #7 0x7f92456a509a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)\n\nSUMMARY: AddressSanitizer: 384 byte(s) leaked in 1 allocation(s).\n"}
5
+ {"name": "test-mem-store-add-folders", "stdout": "", "result": "FAIL", "duration": 0.37346959114074707, "returncode": 1, "command": ["/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store-add-folders"], "env": {"GIT_PREVIOUS_SUCCESSFUL_COMMIT": "980602362882ea45fe08b67e01eecf8114e663b9", "HOSTNAME": "d38bcdc0a0f0", "RUN_CHANGES_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect?page=changes", "GIT_COMMIT": "0a342a9d5f2058e9f2872078c45d791cd62a3b61", "NODE_LABELS": "master", "HUDSON_URL": "http://hive:9090/", "HOME": "/", "OLDPWD": "/var/lib/jenkins/workspace/raggle_master", "BUILD_URL": "http://hive:9090/job/raggle/job/master/32/", "GIT_LOCAL_BRANCH": "master", "JENKINS_SERVER_COOKIE": "durable-a623a7ae73afbc86e3205e2d30ff0631", "LDFLAGS": "-lasan", "WORKSPACE": "/var/lib/jenkins/workspace/raggle_master", "NODE_NAME": "master", "EXECUTOR_NUMBER": "1", "GIT_BRANCH": "master", "STAGE_NAME": "address", "BUILD_DISPLAY_NAME": "#32", "HUDSON_HOME": "/var/lib/jenkins", "JOB_BASE_NAME": "master", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "BUILD_ID": "32", "CFLAGS": "-g", "BUILD_TAG": "jenkins-raggle-master-32", "JENKINS_URL": "http://hive:9090/", "JOB_URL": "http://hive:9090/job/raggle/job/master/", "GIT_URL": "git://u3/raggle.git", "BUILD_NUMBER": "32", "JENKINS_NODE_COOKIE": "5384bb4a-0b67-4e96-8d36-afa4e39e8bff", "RUN_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/32/display/redirect", "HUDSON_SERVER_COOKIE": "44bd36d136089097", "JOB_DISPLAY_URL": "http://hive:9090/job/raggle/job/master/display/redirect", "CLASSPATH": "", "JOB_NAME": "raggle/master", "PWD": "/var/lib/jenkins/workspace/raggle_master/build/sanitize/address", "GIT_PREVIOUS_COMMIT": "d1721a6594f2688dbac2be0c1142edf49ff634da", "CC": "clang-7", "BRANCH_NAME": "master", "LC_CTYPE": "C.UTF-8"}, "stderr": "\n=================================================================\n==304==ERROR: LeakSanitizer: detected memory leaks\n\nDirect leak of 384 byte(s) in 1 object(s) allocated from:\n #0 0x4c5552 in realloc (/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store-add-folders+0x4c5552)\n #1 0x4f4759 in on_rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:27:26\n #2 0x4f4539 in rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:125:10\n #3 0x4f891f in rg_mem_store_resize_folders /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:43:37\n #4 0x4f8656 in rg_mem_store_init /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:377:8\n #5 0x4fb769 in mem_store_test_run /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/shared/mem-store-test.c:23:8\n #6 0x4fb8ce in main /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/mem-store-add-folders/main.c:34:3\n #7 0x7f967de4a09a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)\n\nIndirect leak of 12 byte(s) in 3 object(s) allocated from:\n #0 0x4c5552 in realloc (/var/lib/jenkins/workspace/raggle_master/build/sanitize/address/test-mem-store-add-folders+0x4c5552)\n #1 0x4f4759 in on_rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:27:26\n #2 0x4f4539 in rg_ctx_realloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:125:10\n #3 0x4f44b3 in rg_ctx_malloc /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:116:10\n #4 0x4f45cf in rg_ctx_strndup /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-ctx.c:149:22\n #5 0x4fb0b1 in rg_folder_set_str /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-folder.c:68:38\n #6 0x4f91ec in on_mem_store_folder_add /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-mem-store.c:92:8\n #7 0x4f68b1 in rg_store_folder_add /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/core/rg-store.c:76:5\n #8 0x4fba48 in run /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/mem-store-add-folders/main.c:23:10\n #9 0x4fb793 in mem_store_test_run /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/shared/mem-store-test.c:28:3\n #10 0x4fb8ce in main /var/lib/jenkins/workspace/raggle_master/build/sanitize/address/../../../src/tests/mem-store-add-folders/main.c:34:3\n #11 0x7f967de4a09a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)\n\nSUMMARY: AddressSanitizer: 396 byte(s) leaked in 4 allocation(s).\n"}
@@ -0,0 +1,24 @@
1
+ require 'minitest/autorun'
2
+ require 'meson-junit'
3
+
4
+ class JunitTest < MiniTest::Test
5
+ def test_junit_xmlbuilder_new
6
+ builder = ::MesonJunit::Junit::XMLBuilder.new
7
+ assert_instance_of ::MesonJunit::Junit::XMLBuilder, builder
8
+ end
9
+
10
+ TESTLOG_PATH = File.join(__dir__, 'data', 'testlog.json')
11
+
12
+ def test_junit_xmlbuilder_build
13
+ # parse sample testlog.json
14
+ log = File.open(TESTLOG_PATH) do |fh|
15
+ # parse input file as a Meson::TestLog
16
+ ::MesonJunit::Meson::TestLog.new(fh)
17
+ end
18
+
19
+ # build junit xml
20
+ xml = ::MesonJunit::Junit::XMLBuilder.build(log)
21
+
22
+ assert_instance_of String, xml
23
+ end
24
+ end
@@ -0,0 +1,59 @@
1
+ require 'minitest/autorun'
2
+ require 'json'
3
+ require 'meson-junit'
4
+
5
+ class MesonTest < MiniTest::Test
6
+ # sample JSON
7
+ MOCK_JSON = '{
8
+ "name": "test-something",
9
+ "stdout": "",
10
+ "result": "OK",
11
+ "duration": 0.017489910125732422,
12
+ "returncode": 0,
13
+ "command": [
14
+ "/path/to/tests/test-something"
15
+ ],
16
+ "env": {
17
+ "FOO": "some foo data",
18
+ "BAR": "some bar data",
19
+ "BAZ": "some baz data"
20
+ }
21
+ }'.freeze
22
+
23
+ def test_meson_test_new
24
+ data = ::JSON.parse(MOCK_JSON)
25
+ t = ::MesonJunit::Meson::Test.new(data)
26
+ assert_instance_of ::MesonJunit::Meson::Test, t
27
+ end
28
+
29
+ # path to sample testlog.json
30
+ TESTLOG_PATH = File.join(__dir__, 'data', 'testlog.json').freeze
31
+
32
+ # expected sums
33
+ EXPECTED_SUMS = {
34
+ all: 5,
35
+ OK: 2,
36
+ FAIL: 3,
37
+ }
38
+
39
+ def test_meson_testlog_new
40
+ # parse sample testlog.json
41
+ log = File.open(TESTLOG_PATH) do |fh|
42
+ ::MesonJunit::Meson::TestLog.new(fh)
43
+ end
44
+
45
+ # verify that it parsed as a test log
46
+ assert_instance_of ::MesonJunit::Meson::TestLog, log
47
+
48
+ sums = log.tests.reduce(Hash.new { |h, k| h[k] = 0 }) do |r, test|
49
+ r[:all] += 1
50
+ r[test.result] += 1
51
+ r
52
+ end
53
+
54
+ # verify test counts
55
+ EXPECTED_SUMS.each do |key, sum|
56
+ assert_equal sum, sums[key]
57
+ end
58
+ end
59
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meson-junit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Duncan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-junit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
55
+ description: "\n Command-line tool and library to convert Meson testlog JSOn files
56
+ to\n Jenkins-compatible JUnit XML files.\n "
57
+ email: pabs@pablotron.org
58
+ executables:
59
+ - meson-junit
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - Rakefile
65
+ - bin/meson-junit
66
+ - lib/meson-junit.rb
67
+ - lib/meson-junit/cli.rb
68
+ - lib/meson-junit/junit.rb
69
+ - lib/meson-junit/junit/xml-builder.rb
70
+ - lib/meson-junit/meson.rb
71
+ - lib/meson-junit/meson/test-log.rb
72
+ - lib/meson-junit/meson/test.rb
73
+ - test/data/testlog.json
74
+ - test/test_junit.rb
75
+ - test/test_meson.rb
76
+ homepage: https://github.com/pablotron/meson-junit
77
+ licenses:
78
+ - MIT
79
+ metadata:
80
+ bug_tracker_uri: https://github.com/pablotron/meson-junit/issues
81
+ documentation_uri: https://pablotron.github.io/meson-junit/
82
+ homepage_uri: https://github.com/pablotron/meson-junit
83
+ source_code_uri: https://github.com/pablotron/meson-junit
84
+ wiki_uri: https://github.com/pablotron/meson-junit/wiki
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.7.6.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Convert Meson testlog JSON to JUnit XML.
105
+ test_files: []