summaryrefslogtreecommitdiff
path: root/rtemsspec
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2023-11-21 11:13:16 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2023-11-21 11:15:25 +0100
commitaf3aea58121bece04748239baf47dd6bb052228c (patch)
tree31c200f2ad1a07ab0d29edafdc4fbe4217542f70 /rtemsspec
parent9e37fd1ade97d2bda951b0e15dd865452e01d6a1 (diff)
gcdaproducer: New
Diffstat (limited to 'rtemsspec')
-rw-r--r--rtemsspec/gcdaproducer.py95
-rw-r--r--rtemsspec/packagebuildfactory.py2
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/build/bsp.yml2
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/build/gcda.yml13
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/package-build.yml2
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/steps/gcda-producer.yml23
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/test-logs/coverage.yml15
-rw-r--r--rtemsspec/tests/test-files/pkg/build/bsp/f.gcda0
-rw-r--r--rtemsspec/tests/test-files/pkg/build/bsp/f.gcno0
-rw-r--r--rtemsspec/tests/test-files/pkg/test-log-coverage.json167
-rw-r--r--rtemsspec/tests/test_packagebuild.py21
11 files changed, 340 insertions, 0 deletions
diff --git a/rtemsspec/gcdaproducer.py b/rtemsspec/gcdaproducer.py
new file mode 100644
index 00000000..23215b0c
--- /dev/null
+++ b/rtemsspec/gcdaproducer.py
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: BSD-2-Clause
+""" This module provides a build step to produce gcda files. """
+
+# Copyright (C) 2022 embedded brains GmbH & Co. KG
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import base64
+import glob
+import json
+import logging
+import os
+import shutil
+from subprocess import run as subprocess_run
+
+from rtemsspec.directorystate import DirectoryState
+from rtemsspec.packagebuild import BuildItem
+
+
+class GCDAProducer(BuildItem):
+ """ Runs the gcov-tool to produce gcda files from a test log. """
+
+ def run(self):
+ build = self.input("build")
+ assert isinstance(build, DirectoryState)
+
+ destination = self.output("destination")
+ assert isinstance(destination, DirectoryState)
+
+ logging.info("%s: copy *.gcno files from '%s' to '%s'", self.uid,
+ build.directory, destination.directory)
+ for file in build.files():
+ assert not file.endswith(".gcda")
+ if file.endswith(".gcno"):
+ file_dest = file.replace(build.directory,
+ destination.directory)
+ os.makedirs(os.path.dirname(file_dest), exist_ok=True)
+ shutil.copy2(file, file_dest)
+
+ gcda_pattern = f"{build.directory}/**/*.gcda"
+ for file in glob.glob(gcda_pattern, recursive=True):
+ logging.warning(
+ "%s: remove unexpected *.gcda file in build directory: '%s'",
+ self.uid, file)
+ os.remove(file)
+
+ log = self.input("log")
+ assert isinstance(log, DirectoryState)
+
+ gcov_tool = self["gcov-tool"]
+ cwd = self["working-directory"]
+
+ with open(log.file, "r", encoding="utf-8") as src:
+ data = json.load(src)
+
+ for report in data["reports"]:
+ if "line-end-of-test" not in report["info"]:
+ # Do not use coverage data of failed tests
+ continue
+ begin = report.get("line-gcov-info-base64-begin", -1)
+ end = report.get("line-gcov-info-base64-end", -1)
+ if begin >= 0 and end >= 0:
+ logging.debug("%s: process: %s", self.uid,
+ report["executable"])
+ gcov_info = base64.b64decode("".join(report["output"][begin +
+ 1:end]))
+ subprocess_run([gcov_tool, "merge-stream"],
+ check=True,
+ cwd=cwd,
+ input=gcov_info)
+
+ logging.info("%s: move *.gcda files from '%s' to '%s'", self.uid,
+ build.directory, destination.directory)
+ for file in glob.glob(gcda_pattern, recursive=True):
+ file_dest = file.replace(build.directory, destination.directory)
+ os.replace(file, file_dest)
diff --git a/rtemsspec/packagebuildfactory.py b/rtemsspec/packagebuildfactory.py
index 28e52fa3..c38faf60 100644
--- a/rtemsspec/packagebuildfactory.py
+++ b/rtemsspec/packagebuildfactory.py
@@ -26,6 +26,7 @@
from rtemsspec.archiver import Archiver
from rtemsspec.directorystate import DirectoryState
+from rtemsspec.gcdaproducer import GCDAProducer
from rtemsspec.packagebuild import BuildItemFactory, PackageVariant
from rtemsspec.reposubset import RepositorySubset
from rtemsspec.rtems import RTEMSItemCache
@@ -39,6 +40,7 @@ def create_build_item_factory() -> BuildItemFactory:
""" Creates the default build item factory. """
factory = BuildItemFactory()
factory.add_constructor("qdp/build-step/archive", Archiver)
+ factory.add_constructor("qdp/build-step/gcda-producer", GCDAProducer)
factory.add_constructor("qdp/build-step/repository-subset",
RepositorySubset)
factory.add_constructor("qdp/build-step/rtems-item-cache", RTEMSItemCache)
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/build/bsp.yml b/rtemsspec/tests/spec-packagebuild/qdp/build/bsp.yml
index 109b8ed8..eba8a01b 100644
--- a/rtemsspec/tests/spec-packagebuild/qdp/build/bsp.yml
+++ b/rtemsspec/tests/spec-packagebuild/qdp/build/bsp.yml
@@ -12,6 +12,8 @@ files:
hash: null
- file: b.norun.exe
hash: null
+- file: f.gcno
+ hash: null
hash: null
links: []
patterns: []
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/build/gcda.yml b/rtemsspec/tests/spec-packagebuild/qdp/build/gcda.yml
new file mode 100644
index 00000000..687663e3
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/build/gcda.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}/gcda
+directory-state-type: generic
+enabled-by: true
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml b/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
index b97ccd14..3b8c2419 100644
--- a/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
+++ b/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
@@ -18,6 +18,8 @@ links:
- role: build-step
uid: steps/run-tests
- role: build-step
+ uid: steps/gcda-producer
+- role: build-step
uid: steps/archive
qdp-type: package-build
type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/steps/gcda-producer.yml b/rtemsspec/tests/spec-packagebuild/qdp/steps/gcda-producer.yml
new file mode 100644
index 00000000..957464f3
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/steps/gcda-producer.yml
@@ -0,0 +1,23 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-step-type: gcda-producer
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+description: |
+ Produces gcda files.
+enabled-by: gcda-producer
+gcov-tool: foo
+links:
+- hash: null
+ name: build
+ role: input
+ uid: ../build/bsp
+- hash: null
+ name: log
+ role: input
+ uid: ../test-logs/coverage
+- name: destination
+ role: output
+ uid: ../build/gcda
+qdp-type: build-step
+type: qdp
+working-directory: ${../build/bsp:/directory}
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/test-logs/coverage.yml b/rtemsspec/tests/spec-packagebuild/qdp/test-logs/coverage.yml
new file mode 100644
index 00000000..abc53ac2
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/test-logs/coverage.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/deployment-directory}
+directory-state-type: generic
+enabled-by: true
+files:
+- file: test-log-coverage.json
+ hash: null
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/test-files/pkg/build/bsp/f.gcda b/rtemsspec/tests/test-files/pkg/build/bsp/f.gcda
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/build/bsp/f.gcda
diff --git a/rtemsspec/tests/test-files/pkg/build/bsp/f.gcno b/rtemsspec/tests/test-files/pkg/build/bsp/f.gcno
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/build/bsp/f.gcno
diff --git a/rtemsspec/tests/test-files/pkg/test-log-coverage.json b/rtemsspec/tests/test-files/pkg/test-log-coverage.json
new file mode 100644
index 00000000..ef729a6a
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/test-log-coverage.json
@@ -0,0 +1,167 @@
+{
+ "duration": 272.82567146699876,
+ "end-time": "2023-07-11T09:52:01.875951",
+ "reports": [
+ {
+ "command-line": [
+ "sparc-rtems6-sis",
+ "-leon3",
+ "-extirq",
+ "12",
+ "-dumbio",
+ "-r",
+ "-m",
+ "2",
+ "ts-unit-no-clock-0.exe"
+ ],
+ "data-ranges": [
+ [
+ 41,
+ 2081
+ ]
+ ],
+ "duration": 11.234533725000801,
+ "executable": "ts-unit-no-clock-0.exe",
+ "executable-sha512": "605858485568eff4a0e4ebccbc979d113b226127a9e13bffd4d650255074a5cbeeb0ca671742038a365ded9f049ae750752b4ef3d757d13a3ee44f866f4e9271",
+ "info": {
+ "build": [
+ "RTEMS_SMP"
+ ],
+ "line-begin-of-test": 9,
+ "line-build": 12,
+ "line-end-of-test": 37,
+ "line-state": 11,
+ "line-tools": 13,
+ "line-version": 10,
+ "name": "TestsuitesUnitNoClock0",
+ "state": "EXPECTED_PASS",
+ "tools": "10.4.0 20220628 (RTEMS 6, RSB f8d79ee51187d98b88b8b7400ad77a991f53c8c0, Newlib b9898fc)",
+ "version": "6.0.0.1c46841ad34939632fee92894e8c73b4ea92f979"
+ },
+ "line-gcov-info-base64-begin": 40,
+ "line-gcov-info-base64-end": 42,
+ "output": [
+ "",
+ " SIS - SPARC/RISCV instruction simulator 2.30, copyright Jiri Gaisler 2020",
+ " Bug-reports to jiri@gaisler.se",
+ "",
+ " LEON3 emulation enabled, 2 cpus online, delta 50 clocks",
+ "",
+ " Loaded ts-unit-no-clock-0.exe, entry 0x40000000",
+ "",
+ "",
+ "*** BEGIN OF TEST TestsuitesUnitNoClock0 ***",
+ "*** TEST VERSION: 6.0.0.1c46841ad34939632fee92894e8c73b4ea92f979",
+ "*** TEST STATE: EXPECTED_PASS",
+ "*** TEST BUILD: RTEMS_SMP",
+ "*** TEST TOOLS: 10.4.0 20220628 (RTEMS 6, RSB f8d79ee51187d98b88b8b7400ad77a991f53c8c0, Newlib b9898fc)",
+ "A:TestsuitesUnitNoClock0",
+ "S:Platform:RTEMS",
+ "S:Compiler:10.4.0 20220628 (RTEMS 6, RSB f8d79ee51187d98b88b8b7400ad77a991f53c8c0, Newlib b9898fc)",
+ "S:Version:6.0.0.1c46841ad34939632fee92894e8c73b4ea92f979",
+ "S:BSP:gr712rc",
+ "S:BuildLabel:sparc/gr712rc/smp/qual-only-coverage",
+ "S:TargetHash:SHA256:5zrudgccHYC6azWEU3SRYUnkVXCeq9MufBd5zmfMeEg=",
+ "S:RTEMS_DEBUG:0",
+ "S:RTEMS_MULTIPROCESSING:0",
+ "S:RTEMS_POSIX_API:0",
+ "S:RTEMS_PROFILING:0",
+ "S:RTEMS_SMP:1",
+ "B:ScoreRbtreeUnitRbtree",
+ "E:ScoreRbtreeUnitRbtree:N:495132:F:0:D:1.164048",
+ "B:ScoreMsgqUnitMsgq",
+ "E:ScoreMsgqUnitMsgq:N:41:F:0:D:0.010895",
+ "B:RtemsConfigUnitConfig",
+ "E:RtemsConfigUnitConfig:N:1:F:0:D:0.001789",
+ "B:MisalignedBuiltinMemcpy",
+ "E:MisalignedBuiltinMemcpy:N:1:F:0:D:0.001803",
+ "Z:TestsuitesUnitNoClock0:C:4:N:495175:F:0:D:1.185642",
+ "Y:ReportHash:SHA256:a8e6RdqXa7Pt_SGpe7s2ezaVCSSY-j5PFEj6JTjrB4A=",
+ "",
+ "*** END OF TEST TestsuitesUnitNoClock0 ***",
+ "",
+ "",
+ "*** BEGIN OF GCOV INFO BASE64 ***",
+ "Z2NmbkIwNFIAAACVL29wdC==",
+ "*** END OF GCOV INFO BASE64 ***",
+ "cpu 0 in error mode (tt = 0x80)",
+ " 804542950 4003a5a0: 91d02000 ta 0x0"
+ ],
+ "start-time": "2023-07-11T09:47:29.059658"
+ },
+ {
+ "command-line": [
+ "sparc-rtems6-sis",
+ "-leon3",
+ "-extirq",
+ "12",
+ "-dumbio",
+ "-r",
+ "-m",
+ "2",
+ "ts-fatal-sparc-leon3-cache-snooping-disabled-boot.exe"
+ ],
+ "data-ranges": [
+ [
+ 35,
+ 1559
+ ]
+ ],
+ "duration": 1.5510155570082134,
+ "executable": "ts-fatal-sparc-leon3-cache-snooping-disabled-boot.exe",
+ "executable-sha512": "69f7d8cabeb23bba8c5b43fd658803f479d19a83cc858485ffc54bb727a0810bddb8ae61493839b4ade11094990e27c064426e45beaac3eadba01643ef120366",
+ "info": {
+ "build": [
+ "RTEMS_SMP"
+ ],
+ "line-begin-of-test": 9,
+ "line-build": 12,
+ "line-state": 11,
+ "line-tools": 13,
+ "line-version": 10,
+ "name": "TestsuitesBspsFatalSparcLeon3CacheSnoopingDisabledBoot",
+ "state": "EXPECTED_PASS",
+ "tools": "10.4.0 20220628 (RTEMS 6, RSB f8d79ee51187d98b88b8b7400ad77a991f53c8c0, Newlib b9898fc)",
+ "version": "6.0.0.1c46841ad34939632fee92894e8c73b4ea92f979"
+ }
+ },
+ {
+ "command-line": [
+ "sparc-rtems6-sis",
+ "-leon3",
+ "-extirq",
+ "12",
+ "-dumbio",
+ "-r",
+ "-m",
+ "2",
+ "ts-fatal-sparc-leon3-cache-snooping-disabled-boot.exe"
+ ],
+ "data-ranges": [
+ [
+ 35,
+ 1559
+ ]
+ ],
+ "duration": 1.5510155570082134,
+ "executable": "ts-fatal-sparc-leon3-cache-snooping-disabled-boot.exe",
+ "executable-sha512": "69f7d8cabeb23bba8c5b43fd658803f479d19a83cc858485ffc54bb727a0810bddb8ae61493839b4ade11094990e27c064426e45beaac3eadba01643ef120366",
+ "info": {
+ "build": [
+ "RTEMS_SMP"
+ ],
+ "line-begin-of-test": 9,
+ "line-end-of-test": 14,
+ "line-build": 12,
+ "line-state": 11,
+ "line-tools": 13,
+ "line-version": 10,
+ "name": "TestsuitesBspsFatalSparcLeon3CacheSnoopingDisabledBoot",
+ "state": "EXPECTED_PASS",
+ "tools": "10.4.0 20220628 (RTEMS 6, RSB f8d79ee51187d98b88b8b7400ad77a991f53c8c0, Newlib b9898fc)",
+ "version": "6.0.0.1c46841ad34939632fee92894e8c73b4ea92f979"
+ }
+ }
+ ],
+ "start-time": "2023-07-11T09:47:29.050266"
+}
diff --git a/rtemsspec/tests/test_packagebuild.py b/rtemsspec/tests/test_packagebuild.py
index 6ff9c8e4..cf6d91c2 100644
--- a/rtemsspec/tests/test_packagebuild.py
+++ b/rtemsspec/tests/test_packagebuild.py
@@ -35,6 +35,7 @@ import tarfile
from typing import List, NamedTuple
from rtemsspec.items import EmptyItem, Item, ItemCache, ItemGetValueContext
+import rtemsspec.gcdaproducer
from rtemsspec.packagebuild import BuildItem, BuildItemMapper, \
build_item_input, PackageBuildDirector
from rtemsspec.packagebuildfactory import create_build_item_factory
@@ -113,6 +114,13 @@ def _test_runner_subprocess(command, check, stdin, stdout, timeout):
return _Subprocess(b"u\r\nv\nw\n")
+def _gcov_tool(command, check, cwd, input):
+ assert command == ["foo", "merge-stream"]
+ assert check
+ assert input == b"gcfnB04R\x00\x00\x00\x95/opt"
+ (Path(cwd) / "file.gcda").touch()
+
+
def test_packagebuild(caplog, tmpdir, monkeypatch):
tmp_dir = Path(tmpdir)
item_cache = _create_item_cache(tmp_dir, Path("spec-packagebuild"))
@@ -403,3 +411,16 @@ def test_packagebuild(caplog, tmpdir, monkeypatch):
director.build_package(None, ["/qdp/steps/run-tests"])
log = get_and_clear_log(caplog)
assert f"use previous report for: {build_bsp.directory}/a.exe"
+
+ # Test GCDAProducer
+ variant["enabled"] = ["gcda-producer"]
+ test_log_coverage = director["/qdp/test-logs/coverage"]
+ test_log_coverage.load()
+ monkeypatch.setattr(rtemsspec.gcdaproducer, "subprocess_run", _gcov_tool)
+ director.build_package(None, None)
+ monkeypatch.undo()
+ log = get_and_clear_log(caplog)
+ assert f"/qdp/steps/gcda-producer: copy *.gcno files from '{tmp_dir}/pkg/build/bsp' to '{tmp_dir}/pkg/build/gcda'" in log
+ assert f"/qdp/steps/gcda-producer: remove unexpected *.gcda file in build directory: '{tmp_dir}/pkg/build/bsp/f.gcda'" in log
+ assert f"/qdp/steps/gcda-producer: process: ts-unit-no-clock-0.exe" in log
+ assert f"/qdp/steps/gcda-producer: move *.gcda files from '{tmp_dir}/pkg/build/bsp' to '{tmp_dir}/pkg/build/gcda'" in log