Skip to content

Commit 785ed2e

Browse files
committed
Migrate SCTF tests to integration tests
1 parent 5270e48 commit 785ed2e

18 files changed

Lines changed: 1189 additions & 4 deletions

.bazelrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ build --experimental_retain_test_configuration_across_testonly #https://github.c
2727
build:_common --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_unknown_linux_gnu
2828
build:_common --features=minimal_warnings --features=-strict_warnings --features=warnings_as_errors
2929

30+
# Suppress upstream issues in score_itf's dlt_daemon (dlt_shm.c has two
31+
# functions without prototypes). They are compiled in exec (tool) configuration
32+
# so --features=-strict_warnings above does not reach them.
33+
# TODO: Remove once score_itf ships a patched dlt_daemon.
34+
build --per_file_copt=external/score_itf.*@-Wno-missing-prototypes,-Wno-enum-int-mismatch
35+
3036
# Common flags for all builds
3137
common --@score_baselibs//score/memory/shared/flags:use_typedshmd=False
3238
common --@score_baselibs//score/mw/log/flags:KRemote_Logging=False

MODULE.bazel

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,22 @@ bazel_dep(name = "rapidjson", version = "1.1.0")
100100
bazel_dep(name = "score_baselibs", version = "0.2.7")
101101
bazel_dep(name = "score_communication", version = "0.2.1")
102102

103+
# Integration test dependencies
104+
105+
bazel_dep(name = "score_itf", version = "0.3.0", dev_dependency = True)
106+
bazel_dep(name = "rules_oci", version = "2.2.7", dev_dependency = True)
107+
bazel_dep(name = "rules_pkg", version = "1.2.0", dev_dependency = True)
108+
109+
oci = use_extension("@rules_oci//oci:extensions.bzl", "oci", dev_dependency = True)
110+
oci.pull(
111+
name = "ubuntu_24_04",
112+
digest = "sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30",
113+
image = "ubuntu",
114+
platforms = ["linux/amd64"],
115+
tag = "24.04",
116+
)
117+
use_repo(oci, "ubuntu_24_04", "ubuntu_24_04_linux_amd64")
118+
103119
# Rust dependencies
104120

105121
bazel_dep(name = "score_baselibs_rust", version = "0.1.0")

MODULE.bazel.lock

Lines changed: 204 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

score/datarouter/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,18 @@ filegroup(
370370
],
371371
)
372372

373+
filegroup(
374+
name = "integration_config_files",
375+
srcs = [
376+
"etc/log-channels.json",
377+
"etc/logging.json",
378+
"etc/raw-channels.json",
379+
],
380+
visibility = [
381+
"//score/test/integration:__subpackages__",
382+
],
383+
)
384+
373385
cc_library(
374386
name = "datarouter_options",
375387
srcs = [

score/mw/log/legacy_non_verbose_api/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cc_library(
3636
visibility = [
3737
"//platform/aas/ara/log:__subpackages__",
3838
"//score/mw/log:__subpackages__",
39+
"//score/test/integration/filters:__pkg__",
3940
"@score_baselibs//score/mw/log:__subpackages__",
4041
"@score_logging//score/datarouter:__subpackages__",
4142
],

score/test/integration/BUILD

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
14+
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
15+
load("@rules_python//python:defs.bzl", "py_library")
16+
load("@score_itf//bazel:py_itf_plugin.bzl", "py_itf_plugin")
17+
18+
# =============================================================================
19+
# Shared base layers (included in every test image by the macro)
20+
# =============================================================================
21+
pkg_tar(
22+
name = "dlt_pkg",
23+
srcs = [
24+
"@score_itf//third_party/dlt:dlt-receive",
25+
],
26+
visibility = ["//score/test/integration:__subpackages__"],
27+
)
28+
29+
pkg_tar(
30+
name = "datarouter_bin_pkg",
31+
srcs = ["//score/datarouter"],
32+
package_dir = "opt/datarouter/bin",
33+
)
34+
35+
pkg_tar(
36+
name = "datarouter_conf_pkg",
37+
srcs = ["//score/datarouter:integration_config_files"],
38+
package_dir = "opt/datarouter",
39+
strip_prefix = "/score/datarouter",
40+
)
41+
42+
pkg_tar(
43+
name = "datarouter_pkg",
44+
visibility = ["//score/test/integration:__subpackages__"],
45+
deps = [
46+
":datarouter_bin_pkg",
47+
":datarouter_conf_pkg",
48+
],
49+
)
50+
51+
# =============================================================================
52+
# Shared Python libraries and plugin
53+
# =============================================================================
54+
55+
py_library(
56+
name = "dlt_parser",
57+
srcs = ["dlt_parser.py"],
58+
imports = ["."],
59+
visibility = ["//score/test/integration:__subpackages__"],
60+
)
61+
62+
py_library(
63+
name = "logging_plugin_lib",
64+
srcs = ["logging_plugin.py"],
65+
imports = ["."],
66+
deps = ["@score_itf//score/itf/plugins:docker"],
67+
)
68+
69+
py_itf_plugin(
70+
name = "logging_plugin",
71+
enabled_plugins = [
72+
"logging_plugin",
73+
],
74+
py_library = ":logging_plugin_lib",
75+
visibility = ["//score/test/integration:__subpackages__"],
76+
)

score/test/integration/defs.bzl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
14+
load("@rules_oci//oci:defs.bzl", "oci_image", "oci_load")
15+
load("@score_itf//:defs.bzl", "py_itf_test")
16+
17+
def _extend_list_in_kwargs(kwargs, key, values):
18+
kwargs[key] = kwargs.get(key, []) + values
19+
return kwargs
20+
21+
def py_logging_itf_test(name, srcs, filesystem, **kwargs):
22+
"""Integration test macro for score_logging using Docker + DLT plugins.
23+
24+
Builds a per-test Docker image from the given filesystem tar layers
25+
(which must include the test app binaries/configs) combined with the
26+
shared base layers (DLT daemon, datarouter).
27+
28+
Args:
29+
name: Test target name.
30+
srcs: Python test source files.
31+
filesystem: A pkg_tar target containing the test-specific binaries
32+
and configuration files.
33+
**kwargs: Forwarded to py_itf_test (e.g. deps, data, tags, timeout).
34+
"""
35+
image_name = "_image_{}".format(name)
36+
image_loader = "_image_{}_loader".format(name)
37+
repo_tag = "{}:latest".format(name)
38+
39+
oci_image(
40+
name = image_name,
41+
base = "@ubuntu_24_04",
42+
tars = [
43+
"//score/test/integration:dlt_pkg",
44+
"//score/test/integration:datarouter_pkg",
45+
filesystem,
46+
],
47+
)
48+
49+
oci_load(
50+
name = image_loader,
51+
image = image_name,
52+
repo_tags = [repo_tag],
53+
)
54+
55+
_extend_list_in_kwargs(kwargs, "data", [image_loader])
56+
_extend_list_in_kwargs(kwargs, "args", [
57+
"--docker-image-bootstrap=$(location {})".format(image_loader),
58+
"--docker-image={}".format(repo_tag),
59+
])
60+
61+
if "tags" not in kwargs:
62+
kwargs["tags"] = []
63+
if "integration" not in kwargs["tags"]:
64+
kwargs["tags"] = kwargs["tags"] + ["integration"]
65+
66+
if "size" not in kwargs:
67+
kwargs["size"] = "enormous"
68+
69+
if "timeout" not in kwargs:
70+
kwargs["timeout"] = "short"
71+
72+
py_itf_test(
73+
name = name,
74+
srcs = srcs,
75+
plugins = [
76+
"@score_itf//score/itf/plugins:docker_plugin",
77+
"@score_itf//score/itf/plugins:dlt_plugin",
78+
"//score/test/integration:logging_plugin",
79+
],
80+
env = {"DOCKER_HOST": ""},
81+
**kwargs
82+
)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
14+
"""Structured parser for ``dlt-receive -a`` text output.
15+
16+
DLT text lines produced by ``dlt-receive -a`` have the form::
17+
18+
<timestamp> <ecuid> <apid> <ctid> <type> <subtype> <mode> <noar> <payload ...>
19+
20+
Field positions can vary (some fields may be absent in non-extended
21+
headers), but the *apid* and *ctid* fields always appear as a
22+
whitespace-separated pair. DLT pads short IDs to 4 characters with
23+
``-`` (e.g. ``TAP`` → ``TAP-``).
24+
25+
This module provides helpers that work on the *text* output captured by
26+
``dlt-receive -a --stdout-flush`` (which is what ``dlt_on_target``
27+
returns via ``receiver.get_output()``).
28+
"""
29+
30+
from collections import defaultdict
31+
from dataclasses import dataclass, field
32+
33+
34+
@dataclass
35+
class DltMessage:
36+
"""A single parsed DLT message."""
37+
38+
apid: str
39+
ctid: str
40+
payload: str
41+
raw_line: str
42+
43+
44+
def parse_messages(dlt_output: str, app_id: str) -> list[DltMessage]:
45+
"""Parse DLT text output and return messages matching *app_id*.
46+
47+
Args:
48+
dlt_output: Full text output from ``dlt-receive -a``.
49+
app_id: Application ID to filter on (without padding).
50+
51+
Returns:
52+
List of :class:`DltMessage` instances whose *apid* matches *app_id*.
53+
"""
54+
messages: list[DltMessage] = []
55+
for line in dlt_output.splitlines():
56+
parts = line.split()
57+
for i, part in enumerate(parts):
58+
if part.rstrip("-") == app_id and i + 1 < len(parts):
59+
ctid = parts[i + 1].rstrip("-")
60+
# Everything after apid and ctid is the payload
61+
payload = " ".join(parts[i + 2 :]) if i + 2 < len(parts) else ""
62+
messages.append(
63+
DltMessage(
64+
apid=app_id,
65+
ctid=ctid,
66+
payload=payload,
67+
raw_line=line,
68+
)
69+
)
70+
break
71+
return messages
72+
73+
74+
def count_messages_by_context(
75+
dlt_output: str,
76+
app_id: str,
77+
context_ids: set[str] | None = None,
78+
) -> tuple[dict[str, int], int]:
79+
"""Count messages per context ID for a given application.
80+
81+
Args:
82+
dlt_output: Full text output from ``dlt-receive -a``.
83+
app_id: Application ID to filter on.
84+
context_ids: Optional set of context IDs to include in the
85+
per-context breakdown. Messages with other context IDs are
86+
still included in the total count.
87+
88+
Returns:
89+
A ``(counts, total)`` tuple where *counts* maps context ID to
90+
message count and *total* is the overall number of messages from
91+
*app_id*.
92+
"""
93+
counts: dict[str, int] = defaultdict(int)
94+
total = 0
95+
for msg in parse_messages(dlt_output, app_id):
96+
total += 1
97+
if context_ids is None or msg.ctid in context_ids:
98+
counts[msg.ctid] += 1
99+
return dict(counts), total

0 commit comments

Comments
 (0)