From b746ae6b18732e5d851c5064aea1cbcced16aa0e Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:30:30 +0200 Subject: [PATCH 01/11] Add score_itf and OCI build dependencies --- MODULE.bazel | 15 ++++ MODULE.bazel.lock | 208 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 219 insertions(+), 4 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 11e26dca..da9612f7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -38,6 +38,21 @@ bazel_dep(name = "score_rust_policies", version = "0.0.3") bazel_dep(name = "score_process", version = "1.5.4", dev_dependency = True) bazel_dep(name = "score_platform", version = "0.5.5", dev_dependency = True) +bazel_dep(name = "score_itf", version = "0.4.0", dev_dependency = True) + +# OCI / Docker image rules for integration tests +bazel_dep(name = "rules_oci", version = "2.2.7", dev_dependency = True) +bazel_dep(name = "rules_pkg", version = "1.2.0", dev_dependency = True) + +oci = use_extension("@rules_oci//oci:extensions.bzl", "oci", dev_dependency = True) +oci.pull( + name = "ubuntu_24_04", + digest = "sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30", + image = "ubuntu", + platforms = ["linux/amd64"], + tag = "24.04", +) +use_repo(oci, "ubuntu_24_04", "ubuntu_24_04_linux_amd64") # Toolchains and extensions bazel_dep(name = "score_bazel_cpp_toolchains", version = "0.5.1", dev_dependency = True) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index a802e7c8..04dc3a02 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -35,6 +35,7 @@ "https://bcr.bazel.build/modules/aspect_bazel_lib/2.20.0/MODULE.bazel": "c5565bac49e1973227225b441fad1c938d498d83df62dc5da95b2fab0f0626a2", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.0/MODULE.bazel": "7fe0191f047d4fe4a4a46c1107e2350cbb58a8fc2e10913aa4322d3190dec0bf", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.0/source.json": "369df5b7f2eae82f200fff95cf1425f90dee90a0d0948122060b48150ff0e224", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.2/MODULE.bazel": "780d1a6522b28f5edb7ea09630748720721dfe27690d65a2d33aa7509de77e07", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14", @@ -425,10 +426,13 @@ "https://bcr.bazel.build/modules/rules_nodejs/6.3.3/MODULE.bazel": "b66eadebd10f1f1b25f52f95ab5213a57e82c37c3f656fcd9a57ad04d2264ce7", "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/MODULE.bazel": "7f9ea68a0ce6d82905ce9f74e76ab8a8b4531ed4c747018c9d76424ad0b3370d", "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/source.json": "6a6ca0940914d55c550d1417cad13a56c9900e23f651a762d8ccc5a64adcf661", + "https://bcr.bazel.build/modules/rules_oci/2.2.7/MODULE.bazel": "f6150e4b224d459f7f6523ef65967464ca4efdd266c7fbf2f5a2a51011957e0c", + "https://bcr.bazel.build/modules/rules_oci/2.2.7/source.json": "b099f02af330f47f19dc67fc9300ef6e1937a8c86882690db0e7a2fcea8c7f6b", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.1.0/MODULE.bazel": "9db8031e71b6ef32d1846106e10dd0ee2deac042bd9a2de22b4761b0c3036453", - "https://bcr.bazel.build/modules/rules_pkg/1.1.0/source.json": "fef768df13a92ce6067e1cd0cdc47560dace01354f1d921cfb1d632511f7d608", + "https://bcr.bazel.build/modules/rules_pkg/1.2.0/MODULE.bazel": "c7db3c2b407e673c7a39e3625dc05dc9f12d6682cbd82a3a5924a13b491eda7e", + "https://bcr.bazel.build/modules/rules_pkg/1.2.0/source.json": "9062e00845bf91a4247465d371baa837adf9b6ff44c542f73ba084f07667e1dc", "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483", @@ -458,7 +462,8 @@ "https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6", "https://bcr.bazel.build/modules/rules_python/1.5.1/MODULE.bazel": "acfe65880942d44a69129d4c5c3122d57baaf3edf58ae5a6bd4edea114906bf5", "https://bcr.bazel.build/modules/rules_python/1.8.3/MODULE.bazel": "f343e159b59701334be3914416b9f1b72845801ba47920fcb288af4ce8c5cce3", - "https://bcr.bazel.build/modules/rules_python/1.8.3/source.json": "e5439f308e3c6f79f318a0f87108db46fc575be89370c3dfb3f7e0eaa571a3f8", + "https://bcr.bazel.build/modules/rules_python/1.8.5/MODULE.bazel": "28b2d79ed8368d7d45b34bacc220e3c0b99cbcd9392641961b849e4c3f55dd30", + "https://bcr.bazel.build/modules/rules_python/1.8.5/source.json": "e261b03c8804f2582c9536013f987e1ea105a2b38c238aa2ac8f98fc34c8b18a", "https://bcr.bazel.build/modules/rules_rust/0.56.0/MODULE.bazel": "3295b00757db397122092322fe1e920be7f5c9fbfb8619138977e820f2cbbbae", "https://bcr.bazel.build/modules/rules_rust/0.61.0/MODULE.bazel": "0318a95777b9114c8740f34b60d6d68f9cfef61e2f4b52424ca626213d33787b", "https://bcr.bazel.build/modules/rules_rust/0.67.0/MODULE.bazel": "87c3816c4321352dcfd9e9e26b58e84efc5b21351ae3ef8fb5d0d57bde7237f5", @@ -537,6 +542,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.20.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.22.0/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.7.2/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "not found", @@ -823,9 +829,11 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_nodejs/6.3.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_nodejs/6.3.3/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_nodejs/6.5.2/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_oci/2.2.7/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/0.7.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.0.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.1.0/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.2.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_proto/4.0.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "not found", @@ -854,6 +862,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_python/1.4.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_python/1.5.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_python/1.8.3/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_python/1.8.5/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_rust/0.56.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_rust/0.61.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_rust/0.67.0/MODULE.bazel": "not found", @@ -886,6 +895,8 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.9/source.json": "58f24336e5e21d53551c0f0d304b0efa318eca031d296f33b998996c73573ce3", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.0.1/MODULE.bazel": "5955f4cf37228a9cdda7f6009b81db0446f005c618f4bc43665bfa45f2673ebc", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.0.1/source.json": "636a0e9413885bc483d98cd32ba14709fb694f8b07bd8a112641092dc699db90", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_itf/0.4.0/MODULE.bazel": "dd3e225e6fea37ab0c950888f4785faa4485215c15dfc5082ea8c577709db4e9", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_itf/0.4.0/source.json": "95fc7a5446339690dd40700ae3cab0492257cfd0269d402f42531af1e3278734", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_platform/0.5.5/MODULE.bazel": "070fa5fb10456e50675bcad2958fec0ed834f0aadbd0b71f25917f9e7edae2e2", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_platform/0.5.5/source.json": "1ce2e94f0e366eaae131091aaee2c16199c974e82959eec9d863c9b0c93f2fdc", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/1.3.2/MODULE.bazel": "a32390ef217cef9a811408b0a1c5aeed1398c377aa846f5d5416d7b95b4e4366", @@ -2334,10 +2345,199 @@ "recordedRepoMappingEntries": [] } }, + "@@rules_oci+//oci:extensions.bzl%oci": { + "general": { + "bzlTransitiveDigest": "kH8yGTr0UMGNfLvOd8gBxVC/iY5HHeVuhIZfOyZpCSU=", + "usagesDigest": "sRVlTEOffP1bFxYjWmpA8p+LdvK9HarT6DEnX61AroE=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "ubuntu_24_04_linux_amd64": { + "repoRuleId": "@@rules_oci+//oci/private:pull.bzl%oci_pull", + "attributes": { + "www_authenticate_challenges": {}, + "scheme": "https", + "registry": "index.docker.io", + "repository": "library/ubuntu", + "identifier": "sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30", + "platform": "linux/amd64", + "target_name": "ubuntu_24_04_linux_amd64", + "bazel_tags": [] + } + }, + "ubuntu_24_04": { + "repoRuleId": "@@rules_oci+//oci/private:pull.bzl%oci_alias", + "attributes": { + "target_name": "ubuntu_24_04", + "www_authenticate_challenges": {}, + "scheme": "https", + "registry": "index.docker.io", + "repository": "library/ubuntu", + "identifier": "sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30", + "platforms": { + "@@platforms//cpu:x86_64": "@ubuntu_24_04_linux_amd64" + }, + "bzlmod_repository": "ubuntu_24_04", + "reproducible": true + } + }, + "oci_crane_darwin_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "darwin_amd64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_darwin_arm64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "darwin_arm64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_arm64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_arm64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_armv6": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_armv6", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_i386": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_i386", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_s390x": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_s390x", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_amd64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_windows_armv6": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "windows_armv6", + "crane_version": "v0.18.0" + } + }, + "oci_crane_windows_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "windows_amd64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_toolchains": { + "repoRuleId": "@@rules_oci+//oci/private:toolchains_repo.bzl%toolchains_repo", + "attributes": { + "toolchain_type": "@rules_oci//oci:crane_toolchain_type", + "toolchain": "@oci_crane_{platform}//:crane_toolchain" + } + }, + "oci_regctl_darwin_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%regctl_repositories", + "attributes": { + "platform": "darwin_amd64" + } + }, + "oci_regctl_darwin_arm64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%regctl_repositories", + "attributes": { + "platform": "darwin_arm64" + } + }, + "oci_regctl_linux_arm64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%regctl_repositories", + "attributes": { + "platform": "linux_arm64" + } + }, + "oci_regctl_linux_s390x": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%regctl_repositories", + "attributes": { + "platform": "linux_s390x" + } + }, + "oci_regctl_linux_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%regctl_repositories", + "attributes": { + "platform": "linux_amd64" + } + }, + "oci_regctl_windows_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%regctl_repositories", + "attributes": { + "platform": "windows_amd64" + } + }, + "oci_regctl_toolchains": { + "repoRuleId": "@@rules_oci+//oci/private:toolchains_repo.bzl%toolchains_repo", + "attributes": { + "toolchain_type": "@rules_oci//oci:regctl_toolchain_type", + "toolchain": "@oci_regctl_{platform}//:regctl_toolchain" + } + } + }, + "moduleExtensionMetadata": { + "explicitRootModuleDirectDeps": [], + "explicitRootModuleDirectDevDeps": [ + "ubuntu_24_04", + "ubuntu_24_04_linux_amd64" + ], + "useAllRepos": "NO", + "reproducible": false + }, + "recordedRepoMappingEntries": [ + [ + "aspect_bazel_lib+", + "bazel_tools", + "bazel_tools" + ], + [ + "bazel_features+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_oci+", + "aspect_bazel_lib", + "aspect_bazel_lib+" + ], + [ + "rules_oci+", + "bazel_features", + "bazel_features+" + ], + [ + "rules_oci+", + "bazel_skylib", + "bazel_skylib+" + ] + ] + } + }, "@@rules_python+//python/extensions:config.bzl%config": { "general": { "bzlTransitiveDigest": "V+wrDxg73HRC54yN8US3eQCsE4GnYCcebkee7voYa1E=", - "usagesDigest": "HZ99ezJBkgjKcxXQ3OBxGgesUIMF6eg7E0TUNOait2I=", + "usagesDigest": "lDbpRfhoWmZCHSaNxwZv/8fF2y0wu2th0G0f/uqX7VM=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -2572,7 +2772,7 @@ "@@rules_python+//python/uv:uv.bzl%uv": { "general": { "bzlTransitiveDigest": "85utVTiuGY4Ut0FgpNLZvwD42nCeVn+J4Cit6fSR5OM=", - "usagesDigest": "XRYYokHTb3p1WwpZj2sncZ1bh8zJfO4YrKJ2PkapnO8=", + "usagesDigest": "c4BCoL7WnccEomzDYulDuOys9pd6N93KaNI4mTVbqi0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, From 5ae46c1ac4c14e05673e7f89ddcd3b1e37437656 Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:30:47 +0200 Subject: [PATCH 02/11] Suppress score_baselibs deprecation warnings --- .bazelrc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.bazelrc b/.bazelrc index 4e27c368..24afacc2 100644 --- a/.bazelrc +++ b/.bazelrc @@ -38,6 +38,11 @@ common --//score/datarouter/build_configuration_flags:enable_dynamic_configurati common --//score/datarouter/build_configuration_flags:file_transfer=False common --//score/datarouter/build_configuration_flags:use_local_vlan=True +# TODO: Remove once score_baselibs fixes deprecated StringLiteral and +# ignored-attributes warnings (string_comparison_adaptor.h, text_format.h, etc.) +build --copt=-Wno-deprecated-declarations +build --copt=-Wno-ignored-attributes + # Base QNX config (shared flags) common:qnx --credential_helper=*.qnx.com=%workspace%/scripts/internal/qnx_creds.py common:qnx --credential_helper_timeout="60s" From dcc8f7b3aa182481ee01ef65220b7cce5b3cb93b Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:31:13 +0200 Subject: [PATCH 03/11] Add shared ITF infrastructure for logging integration tests --- score/datarouter/BUILD | 16 ++++ score/test/itf/BUILD | 98 ++++++++++++++++++++++++ score/test/itf/defs.bzl | 82 ++++++++++++++++++++ score/test/itf/dlt_parser.py | 99 ++++++++++++++++++++++++ score/test/itf/logging_plugin.py | 125 +++++++++++++++++++++++++++++++ 5 files changed, 420 insertions(+) create mode 100644 score/test/itf/BUILD create mode 100644 score/test/itf/defs.bzl create mode 100644 score/test/itf/dlt_parser.py create mode 100644 score/test/itf/logging_plugin.py diff --git a/score/datarouter/BUILD b/score/datarouter/BUILD index c28de93b..a99db96b 100644 --- a/score/datarouter/BUILD +++ b/score/datarouter/BUILD @@ -367,6 +367,22 @@ filegroup( "//platform/aas/tools/sctf:__subpackages__", "//pqr/abc/abc-lmn/config/project/cpu/pas/datarouter:__pkg__", "//score/datarouter/test:__subpackages__", + "//score/test/itf:__subpackages__", + ], +) + +filegroup( + name = "all_config_files", + srcs = [ + "etc/key_value_storage_list.json", + "etc/log-channels.json", + "etc/logging.json", + "etc/persistent-database-override.json", + "etc/persistent-logging.json", + "etc/raw-channels.json", + ], + visibility = [ + "//score/test/itf:__subpackages__", ], ) diff --git a/score/test/itf/BUILD b/score/test/itf/BUILD new file mode 100644 index 00000000..3689de99 --- /dev/null +++ b/score/test/itf/BUILD @@ -0,0 +1,98 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("@rules_python//python:defs.bzl", "py_library") +load("@score_itf//bazel:py_itf_plugin.bzl", "py_itf_plugin") + +# ============================================================================= +# Shared base layers (included in every test image by the macro) +# ============================================================================= + +# --- DLT daemon binaries (from @score_itf) --- +pkg_tar( + name = "dlt_bins_pkg", + srcs = [ + "@score_itf//third_party/dlt:dlt-adaptor-stdin", + "@score_itf//third_party/dlt:dlt-daemon", + "@score_itf//third_party/dlt:dlt-receive", + ], + package_dir = "usr/bin", +) + +pkg_tar( + name = "dlt_conf_pkg", + srcs = [ + "@score_itf//third_party/dlt:dlt-daemon-conf", + ], + package_dir = "etc", +) + +pkg_tar( + name = "dlt_pkg", + visibility = ["//score/test/itf:__subpackages__"], + deps = [ + ":dlt_bins_pkg", + ":dlt_conf_pkg", + ], +) + +# --- Datarouter binary + config --- +pkg_tar( + name = "datarouter_bin_pkg", + srcs = ["//score/datarouter"], + package_dir = "opt/datarouter/bin", +) + +pkg_tar( + name = "datarouter_conf_pkg", + srcs = ["//score/datarouter:all_config_files"], + package_dir = "opt/datarouter", + strip_prefix = "/score/datarouter", +) + +pkg_tar( + name = "datarouter_pkg", + visibility = ["//score/test/itf:__subpackages__"], + deps = [ + ":datarouter_bin_pkg", + ":datarouter_conf_pkg", + ], +) + +# ============================================================================= +# Shared Python libraries and plugin +# ============================================================================= + +py_library( + name = "dlt_parser", + srcs = ["dlt_parser.py"], + imports = ["."], + visibility = ["//score/test/itf:__subpackages__"], +) + +py_library( + name = "logging_plugin_lib", + srcs = ["logging_plugin.py"], + imports = ["."], + deps = ["@score_itf//score/itf/plugins:docker"], +) + +py_itf_plugin( + name = "logging_plugin", + enabled_plugins = [ + "logging_plugin", + ], + py_library = ":logging_plugin_lib", + visibility = ["//score/test/itf:__subpackages__"], +) diff --git a/score/test/itf/defs.bzl b/score/test/itf/defs.bzl new file mode 100644 index 00000000..4efc41b1 --- /dev/null +++ b/score/test/itf/defs.bzl @@ -0,0 +1,82 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_oci//oci:defs.bzl", "oci_image", "oci_load") +load("@score_itf//:defs.bzl", "py_itf_test") + +def _extend_list_in_kwargs(kwargs, key, values): + kwargs[key] = kwargs.get(key, []) + values + return kwargs + +def py_logging_itf_test(name, srcs, filesystem, **kwargs): + """Integration test macro for score_logging using Docker + DLT plugins. + + Builds a per-test Docker image from the given filesystem tar layers + (which must include the test app binaries/configs) combined with the + shared base layers (DLT daemon, datarouter). + + Args: + name: Test target name. + srcs: Python test source files. + filesystem: A pkg_tar target containing the test-specific binaries + and configuration files. + **kwargs: Forwarded to py_itf_test (e.g. deps, data, tags, timeout). + """ + image_name = "_image_{}".format(name) + image_loader = "_image_{}_loader".format(name) + repo_tag = "{}:latest".format(name) + + oci_image( + name = image_name, + base = "@ubuntu_24_04", + tars = [ + "//score/test/itf:dlt_pkg", + "//score/test/itf:datarouter_pkg", + filesystem, + ], + ) + + oci_load( + name = image_loader, + image = image_name, + repo_tags = [repo_tag], + ) + + _extend_list_in_kwargs(kwargs, "data", [image_loader]) + _extend_list_in_kwargs(kwargs, "args", [ + "--docker-image-bootstrap=$(location {})".format(image_loader), + "--docker-image={}".format(repo_tag), + ]) + + if "tags" not in kwargs: + kwargs["tags"] = [] + if "integration" not in kwargs["tags"]: + kwargs["tags"] = kwargs["tags"] + ["integration"] + + if "size" not in kwargs: + kwargs["size"] = "enormous" + + if "timeout" not in kwargs: + kwargs["timeout"] = "short" + + py_itf_test( + name = name, + srcs = srcs, + plugins = [ + "@score_itf//score/itf/plugins:docker_plugin", + "@score_itf//score/itf/plugins:dlt_plugin", + "//score/test/itf:logging_plugin", + ], + env = {"DOCKER_HOST": ""}, + **kwargs + ) diff --git a/score/test/itf/dlt_parser.py b/score/test/itf/dlt_parser.py new file mode 100644 index 00000000..d6c607fb --- /dev/null +++ b/score/test/itf/dlt_parser.py @@ -0,0 +1,99 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Structured parser for ``dlt-receive -a`` text output. + +DLT text lines produced by ``dlt-receive -a`` have the form:: + + + +Field positions can vary (some fields may be absent in non-extended +headers), but the *apid* and *ctid* fields always appear as a +whitespace-separated pair. DLT pads short IDs to 4 characters with +``-`` (e.g. ``TAP`` → ``TAP-``). + +This module provides helpers that work on the *text* output captured by +``dlt-receive -a --stdout-flush`` (which is what ``dlt_on_target`` +returns via ``receiver.get_output()``). +""" + +from collections import defaultdict +from dataclasses import dataclass, field + + +@dataclass +class DltMessage: + """A single parsed DLT message.""" + + apid: str + ctid: str + payload: str + raw_line: str + + +def parse_messages(dlt_output: str, app_id: str) -> list[DltMessage]: + """Parse DLT text output and return messages matching *app_id*. + + Args: + dlt_output: Full text output from ``dlt-receive -a``. + app_id: Application ID to filter on (without padding). + + Returns: + List of :class:`DltMessage` instances whose *apid* matches *app_id*. + """ + messages: list[DltMessage] = [] + for line in dlt_output.splitlines(): + parts = line.split() + for i, part in enumerate(parts): + if part.rstrip("-") == app_id and i + 1 < len(parts): + ctid = parts[i + 1].rstrip("-") + # Everything after apid and ctid is the payload + payload = " ".join(parts[i + 2 :]) if i + 2 < len(parts) else "" + messages.append( + DltMessage( + apid=app_id, + ctid=ctid, + payload=payload, + raw_line=line, + ) + ) + break + return messages + + +def count_messages_by_context( + dlt_output: str, + app_id: str, + context_ids: set[str] | None = None, +) -> tuple[dict[str, int], int]: + """Count messages per context ID for a given application. + + Args: + dlt_output: Full text output from ``dlt-receive -a``. + app_id: Application ID to filter on. + context_ids: Optional set of context IDs to include in the + per-context breakdown. Messages with other context IDs are + still included in the total count. + + Returns: + A ``(counts, total)`` tuple where *counts* maps context ID to + message count and *total* is the overall number of messages from + *app_id*. + """ + counts: dict[str, int] = defaultdict(int) + total = 0 + for msg in parse_messages(dlt_output, app_id): + total += 1 + if context_ids is None or msg.ctid in context_ids: + counts[msg.ctid] += 1 + return dict(counts), total diff --git a/score/test/itf/logging_plugin.py b/score/test/itf/logging_plugin.py new file mode 100644 index 00000000..8a8cb422 --- /dev/null +++ b/score/test/itf/logging_plugin.py @@ -0,0 +1,125 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Shared pytest plugin for score_logging integration tests. + +Provides Docker container configuration, a datarouter lifecycle fixture, +and DLT utility functions used by all logging ITF tests. +""" + +import logging +import os +import tempfile +import time +from contextlib import contextmanager + +import pytest +from score.itf.plugins.dlt.dlt_receive import Protocol +from score.itf.plugins.dlt.dlt_window import DltLogRecord + +LOGGER = logging.getLogger(__name__) + +# UDP multicast group addresses for DLT — dlt-receive joins these groups +# to capture messages sent by the datarouter. +DLT_MULTICAST_IPS = ["239.255.42.99"] + +# Settle time (seconds) after dlt-receive starts, to allow the multicast group +# join to propagate before the application under test begins sending. +_DLT_RECEIVER_SETTLE_DELAY = 0.2 + +# Datarouter readiness polling parameters. +_DATAROUTER_READY_TIMEOUT = 5.0 +_DATAROUTER_READY_INTERVAL = 0.1 + + +def _wait_for_datarouter(target, timeout=_DATAROUTER_READY_TIMEOUT): + """Poll /proc/net/unix for the datarouter abstract socket to appear.""" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + exit_code, _ = target.execute("grep -q datarouter /proc/net/unix") + if exit_code == 0: + LOGGER.info("Datarouter socket detected") + return + time.sleep(_DATAROUTER_READY_INTERVAL) + raise TimeoutError(f"Datarouter socket not found within {timeout}s") + + +def download_dlt(target, remote_path): + """Download a .dlt file from the target and return a DltLogRecord for querying. + + The file is stored in a temporary directory that persists for the process + lifetime. Use ``record.find()`` to query verbose/non-verbose messages. + """ + local_dir = tempfile.mkdtemp(prefix="dlt_") + local_path = os.path.join(local_dir, os.path.basename(remote_path)) + target.download(remote_path, local_path) + LOGGER.info(f"Downloaded {remote_path}: {os.path.getsize(local_path)} bytes") + return DltLogRecord(local_path) + + +@pytest.fixture(scope="session") +def docker_configuration(): + """Configure Docker container for DLT integration tests.""" + return { + "init": True, + "shm_size": "2G", + } + + +@pytest.fixture(scope="function") +def datarouter_on_target(target): + """Start the datarouter (DLT daemon) on the Docker target. + + Launches the datarouter in non-adaptive mode as a background process, + polls for socket readiness, and stops it on teardown. + """ + proc = target.execute_async( + "/opt/datarouter/bin/datarouter", + args=["--no_adaptive_runtime"], + cwd="/opt/datarouter", + ) + _wait_for_datarouter(target) + yield target + if proc.is_running(): + proc.stop() + + +@pytest.fixture(scope="function") +def dlt_capture(target, dlt_on_target): + """Start a DLT receiver with deterministic multicast reception. + + Wraps the framework's ``dlt_on_target`` with default multicast parameters + and a settle delay to ensure the multicast group join propagates before the + application under test begins sending. + + Usage in tests:: + + with dlt_capture() as receiver: + target.execute(app_cmd) + + output = receiver.get_output() + """ + + @contextmanager + def _start(protocol=Protocol.UDP, host_ip=None, multicast_ips=None): + if host_ip is None: + host_ip = target.get_ip() + if multicast_ips is None: + multicast_ips = DLT_MULTICAST_IPS + with dlt_on_target( + protocol, host_ip=host_ip, multicast_ips=multicast_ips + ) as receiver: + time.sleep(_DLT_RECEIVER_SETTLE_DELAY) + yield receiver + + return _start From 2f40e5e3a5030004960768c6066ae5f46652f41f Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:31:32 +0200 Subject: [PATCH 04/11] Add mw_log integration tests --- score/test/itf/mw_log/BUILD | 51 +++++++ score/test/itf/mw_log/etc/logging.json | 7 + score/test/itf/mw_log/logging_app.cpp | 96 ++++++++++++++ score/test/itf/mw_log/test_mw_log.py | 175 +++++++++++++++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 score/test/itf/mw_log/BUILD create mode 100644 score/test/itf/mw_log/etc/logging.json create mode 100644 score/test/itf/mw_log/logging_app.cpp create mode 100644 score/test/itf/mw_log/test_mw_log.py diff --git a/score/test/itf/mw_log/BUILD b/score/test/itf/mw_log/BUILD new file mode 100644 index 00000000..9131921c --- /dev/null +++ b/score/test/itf/mw_log/BUILD @@ -0,0 +1,51 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//score/test/itf:defs.bzl", "py_logging_itf_test") + +cc_binary( + name = "logging_app", + srcs = ["logging_app.cpp"], + deps = ["//score/mw/log"], +) + +pkg_tar( + name = "logging_app_bin_pkg", + srcs = [":logging_app"], + package_dir = "opt/test_apps/logging_app/bin", +) + +pkg_tar( + name = "logging_app_config_pkg", + srcs = ["etc/logging.json"], + package_dir = "opt/test_apps/logging_app/etc", +) + +pkg_tar( + name = "logging_app_filesystem", + deps = [ + ":logging_app_bin_pkg", + ":logging_app_config_pkg", + ], +) + +py_logging_itf_test( + name = "test_mw_log", + srcs = ["test_mw_log.py"], + filesystem = ":logging_app_filesystem", + deps = [ + "//score/test/itf:dlt_parser", + "@score_itf//third_party/python_dlt", + ], +) diff --git a/score/test/itf/mw_log/etc/logging.json b/score/test/itf/mw_log/etc/logging.json new file mode 100644 index 00000000..66d1e45a --- /dev/null +++ b/score/test/itf/mw_log/etc/logging.json @@ -0,0 +1,7 @@ +{ + "appId": "EXA", + "appDesc": "Example App", + "logMode": "kConsole|kRemote|kFile", + "logLevel": "kVerbose", + "logLevelThresholdConsole": "kVerbose" +} diff --git a/score/test/itf/mw_log/logging_app.cpp b/score/test/itf/mw_log/logging_app.cpp new file mode 100644 index 00000000..e37e8b50 --- /dev/null +++ b/score/test/itf/mw_log/logging_app.cpp @@ -0,0 +1,96 @@ +// ******************************************************************************* +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +#include "score/mw/log/logging.h" + +#include +#include +#include +#include + +namespace log = score::mw::log; + +namespace { + +void DoLogging() { + const std::string SWID{"Logging Application"}; + log::LogInfo() << SWID << "DoLogging"; + log::LogInfo() << "val_bool" << true; + + // Unsigned integers + const uint8_t val_uint8t = 123; + const uint16_t val_uint16t = 1234; + const uint32_t val_uint32t = 12345; + const uint64_t val_uint64t = 123456; + log::LogDebug() << "val_uint8t" << val_uint8t << "val_uint16t" << val_uint16t + << "val_uint32t" << val_uint32t << "val_uint64t" << val_uint64t; + + log::LogWarn() << "val_uint8tmax" << UINT8_MAX << "val_uint16tmax" << UINT16_MAX + << "val_uint32tmax" << UINT32_MAX << "val_uint64tmax" << UINT64_MAX; + + // Signed integers + const int8_t val_int8t = -34; + const int16_t val_int16t = -14576; + const int32_t val_int32t = -2147483640; + const int64_t val_int64t = -9223372036854775700LL; + log::LogFatal() << "val_int8t" << val_int8t << "val_int16t" << val_int16t + << "val_int32t" << val_int32t << "val_int64t" << val_int64t; + + log::LogWarn() << "val_int8tmax" << INT8_MAX << "val_int16tmax" << INT16_MAX + << "val_int32tmax" << INT32_MAX << "val_int64tmax" << INT64_MAX; + + log::LogDebug() << "val_uint8t" << val_uint8t << "val_uint16t" << val_uint16t + << "val_uint32t" << val_uint32t << "val_uint64t" << val_uint64t; + + log::LogWarn() << "val_int8tmin" << INT8_MIN << "val_int16tmin" << INT16_MIN + << "val_int32tmin" << INT32_MIN << "val_int64tmin" << INT64_MIN; + + const int32_t val_int8tminplusint8t = static_cast(INT8_MIN) - val_int8t; + const int32_t val_int16tminplusint16t = static_cast(INT16_MIN) - val_int16t; + const int32_t val_int32tminplusint32t = INT32_MIN - val_int32t; + const int64_t val_int64tminplusint64t = INT64_MIN - val_int64t; + log::LogError() << "val_int8tminplusint8t" << val_int8tminplusint8t + << "val_int16tminplusint16t" << val_int16tminplusint16t + << "val_int32tminplusint32t" << val_int32tminplusint32t + << "val_int64tminplusint64t" << val_int64tminplusint64t; + + // String and double + log::LogFatal() << "val_string" << "Logging"; + log::LogFatal() << "val_double" << 93454.6; + + // Hex values + log::LogInfo() << "log_hex_8" << log::LogHex8{10} + << "log_hex_16" << log::LogHex16{9876} + << "log_hex_32" << log::LogHex32{543210987} + << "log_hex_64" << log::LogHex64{654321098765432109ULL}; + + // Bin values + log::LogWarn() << "log_bin_8" << log::LogBin8{8} + << "log_bin_16" << log::LogBin16{9012} + << "log_bin_32" << log::LogBin32{3456789012UL} + << "log_bin_64" << log::LogBin64{3456789012345678901ULL}; + + // Raw buffer + log::LogFatal() << "log_raw_buffer" << log::LogRawBuffer{"raw", 3}; + + // Slog2 message + log::LogFatal() << "log_slog2_message" << log::LogSlog2Message{11, "slog2_message"}; +} + +} // namespace + +int main() { + DoLogging(); + sleep(1); + return 0; +} diff --git a/score/test/itf/mw_log/test_mw_log.py b/score/test/itf/mw_log/test_mw_log.py new file mode 100644 index 00000000..180e4e67 --- /dev/null +++ b/score/test/itf/mw_log/test_mw_log.py @@ -0,0 +1,175 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test for mw::log with all data types. + +Verifies that the logging_app binary correctly sends DLT messages containing +all supported data types (bool, integers, hex, bin, raw buffer, slog2, etc.) +via the datarouter, and that they are received by dlt-receive with correct +content. Also verifies console logging output and file (.dlt) logging. +""" + +import logging +import os +import tempfile + +import dlt.dlt as python_dlt +from dlt_parser import parse_messages + + +LOGGER = logging.getLogger(__name__) + +LOGGING_APP_ID = "EXA" +LOGGING_APP_CMD = "cd /opt/test_apps/logging_app && ./bin/logging_app" + +# Expected substrings that must appear in the DLT output from our app. +# These match the structured content of each message emitted by logging_app.cpp +# as formatted by dlt-receive -a text output. +# NOTE: dlt-receive -a renders bool as 1/0 (not True/False), +# UINT64_MAX as -1 (signed), and raw buffers as hex bytes. +VALUES_TO_CHECK_REMOTE = [ + "Logging Application DoLogging", + "val_bool 1", + "val_uint8t 123 val_uint16t 1234 val_uint32t 12345 val_uint64t 123456", + "val_uint8tmax 255 val_uint16tmax 65535 val_uint32tmax 4294967295 val_uint64tmax -1", + "val_int8t -34 val_int16t -14576 val_int32t -2147483640 val_int64t -9223372036854775700", + "val_int8tmax 127 val_int16tmax 32767 val_int32tmax 2147483647 val_int64tmax 9223372036854775807", + "val_int8tmin -128 val_int16tmin -32768 val_int32tmin -2147483648 val_int64tmin -9223372036854775808", + "val_int8tminplusint8t -94 val_int16tminplusint16t -18192 val_int32tminplusint32t -8 val_int64tminplusint64t -108", + "val_string Logging", + "val_double 93454.6", + "log_hex_8 10 log_hex_16 9876 log_hex_32 543210987 log_hex_64 654321098765432109", + "log_bin_8 8 log_bin_16 9012 log_bin_32 3456789012 log_bin_64 3456789012345678901", + "log_raw_buffer", + "log_slog2_message slog2_message", +] + +# Expected substrings for console output (captured from the app's stdout). +# Console output differs from dlt-receive -a in several ways: +# - val_bool renders as True (not 1) +# - UINT64_MAX renders as 18446744073709551615 (unsigned) not -1 +# - val_double has more decimal places (93454.600000) +# - log_raw_buffer renders as contiguous hex string (726177) +VALUES_TO_CHECK_CONSOLE = [ + "Logging Application DoLogging", + "val_bool True", + "val_uint8t 123 val_uint16t 1234 val_uint32t 12345 val_uint64t 123456", + "val_uint8tmax 255 val_uint16tmax 65535 val_uint32tmax 4294967295 val_uint64tmax 18446744073709551615", + "val_int8t -34 val_int16t -14576 val_int32t -2147483640 val_int64t -9223372036854775700", + "val_int8tmax 127 val_int16tmax 32767 val_int32tmax 2147483647 val_int64tmax 9223372036854775807", + "val_int8tmin -128 val_int16tmin -32768 val_int32tmin -2147483648 val_int64tmin -9223372036854775808", + "val_int8tminplusint8t -94 val_int16tminplusint16t -18192 val_int32tminplusint32t -8 val_int64tminplusint64t -108", + "val_string Logging", + "val_double 93454.600000", + "log_hex_8 10 log_hex_16 9876 log_hex_32 543210987 log_hex_64 654321098765432109", + "log_bin_8 8 log_bin_16 9012 log_bin_32 3456789012 log_bin_64 3456789012345678901", + "log_raw_buffer 726177", + "log_slog2_message slog2_message", +] + +# Expected substrings for DLT binary file output parsed by python-dlt. +# Differs from dlt-receive -a (remote) in: +# - UINT64_MAX renders as 18446744073709551615 (unsigned, not -1) +# - log_raw_buffer renders as 72'61'77 (apostrophe-separated hex) +VALUES_TO_CHECK_FILE = [ + "Logging Application DoLogging", + "val_bool 1", + "val_uint8t 123 val_uint16t 1234 val_uint32t 12345 val_uint64t 123456", + "val_uint8tmax 255 val_uint16tmax 65535 val_uint32tmax 4294967295 val_uint64tmax 18446744073709551615", + "val_int8t -34 val_int16t -14576 val_int32t -2147483640 val_int64t -9223372036854775700", + "val_int8tmax 127 val_int16tmax 32767 val_int32tmax 2147483647 val_int64tmax 9223372036854775807", + "val_int8tmin -128 val_int16tmin -32768 val_int32tmin -2147483648 val_int64tmin -9223372036854775808", + "val_int8tminplusint8t -94 val_int16tminplusint16t -18192 val_int32tminplusint32t -8 val_int64tminplusint64t -108", + "val_string Logging", + "val_double 93454.6", + "log_hex_8 10 log_hex_16 9876 log_hex_32 543210987 log_hex_64 654321098765432109", + "log_bin_8 8 log_bin_16 9012 log_bin_32 3456789012 log_bin_64 3456789012345678901", + "log_raw_buffer", + "log_slog2_message slog2_message", +] + + +def test_mw_log_remote_logging(target, datarouter_on_target, dlt_capture): + """Verify all data types are correctly logged and received via DLT.""" + with dlt_capture() as receiver: + target.execute(LOGGING_APP_CMD) + + output = receiver.get_output() + LOGGER.info(f"DLT output length: {len(output)} chars") + + messages = parse_messages(output, LOGGING_APP_ID) + LOGGER.info(f"Received {len(messages)} messages from {LOGGING_APP_ID}") + for msg in messages: + LOGGER.info(f" [{msg.ctid}] {msg.payload}") + + assert len(messages) > 0, "No DLT messages received from logging_app" + + app_output = "\n".join(msg.payload for msg in messages) + missing = [v for v in VALUES_TO_CHECK_REMOTE if v not in app_output] + assert not missing, f"Missing expected values in DLT output: {missing}" + + +def test_mw_log_console_logging(target, datarouter_on_target): + """Verify all data types are correctly logged to console (stdout). + + The app writes DLT-formatted log lines to stdout when logMode includes + kConsole. Console rendering differs from dlt-receive -a in how certain + types are formatted (unsigned vs signed integers, binary representations, + raw buffer hex encoding, double precision). + """ + proc = target.execute_async( + "/opt/test_apps/logging_app/bin/logging_app", + cwd="/opt/test_apps/logging_app", + ) + proc.wait(timeout_s=10) + console_output = proc.get_output() + LOGGER.info(f"Console output length: {len(console_output)} chars") + LOGGER.info(f"Console output:\n{console_output}") + + assert len(console_output) > 0, "No console output captured from logging_app" + + missing = [v for v in VALUES_TO_CHECK_CONSOLE if v not in console_output] + assert not missing, f"Missing expected values in console output: {missing}" + + +def test_mw_log_file_logging(target, datarouter_on_target): + """Verify all data types are correctly logged to a .dlt file on disk. + + The app writes DLT binary messages to /tmp/EXA.dlt when logMode includes + kFile. The test downloads the file and parses it with python-dlt to verify + that all expected values are present in the message payloads. + """ + target.execute(LOGGING_APP_CMD) + + with tempfile.TemporaryDirectory() as tmpdir: + local_dlt = os.path.join(tmpdir, "EXA.dlt") + target.download("/tmp/EXA.dlt", local_dlt) + LOGGER.info(f"Downloaded DLT file: {os.path.getsize(local_dlt)} bytes") + + messages = python_dlt.load(local_dlt, None) + payloads = [] + for msg in messages: + if getattr(msg, "apid", None) == LOGGING_APP_ID: + payload = msg.payload_decoded + if isinstance(payload, bytes): + payload = payload.decode(errors="ignore") + payloads.append(str(payload)) + + LOGGER.info(f"Parsed {len(payloads)} messages from DLT file") + for p in payloads: + LOGGER.info(f" FILE payload: {p}") + assert len(payloads) > 0, "No messages from logging_app in DLT file" + + merged = "\n".join(payloads) + missing = [v for v in VALUES_TO_CHECK_FILE if v not in merged] + assert not missing, f"Missing expected values in DLT file: {missing}" From dae2939a2eb1be56ffecc97bb6f692f3f908cbbe Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:31:52 +0200 Subject: [PATCH 05/11] Add mw_log kFile integration tests --- score/test/itf/mw_log_kfile/BUILD | 51 +++++++ score/test/itf/mw_log_kfile/dlt_generator.cpp | 126 ++++++++++++++++++ score/test/itf/mw_log_kfile/etc/logging.json | 7 + .../itf/mw_log_kfile/test_mw_log_kfile.py | 116 ++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 score/test/itf/mw_log_kfile/BUILD create mode 100644 score/test/itf/mw_log_kfile/dlt_generator.cpp create mode 100644 score/test/itf/mw_log_kfile/etc/logging.json create mode 100644 score/test/itf/mw_log_kfile/test_mw_log_kfile.py diff --git a/score/test/itf/mw_log_kfile/BUILD b/score/test/itf/mw_log_kfile/BUILD new file mode 100644 index 00000000..bee7add3 --- /dev/null +++ b/score/test/itf/mw_log_kfile/BUILD @@ -0,0 +1,51 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//score/test/itf:defs.bzl", "py_logging_itf_test") + +cc_binary( + name = "dlt_generator", + srcs = ["dlt_generator.cpp"], + deps = ["//score/mw/log"], +) + +pkg_tar( + name = "dlt_generator_bin_pkg", + srcs = [":dlt_generator"], + package_dir = "opt/test_apps/dlt_generator/bin", +) + +pkg_tar( + name = "dlt_generator_config_pkg", + srcs = ["etc/logging.json"], + package_dir = "opt/test_apps/dlt_generator/etc", +) + +pkg_tar( + name = "dlt_generator_filesystem", + deps = [ + ":dlt_generator_bin_pkg", + ":dlt_generator_config_pkg", + ], +) + +py_logging_itf_test( + name = "test_mw_log_kfile", + srcs = ["test_mw_log_kfile.py"], + filesystem = ":dlt_generator_filesystem", + deps = [ + "//score/test/itf:dlt_parser", + "@score_itf//third_party/python_dlt", + ], +) diff --git a/score/test/itf/mw_log_kfile/dlt_generator.cpp b/score/test/itf/mw_log_kfile/dlt_generator.cpp new file mode 100644 index 00000000..c159c7fe --- /dev/null +++ b/score/test/itf/mw_log_kfile/dlt_generator.cpp @@ -0,0 +1,126 @@ +// ******************************************************************************* +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +#include "score/mw/log/logger.h" +#include "score/mw/log/logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace log = score::mw::log; + +namespace { + +const std::string kDefaultMessage = "default message text for example log generating application"; + +void DltLogJob(log::Logger& logger, + uint32_t iterations, + uint32_t sleep_ms, + bool counter, + bool use_full_output, + std::optional thread_id) { + for (uint32_t i = 0; i < iterations; ++i) { + std::string prefix; + if (thread_id.has_value()) { + prefix = "t" + std::to_string(thread_id.value()) + ":"; + } + if (counter) { + prefix += std::to_string(i + 1) + ": "; + } + + if (use_full_output) { + logger.LogFatal() << prefix << kDefaultMessage; + logger.LogError() << prefix << kDefaultMessage; + logger.LogWarn() << prefix << kDefaultMessage; + } + logger.LogInfo() << prefix << kDefaultMessage; + logger.LogVerbose() << prefix << kDefaultMessage; + logger.LogDebug() << prefix << kDefaultMessage; + + if (sleep_ms > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms)); + } + } +} + +} // namespace + +int main(int argc, char* argv[]) { + uint32_t threads_num = 1; + uint32_t iterations = 1; + uint32_t sleep_ms = 100; + bool counter = false; + bool use_full_output = true; + uint32_t sleep_before_shutdown_ms = 500; + + int opt; + while ((opt = getopt(argc, argv, "t:i:s:c:f:w:")) != -1) { + switch (opt) { + case 't': + threads_num = static_cast(std::atoi(optarg)); + break; + case 'i': + iterations = static_cast(std::atoi(optarg)); + break; + case 's': + sleep_ms = static_cast(std::atoi(optarg)); + break; + case 'c': + counter = (std::string(optarg) == "true"); + break; + case 'f': + use_full_output = (std::string(optarg) == "true"); + break; + case 'w': + sleep_before_shutdown_ms = static_cast(std::atoi(optarg)); + break; + default: + std::cerr << "Usage: " << argv[0] + << " [-t threads] [-i iterations] [-s sleep_ms]" + << " [-c true|false] [-f true|false] [-w shutdown_wait_ms]" + << std::endl; + return 1; + } + } + + log::Logger& logger = log::CreateLogger("LOGG", "dlt generator context"); + logger.LogInfo() << "Welcome warm-up message to initialize logging context."; + + std::vector threads; + for (uint32_t tid = 0; tid < threads_num; ++tid) { + std::optional pass_tid = + (threads_num == 1) ? std::nullopt : std::optional(static_cast(tid)); + threads.emplace_back(DltLogJob, std::ref(logger), iterations, sleep_ms, + counter, use_full_output, pass_tid); + } + + for (auto& t : threads) { + t.join(); + } + + logger.LogInfo() << "DLT generator finished."; + + if (sleep_before_shutdown_ms > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(sleep_before_shutdown_ms)); + } + + return 0; +} diff --git a/score/test/itf/mw_log_kfile/etc/logging.json b/score/test/itf/mw_log_kfile/etc/logging.json new file mode 100644 index 00000000..ccf0f30c --- /dev/null +++ b/score/test/itf/mw_log_kfile/etc/logging.json @@ -0,0 +1,7 @@ +{ + "appId": "LGGG", + "appDesc": "DLT Generator App", + "logMode": "kFile|kRemote", + "logLevel": "kVerbose", + "logLevelThresholdConsole": "kDebug" +} diff --git a/score/test/itf/mw_log_kfile/test_mw_log_kfile.py b/score/test/itf/mw_log_kfile/test_mw_log_kfile.py new file mode 100644 index 00000000..74637b43 --- /dev/null +++ b/score/test/itf/mw_log_kfile/test_mw_log_kfile.py @@ -0,0 +1,116 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test for mw::log kFile logging mode. + +Verifies that dlt_generator binary correctly writes DLT messages to a local +file when configured with kFile|kRemote log mode. Message counts are asserted +against the on-disk .dlt file (written directly by the datarouter from shared +memory). Remote DLT output via UDP is logged for diagnostics but not asserted +exactly, because UDP multicast can truncate messages under load. +""" + +import logging +import os +import tempfile + +import dlt.dlt as python_dlt + +from dlt_parser import parse_messages + + +LOGGER = logging.getLogger(__name__) + +APP_ID = "LGGG" +ITERATIONS = 100 +DEFAULT_MESSAGE = "default message text for example log generating application" +# With use_full_output=true and kVerbose log level via remote: +# Fatal + Error + Warn + Info + Verbose + Debug = 6 messages per iteration +MESSAGES_PER_ITERATION = 6 + + +def _verify_kfile_messages(target, expected): + """Download /tmp/LGGG.dlt from the target and assert the message count.""" + exit_code, _ = target.execute("test -f /tmp/LGGG.dlt && echo EXISTS") + assert exit_code == 0, "DLT file /tmp/LGGG.dlt was not created on the target" + + with tempfile.TemporaryDirectory() as tmpdir: + local_dlt = os.path.join(tmpdir, "LGGG.dlt") + target.download("/tmp/LGGG.dlt", local_dlt) + LOGGER.info(f"Downloaded DLT file: {os.path.getsize(local_dlt)} bytes") + + dlt_messages = python_dlt.load(local_dlt, None) + file_count = sum( + 1 + for m in dlt_messages + if getattr(m, "apid", None) == APP_ID + and DEFAULT_MESSAGE in str(getattr(m, "payload_decoded", "")) + ) + LOGGER.info(f"DLT file message count: {file_count}") + assert file_count == expected, ( + f"DLT file: expected {expected} messages, got {file_count}" + ) + + +def test_mw_log_kfile(target, datarouter_on_target, dlt_capture): + """Verify kFile logging produces the expected number of messages. + + Runs dlt_generator with 100 iterations, each producing 6 log messages + (Fatal, Error, Warn, Info, Verbose, Debug). Verifies the exact count + from the on-disk .dlt file. Remote DLT output via UDP is logged for + diagnostics but not asserted exactly. + """ + expected = ITERATIONS * MESSAGES_PER_ITERATION + + with dlt_capture() as receiver: + target.execute( + "cd /opt/test_apps/dlt_generator && ./bin/dlt_generator" + f" -i {ITERATIONS} -s 0 -c true -w 500" + ) + + # Log remote DLT count for diagnostics (UDP is inherently lossy) + output = receiver.get_output() + messages = parse_messages(output, APP_ID) + remote_count = sum(1 for m in messages if DEFAULT_MESSAGE in m.payload) + LOGGER.info(f"Remote DLT message count: {remote_count} / {expected} expected") + + _verify_kfile_messages(target, expected) + + +def test_mw_log_kfile_multiple_threads(target, datarouter_on_target, dlt_capture): + """Verify kFile logging with multiple threads. + + Runs dlt_generator with 4 threads and 100 iterations each, producing + 4 * 6 * 100 = 2400 messages total. Verifies the exact count from the + on-disk .dlt file (written directly by the datarouter from shared memory). + + Remote DLT output via UDP is logged for diagnostics but not asserted + exactly, because UDP multicast can truncate or drop messages under + concurrent load — this is inherent to the protocol, not a bug. + """ + threads = 4 + expected = threads * ITERATIONS * MESSAGES_PER_ITERATION + + with dlt_capture() as receiver: + target.execute( + "cd /opt/test_apps/dlt_generator && ./bin/dlt_generator" + f" -t {threads} -i {ITERATIONS} -s 0 -c true -w 500" + ) + + # Log remote DLT count for diagnostics (UDP is inherently lossy) + output = receiver.get_output() + messages = parse_messages(output, APP_ID) + remote_count = sum(1 for m in messages if DEFAULT_MESSAGE in m.payload) + LOGGER.info(f"Remote DLT message count: {remote_count} / {expected} expected") + + _verify_kfile_messages(target, expected) From ccfc152c7704f64f41200dd20a5684eeaebd5dbe Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:32:20 +0200 Subject: [PATCH 06/11] Add verbose log-level filter integration tests --- score/test/itf/filters/BUILD | 91 +++++++++++++++++++ score/test/itf/filters/arafiltertest.cpp | 75 +++++++++++++++ score/test/itf/filters/etc/logging.json | 32 +++++++ score/test/itf/filters/mwfiltertest.cpp | 68 ++++++++++++++ .../itf/filters/test_ara_verbose_filters.py | 54 +++++++++++ .../itf/filters/test_mw_verbose_filters.py | 65 +++++++++++++ 6 files changed, 385 insertions(+) create mode 100644 score/test/itf/filters/BUILD create mode 100644 score/test/itf/filters/arafiltertest.cpp create mode 100644 score/test/itf/filters/etc/logging.json create mode 100644 score/test/itf/filters/mwfiltertest.cpp create mode 100644 score/test/itf/filters/test_ara_verbose_filters.py create mode 100644 score/test/itf/filters/test_mw_verbose_filters.py diff --git a/score/test/itf/filters/BUILD b/score/test/itf/filters/BUILD new file mode 100644 index 00000000..756d0259 --- /dev/null +++ b/score/test/itf/filters/BUILD @@ -0,0 +1,91 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//score/test/itf:defs.bzl", "py_logging_itf_test") + +cc_binary( + name = "mwfiltertest", + srcs = ["mwfiltertest.cpp"], + deps = ["//score/mw/log"], +) + +cc_binary( + name = "arafiltertest", + srcs = ["arafiltertest.cpp"], + deps = ["//score/mw/log"], +) + +# --- Per-test filesystems --- + +pkg_tar( + name = "mwfiltertest_pkg", + srcs = [":mwfiltertest"], + package_dir = "opt/test_apps/mwfiltertest/bin", +) + +pkg_tar( + name = "mwfiltertest_config_pkg", + srcs = ["etc/logging.json"], + package_dir = "opt/test_apps/mwfiltertest/etc", +) + +pkg_tar( + name = "mwfiltertest_filesystem", + deps = [ + ":mwfiltertest_config_pkg", + ":mwfiltertest_pkg", + ], +) + +pkg_tar( + name = "arafiltertest_pkg", + srcs = [":arafiltertest"], + package_dir = "opt/test_apps/arafiltertest/bin", +) + +pkg_tar( + name = "arafiltertest_config_pkg", + srcs = ["etc/logging.json"], + package_dir = "opt/test_apps/arafiltertest/etc", +) + +pkg_tar( + name = "arafiltertest_filesystem", + deps = [ + ":arafiltertest_config_pkg", + ":arafiltertest_pkg", + ], +) + +# --- Test targets --- + +py_logging_itf_test( + name = "test_mw_verbose_filters", + srcs = ["test_mw_verbose_filters.py"], + filesystem = ":mwfiltertest_filesystem", + deps = ["//score/test/itf:dlt_parser"], +) + +py_logging_itf_test( + name = "test_ara_verbose_filters", + srcs = ["test_ara_verbose_filters.py"], + filesystem = ":arafiltertest_filesystem", + deps = ["//score/test/itf:dlt_parser"], +) + +# --- Non-verbose (TRACE) filter test --- +# NOTE: Requires --//score/datarouter/build_configuration_flags:enable_nonverbose_dlt=True + +cc_binary( diff --git a/score/test/itf/filters/arafiltertest.cpp b/score/test/itf/filters/arafiltertest.cpp new file mode 100644 index 00000000..b43e526d --- /dev/null +++ b/score/test/itf/filters/arafiltertest.cpp @@ -0,0 +1,75 @@ +// ******************************************************************************* +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +#include "score/mw/log/logger.h" +#include "score/mw/log/logging.h" + +#include + +// With filtering configured for this app in the attached logging.json file, +// totally 22 ( 1 + 2 + 3 + 4 + 5 + 6 + 1 = 22) messages should be visible in DLT +int main() +{ + score::mw::log::Logger logger_1{score::mw::log::CreateLogger("FAT", "Fatal")}; + logger_1.LogFatal() << "Fatal message"; + logger_1.LogError() << "Error message"; + logger_1.LogWarn() << "Warn message"; + logger_1.LogInfo() << "Info message"; + logger_1.LogDebug() << "Debug message"; + logger_1.LogVerbose() << "Verbose message"; + + score::mw::log::Logger logger_2{score::mw::log::CreateLogger("ERR", "Error")}; + logger_2.LogFatal() << "Fatal message"; + logger_2.LogError() << "Error message"; + logger_2.LogWarn() << "Warn message"; + logger_2.LogInfo() << "Info message"; + logger_2.LogDebug() << "Debug message"; + logger_2.LogVerbose() << "Verbose message"; + + score::mw::log::Logger logger_3{score::mw::log::CreateLogger("WRN", "Warn")}; + logger_3.LogFatal() << "Fatal message"; + logger_3.LogError() << "Error message"; + logger_3.LogWarn() << "Warn message"; + logger_3.LogInfo() << "Info message"; + logger_3.LogDebug() << "Debug message"; + logger_3.LogVerbose() << "Verbose message"; + + score::mw::log::Logger logger_4{score::mw::log::CreateLogger("INF", "Info")}; + logger_4.LogFatal() << "Fatal message"; + logger_4.LogError() << "Error message"; + logger_4.LogWarn() << "Warn message"; + logger_4.LogInfo() << "Info message"; + logger_4.LogDebug() << "Debug message"; + logger_4.LogVerbose() << "Verbose message"; + + score::mw::log::Logger logger_5{score::mw::log::CreateLogger("DBG", "Debug")}; + logger_5.LogFatal() << "Fatal message"; + logger_5.LogError() << "Error message"; + logger_5.LogWarn() << "Warn message"; + logger_5.LogInfo() << "Info message"; + logger_5.LogDebug() << "Debug message"; + logger_5.LogVerbose() << "Verbose message"; + + score::mw::log::Logger logger_6{score::mw::log::CreateLogger("VBS", "Verbose")}; + logger_6.LogFatal() << "Fatal message"; + logger_6.LogError() << "Error message"; + logger_6.LogWarn() << "Warn message"; + logger_6.LogInfo() << "Info message"; + logger_6.LogDebug() << "Debug message"; + logger_6.LogVerbose() << "Verbose message"; + + score::mw::log::LogFatal() << "LogFatal"; + + sleep(1); + return 0; +} diff --git a/score/test/itf/filters/etc/logging.json b/score/test/itf/filters/etc/logging.json new file mode 100644 index 00000000..a1953e81 --- /dev/null +++ b/score/test/itf/filters/etc/logging.json @@ -0,0 +1,32 @@ +{ + "appId": "TAP", + "appDesc": "Test Application", + "logLevel": "kFatal", + "logMode": "kRemote", + "contextConfigs": [ + { + "name": "FAT", + "logLevel": "kFatal" + }, + { + "name": "ERR", + "logLevel": "kError" + }, + { + "name": "WRN", + "logLevel": "kWarn" + }, + { + "name": "INF", + "logLevel": "kInfo" + }, + { + "name": "DBG", + "logLevel": "kDebug" + }, + { + "name": "VBS", + "logLevel": "kVerbose" + } + ] +} diff --git a/score/test/itf/filters/mwfiltertest.cpp b/score/test/itf/filters/mwfiltertest.cpp new file mode 100644 index 00000000..fda166f2 --- /dev/null +++ b/score/test/itf/filters/mwfiltertest.cpp @@ -0,0 +1,68 @@ +// ******************************************************************************* +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +#include "score/mw/log/logging.h" + +#include + +// With filtering configured for this app in the attached logging.json file, +// totally 22 ( 1 + 2 + 3 + 4 + 5 + 6 + 1 = 22) messages should be visible in DLT +int main() +{ + score::mw::log::LogFatal("FAT") << "Fatal message"; + score::mw::log::LogError("FAT") << "Error message"; + score::mw::log::LogWarn("FAT") << "Warning message"; + score::mw::log::LogInfo("FAT") << "Info message"; + score::mw::log::LogDebug("FAT") << "Debug message"; + score::mw::log::LogVerbose("FAT") << "Verbose message"; + + score::mw::log::LogFatal("ERR") << "Fatal message"; + score::mw::log::LogError("ERR") << "Error message"; + score::mw::log::LogWarn("ERR") << "Warning message"; + score::mw::log::LogInfo("ERR") << "Info message"; + score::mw::log::LogDebug("ERR") << "Debug message"; + score::mw::log::LogVerbose("ERR") << "Verbose message"; + + score::mw::log::LogFatal("WRN") << "Fatal message"; + score::mw::log::LogError("WRN") << "Error message"; + score::mw::log::LogWarn("WRN") << "Warning message"; + score::mw::log::LogInfo("WRN") << "Info message"; + score::mw::log::LogDebug("WRN") << "Debug message"; + score::mw::log::LogVerbose("WRN") << "Verbose message"; + + score::mw::log::LogFatal("INF") << "Fatal message"; + score::mw::log::LogError("INF") << "Error message"; + score::mw::log::LogWarn("INF") << "Warning message"; + score::mw::log::LogInfo("INF") << "Info message"; + score::mw::log::LogDebug("INF") << "Debug message"; + score::mw::log::LogVerbose("INF") << "Verbose message"; + + score::mw::log::LogFatal("DBG") << "Fatal message"; + score::mw::log::LogError("DBG") << "Error message"; + score::mw::log::LogWarn("DBG") << "Warning message"; + score::mw::log::LogInfo("DBG") << "Info message"; + score::mw::log::LogDebug("DBG") << "Debug message"; + score::mw::log::LogVerbose("DBG") << "Verbose message"; + + score::mw::log::LogFatal("VBS") << "Fatal message"; + score::mw::log::LogError("VBS") << "Error message"; + score::mw::log::LogWarn("VBS") << "Warning message"; + score::mw::log::LogInfo("VBS") << "Info message"; + score::mw::log::LogDebug("VBS") << "Debug message"; + score::mw::log::LogVerbose("VBS") << "Verbose message"; + + score::mw::log::LogFatal() << "LogFatal"; + + sleep(1); + return 0; +} diff --git a/score/test/itf/filters/test_ara_verbose_filters.py b/score/test/itf/filters/test_ara_verbose_filters.py new file mode 100644 index 00000000..51e484b2 --- /dev/null +++ b/score/test/itf/filters/test_ara_verbose_filters.py @@ -0,0 +1,54 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test for mw::log verbose log-level filtering (instance Logger API). + +Same verification as test_mw_verbose_filters but exercises the AUTOSAR-style +CreateLogger() instance API instead of free functions. +""" + +import logging + +from dlt_parser import count_messages_by_context + + +LOGGER = logging.getLogger(__name__) + +TOTAL_VERBOSE_MESSAGES = 22 +TEST_APP_ID = "TAP" +CONTEXT_IDS = {"FAT", "ERR", "WRN", "INF", "DBG", "VBS"} + + +def test_ara_verbose_filters(target, datarouter_on_target, dlt_capture): + """Verify per-context verbose log-level filtering with instance Logger API. + + Same expected counts as test_mw_verbose_filters: + FAT=1, ERR=2, WRN=3, INF=4, DBG=5, VBS=6, total=22 + """ + with dlt_capture() as receiver: + target.execute("cd /opt/test_apps/arafiltertest && ./bin/arafiltertest") + + output = receiver.get_output() + LOGGER.info(f"DLT output length: {len(output)} chars") + + counts, total = count_messages_by_context(output, TEST_APP_ID, CONTEXT_IDS) + + assert counts.get("FAT", 0) == 1, f"FAT: expected 1, got {counts.get('FAT', 0)}" + assert counts.get("ERR", 0) == 2, f"ERR: expected 2, got {counts.get('ERR', 0)}" + assert counts.get("WRN", 0) == 3, f"WRN: expected 3, got {counts.get('WRN', 0)}" + assert counts.get("INF", 0) == 4, f"INF: expected 4, got {counts.get('INF', 0)}" + assert counts.get("DBG", 0) == 5, f"DBG: expected 5, got {counts.get('DBG', 0)}" + assert counts.get("VBS", 0) == 6, f"VBS: expected 6, got {counts.get('VBS', 0)}" + assert total == TOTAL_VERBOSE_MESSAGES, ( + f"Total: expected {TOTAL_VERBOSE_MESSAGES}, got {total}" + ) diff --git a/score/test/itf/filters/test_mw_verbose_filters.py b/score/test/itf/filters/test_mw_verbose_filters.py new file mode 100644 index 00000000..d7574d9d --- /dev/null +++ b/score/test/itf/filters/test_mw_verbose_filters.py @@ -0,0 +1,65 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test for mw::log verbose log-level filtering (free-function API). + +Verifies that per-context log-level filtering works correctly when using the +score::mw::log free-function API (LogFatal("CTX"), LogError("CTX"), etc.). + +The mwfiltertest binary emits 6 messages (Fatal through Verbose) to each of +6 contexts (FAT, ERR, WRN, INF, DBG, VBS), each configured at a different +log level, plus 1 default-context LogFatal. With the configured filters, +exactly 22 messages should be visible. +""" + +import logging + +from dlt_parser import count_messages_by_context + + +LOGGER = logging.getLogger(__name__) + +TOTAL_VERBOSE_MESSAGES = 22 +TEST_APP_ID = "TAP" +CONTEXT_IDS = {"FAT", "ERR", "WRN", "INF", "DBG", "VBS"} + + +def test_mw_verbose_filters(target, datarouter_on_target, dlt_capture): + """Verify per-context verbose log-level filtering with free-function API. + + Expected message counts per context (based on configured log levels): + - FAT (kFatal): 1 message (only Fatal passes) + - ERR (kError): 2 messages (Fatal + Error pass) + - WRN (kWarn): 3 messages (Fatal + Error + Warn pass) + - INF (kInfo): 4 messages (Fatal + Error + Warn + Info pass) + - DBG (kDebug): 5 messages (Fatal + Error + Warn + Info + Debug pass) + - VBS (kVerbose): 6 messages (all pass) + Plus 1 default-context LogFatal = 22 total. + """ + with dlt_capture() as receiver: + target.execute("cd /opt/test_apps/mwfiltertest && ./bin/mwfiltertest") + + output = receiver.get_output() + LOGGER.info(f"DLT output length: {len(output)} chars") + + counts, total = count_messages_by_context(output, TEST_APP_ID, CONTEXT_IDS) + + assert counts.get("FAT", 0) == 1, f"FAT: expected 1, got {counts.get('FAT', 0)}" + assert counts.get("ERR", 0) == 2, f"ERR: expected 2, got {counts.get('ERR', 0)}" + assert counts.get("WRN", 0) == 3, f"WRN: expected 3, got {counts.get('WRN', 0)}" + assert counts.get("INF", 0) == 4, f"INF: expected 4, got {counts.get('INF', 0)}" + assert counts.get("DBG", 0) == 5, f"DBG: expected 5, got {counts.get('DBG', 0)}" + assert counts.get("VBS", 0) == 6, f"VBS: expected 6, got {counts.get('VBS', 0)}" + assert total == TOTAL_VERBOSE_MESSAGES, ( + f"Total: expected {TOTAL_VERBOSE_MESSAGES}, got {total}" + ) From b4a4fba72e7eb5b542191f8e468e9f9eda1a4419 Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:32:49 +0200 Subject: [PATCH 07/11] Add non-verbose (TRACE) filter integration test --- .../build_configuration_flags/BUILD | 2 +- score/mw/log/legacy_non_verbose_api/BUILD | 1 + score/test/itf/filters/BUILD | 57 ++++++++++++ score/test/itf/filters/etc/class-id.json | 3 + .../itf/filters/etc/filtertest_logging.json | 18 ++++ score/test/itf/filters/filtertest.cpp | 82 ++++++++++++++++++ score/test/itf/filters/filtertest.h | 60 +++++++++++++ .../itf/filters/test_datarouter_filters.py | 86 +++++++++++++++++++ 8 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 score/test/itf/filters/etc/class-id.json create mode 100644 score/test/itf/filters/etc/filtertest_logging.json create mode 100644 score/test/itf/filters/filtertest.cpp create mode 100644 score/test/itf/filters/filtertest.h create mode 100644 score/test/itf/filters/test_datarouter_filters.py diff --git a/score/datarouter/build_configuration_flags/BUILD b/score/datarouter/build_configuration_flags/BUILD index 4fb2ee30..34a80766 100644 --- a/score/datarouter/build_configuration_flags/BUILD +++ b/score/datarouter/build_configuration_flags/BUILD @@ -51,7 +51,7 @@ config_setting( ":enable_nonverbose_dlt": "True", }, visibility = [ - "@score_logging//score/datarouter:__subpackages__", + "//visibility:public", ], ) diff --git a/score/mw/log/legacy_non_verbose_api/BUILD b/score/mw/log/legacy_non_verbose_api/BUILD index cc573333..bbdd96b8 100644 --- a/score/mw/log/legacy_non_verbose_api/BUILD +++ b/score/mw/log/legacy_non_verbose_api/BUILD @@ -36,6 +36,7 @@ cc_library( visibility = [ "//platform/aas/ara/log:__subpackages__", "//score/mw/log:__subpackages__", + "//score/test/itf:__subpackages__", "@score_baselibs//score/mw/log:__subpackages__", "@score_logging//score/datarouter:__subpackages__", ], diff --git a/score/test/itf/filters/BUILD b/score/test/itf/filters/BUILD index 756d0259..475844e7 100644 --- a/score/test/itf/filters/BUILD +++ b/score/test/itf/filters/BUILD @@ -89,3 +89,60 @@ py_logging_itf_test( # NOTE: Requires --//score/datarouter/build_configuration_flags:enable_nonverbose_dlt=True cc_binary( + name = "filtertest", + srcs = [ + "filtertest.cpp", + "filtertest.h", + ], + deps = [ + "//score/mw/log", + "//score/mw/log/legacy_non_verbose_api", + "@score_baselibs//score/static_reflection_with_serialization/visitor", + ], +) + +pkg_tar( + name = "filtertest_bin_pkg", + srcs = [":filtertest"], + package_dir = "opt/test_apps/filtertest/bin", +) + +genrule( + name = "filtertest_logging_json", + srcs = ["etc/filtertest_logging.json"], + outs = ["filtertest_etc/logging.json"], + cmd = "cp $< $@", +) + +pkg_tar( + name = "filtertest_config_pkg", + srcs = [":filtertest_logging_json"], + package_dir = "opt/test_apps/filtertest/etc", + strip_prefix = "filtertest_etc", +) + +pkg_tar( + name = "filtertest_classid_pkg", + srcs = ["etc/class-id.json"], + package_dir = "bmw/platform/opt/datarouter/etc", +) + +pkg_tar( + name = "filtertest_filesystem", + deps = [ + ":filtertest_bin_pkg", + ":filtertest_classid_pkg", + ":filtertest_config_pkg", + ], +) + +py_logging_itf_test( + name = "test_datarouter_filters", + srcs = ["test_datarouter_filters.py"], + filesystem = ":filtertest_filesystem", + target_compatible_with = select({ + "//score/datarouter/build_configuration_flags:config_datarouter_nonverbose_dlt": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + deps = ["@score_itf//score/itf/plugins/dlt"], +) diff --git a/score/test/itf/filters/etc/class-id.json b/score/test/itf/filters/etc/class-id.json new file mode 100644 index 00000000..a8ab259f --- /dev/null +++ b/score/test/itf/filters/etc/class-id.json @@ -0,0 +1,3 @@ +{"AAAA_kFatal": {"id": 111, "ctxid": "AAAA", "appid": "APP", "loglevel": 1}, "AAAA_kError": {"id": 112, "ctxid": "AAAA", "appid": "APP", "loglevel": 2}, "AAAA_kWarn": {"id": 113, "ctxid": "AAAA", "appid": "APP", "loglevel": 3}, "AAAA_kInfo": {"id": 114, "ctxid": "AAAA", "appid": "APP", "loglevel": 4}, "AAAA_kDebug": {"id": 115, "ctxid": "AAAA", "appid": "APP", "loglevel": 5}, "AAAA_kVerbose": {"id": 116, "ctxid": "AAAA", "appid": "APP", "loglevel": 6}, + "BBBB_kFatal": {"id": 211, "ctxid": "BBBB", "appid": "APP", "loglevel": 1}, "BBBB_kError": {"id": 212, "ctxid": "BBBB", "appid": "APP", "loglevel": 2}, "BBBB_kWarn": {"id": 213, "ctxid": "BBBB", "appid": "APP", "loglevel": 3}, "BBBB_kInfo": {"id": 214, "ctxid": "BBBB", "appid": "APP", "loglevel": 4}, "BBBB_kDebug": {"id": 215, "ctxid": "BBBB", "appid": "APP", "loglevel": 5}, "BBBB_kVerbose": {"id": 216, "ctxid": "BBBB", "appid": "APP", "loglevel": 6}, + "CCCC_kFatal": {"id": 311, "ctxid": "CCCC", "appid": "APP", "loglevel": 1}, "CCCC_kError": {"id": 312, "ctxid": "CCCC", "appid": "APP", "loglevel": 2}, "CCCC_kWarn": {"id": 313, "ctxid": "CCCC", "appid": "APP", "loglevel": 3}, "CCCC_kInfo": {"id": 314, "ctxid": "CCCC", "appid": "APP", "loglevel": 4}, "CCCC_kDebug": {"id": 315, "ctxid": "CCCC", "appid": "APP", "loglevel": 5}, "CCCC_kVerbose": {"id": 316, "ctxid": "CCCC", "appid": "APP", "loglevel": 6}} diff --git a/score/test/itf/filters/etc/filtertest_logging.json b/score/test/itf/filters/etc/filtertest_logging.json new file mode 100644 index 00000000..2dcc839d --- /dev/null +++ b/score/test/itf/filters/etc/filtertest_logging.json @@ -0,0 +1,18 @@ +{ + "appId": "FTST", + "appDesc": "Filter Test Application", + "contextConfigs": [ + { + "name": "AAAA", + "logLevel": "kVerbose" + }, + { + "name": "BBBB", + "logLevel": "kInfo" + }, + { + "name": "CCCC", + "logLevel": "kFatal" + } + ] + } diff --git a/score/test/itf/filters/filtertest.cpp b/score/test/itf/filters/filtertest.cpp new file mode 100644 index 00000000..475bb054 --- /dev/null +++ b/score/test/itf/filters/filtertest.cpp @@ -0,0 +1,82 @@ +/******************************************************************************* + * + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + */ + +#include "filtertest.h" + +#include +#include + +#include "score/mw/log/logging.h" + +struct UndefinedStruct +{ + int a; + double b; +}; + +STRUCT_VISITABLE(UndefinedStruct, a, b) + +int main(int, char**) +{ + score::mw::log::LogInfo() << "Filtertest starting"; + + AAAA_kFatal a11{{1, 1}}; + TRACE(a11); + AAAA_kError a12{{1, 2}}; + TRACE(a12); + AAAA_kWarn a13{{1, 3}}; + TRACE(a13); + AAAA_kInfo a14{{1, 4}}; + TRACE(a14); + AAAA_kDebug a15{{1, 5}}; + TRACE(a15); + AAAA_kVerbose a16{{1, 6}}; + TRACE(a16); + + BBBB_kFatal b11{{2, 1}}; + TRACE(b11); + BBBB_kError b12{{2, 2}}; + TRACE(b12); + BBBB_kWarn b13{{2, 3}}; + TRACE(b13); + BBBB_kInfo b14{{2, 4}}; + TRACE(b14); + BBBB_kDebug b15{{2, 5}}; + TRACE(b15); + BBBB_kVerbose b16{{2, 6}}; + TRACE(b16); + + CCCC_kFatal c11{{3, 1}}; + TRACE(c11); + CCCC_kError c12{{3, 2}}; + TRACE(c12); + CCCC_kWarn c13{{3, 3}}; + TRACE(c13); + CCCC_kInfo c14{{3, 4}}; + TRACE(c14); + CCCC_kDebug c15{{3, 5}}; + TRACE(c15); + CCCC_kVerbose c16{{3, 6}}; + TRACE(c16); + + UndefinedStruct us{1, 1.0}; + TRACE(us); + + sleep(1); + + score::mw::log::LogInfo() << "Filtertest done"; + + return 0; +} diff --git a/score/test/itf/filters/filtertest.h b/score/test/itf/filters/filtertest.h new file mode 100644 index 00000000..e18e0153 --- /dev/null +++ b/score/test/itf/filters/filtertest.h @@ -0,0 +1,60 @@ +/******************************************************************************* + * + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + */ + +#ifndef FILTERTEST_H +#define FILTERTEST_H + +#include "static_reflection_with_serialization/visitor/visit_as_struct.h" + +struct default_struct +{ + int a; + char b; +}; + +STRUCT_VISITABLE(default_struct, a, b) + +#define dummy_struct_name(ctx, level) dummy_struct_name2(ctx, level) +#define dummy_struct_name2(ctx, level) ctx##_##level + +#define dummy_struct(name) \ + struct name \ + { \ + default_struct val; \ + }; \ + STRUCT_VISITABLE(name, val) + +dummy_struct(dummy_struct_name(AAAA, kFatal)); +dummy_struct(dummy_struct_name(AAAA, kError)); +dummy_struct(dummy_struct_name(AAAA, kWarn)); +dummy_struct(dummy_struct_name(AAAA, kInfo)); +dummy_struct(dummy_struct_name(AAAA, kDebug)); +dummy_struct(dummy_struct_name(AAAA, kVerbose)); + +dummy_struct(dummy_struct_name(BBBB, kFatal)); +dummy_struct(dummy_struct_name(BBBB, kError)); +dummy_struct(dummy_struct_name(BBBB, kWarn)); +dummy_struct(dummy_struct_name(BBBB, kInfo)); +dummy_struct(dummy_struct_name(BBBB, kDebug)); +dummy_struct(dummy_struct_name(BBBB, kVerbose)); + +dummy_struct(dummy_struct_name(CCCC, kFatal)); +dummy_struct(dummy_struct_name(CCCC, kError)); +dummy_struct(dummy_struct_name(CCCC, kWarn)); +dummy_struct(dummy_struct_name(CCCC, kInfo)); +dummy_struct(dummy_struct_name(CCCC, kDebug)); +dummy_struct(dummy_struct_name(CCCC, kVerbose)); + +#endif // FILTERTEST_H diff --git a/score/test/itf/filters/test_datarouter_filters.py b/score/test/itf/filters/test_datarouter_filters.py new file mode 100644 index 00000000..1f21116e --- /dev/null +++ b/score/test/itf/filters/test_datarouter_filters.py @@ -0,0 +1,86 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test for datarouter non-verbose (TRACE) log-level filtering. + +Verifies that per-context log-level filtering works for non-verbose (TRACE) +messages routed through the datarouter. The filtertest binary emits 18 +TRACE'd structs (6 per context x 3 contexts: AAAA, BBBB, CCCC) plus one +UndefinedStruct. Each context is configured at a different log level: + + - AAAA (kVerbose): all 6 messages pass the filter + - BBBB (kInfo): 4 messages pass (Fatal, Error, Warn, Info) + - CCCC (kFatal): 1 message passes (Fatal only) + +Total expected non-verbose messages: 11 + +NOTE: This test requires building with the nonverbose DLT flag: + --//score/datarouter/build_configuration_flags:enable_nonverbose_dlt=True +""" + +import ctypes +import logging + +from logging_plugin import download_dlt + +LOGGER = logging.getLogger(__name__) + +TOTAL_NONVERBOSE_MESSAGES = 11 + + +def test_datarouter_filters(target, datarouter_on_target, dlt_capture): + """Verify per-context non-verbose log-level filtering via TRACE(). + + Expected message counts per context group (type_id // 100): + - group 1 (AAAA, kVerbose): 6 messages + - group 2 (BBBB, kInfo): 4 messages + - group 3 (CCCC, kFatal): 1 message + Total non-verbose messages: 11 + """ + with dlt_capture() as receiver: + target.execute("cd /opt/test_apps/filtertest && ./bin/filtertest") + + # Download the captured .dlt file + record = download_dlt(target, receiver.dlt_file) + + # Find only non-extended (non-verbose / TRACE) messages + messages = record.find(include_ext=False, include_non_ext=True) + LOGGER.info(f"Non-verbose messages found: {len(messages)}") + + # Extract type IDs from the raw DLT payload + received_ids = {} + for msg in messages: + id_t = ctypes.c_uint32 + message_address = ctypes.addressof(msg.raw_msg.databuffer.contents) + typeid = id_t.from_address(message_address).value + + ctxid = typeid // 100 + if ctxid not in received_ids: + received_ids[ctxid] = [] + received_ids[ctxid].append(typeid) + + LOGGER.info(f"Received IDs by context group: {received_ids}") + + assert len(received_ids.get(1, [])) == 6, ( + f"AAAA (kVerbose): expected 6, got {len(received_ids.get(1, []))}" + ) + assert len(received_ids.get(2, [])) == 4, ( + f"BBBB (kInfo): expected 4, got {len(received_ids.get(2, []))}" + ) + assert len(received_ids.get(3, [])) == 1, ( + f"CCCC (kFatal): expected 1, got {len(received_ids.get(3, []))}" + ) + assert len(messages) == TOTAL_NONVERBOSE_MESSAGES, ( + f"Total: expected {TOTAL_NONVERBOSE_MESSAGES}, got {len(messages)}" + ) + LOGGER.info("Datarouter non-verbose filter validation succeeded") From 8245d0d31969048d29c99a046383d190ea16a80f Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:33:06 +0200 Subject: [PATCH 08/11] Add DLT filetransfer integration test --- .../dlt_filetransfer_trigger_lib/BUILD | 1 + score/test/itf/filetransfer/BUILD | 51 ++++++++++ score/test/itf/filetransfer/etc/logging.json | 6 ++ .../itf/filetransfer/filetransfer_app.cpp | 78 +++++++++++++++ .../itf/filetransfer/test_filetransfer.py | 94 +++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 score/test/itf/filetransfer/BUILD create mode 100644 score/test/itf/filetransfer/etc/logging.json create mode 100644 score/test/itf/filetransfer/filetransfer_app.cpp create mode 100644 score/test/itf/filetransfer/test_filetransfer.py diff --git a/score/datarouter/dlt_filetransfer_trigger_lib/BUILD b/score/datarouter/dlt_filetransfer_trigger_lib/BUILD index 5adca908..7f1c1a00 100644 --- a/score/datarouter/dlt_filetransfer_trigger_lib/BUILD +++ b/score/datarouter/dlt_filetransfer_trigger_lib/BUILD @@ -43,6 +43,7 @@ cc_library( "//platform/aas/pas/datarouterconf/src/services:__pkg__", "//platform/aas/test/pas:__subpackages__", "//score/datarouter/test:__subpackages__", + "//score/test/itf:__subpackages__", "@score_baselibs//score/logging:__pkg__", ], deps = [ diff --git a/score/test/itf/filetransfer/BUILD b/score/test/itf/filetransfer/BUILD new file mode 100644 index 00000000..8371a96f --- /dev/null +++ b/score/test/itf/filetransfer/BUILD @@ -0,0 +1,51 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//score/test/itf:defs.bzl", "py_logging_itf_test") + +cc_binary( + name = "filetransfer_app", + srcs = ["filetransfer_app.cpp"], + deps = [ + "//score/datarouter/dlt_filetransfer_trigger_lib", + "//score/mw/log", + ], +) + +pkg_tar( + name = "filetransfer_bin_pkg", + srcs = [":filetransfer_app"], + package_dir = "opt/test_apps/filetransfer/bin", +) + +pkg_tar( + name = "filetransfer_config_pkg", + srcs = ["etc/logging.json"], + package_dir = "opt/test_apps/filetransfer/etc", +) + +pkg_tar( + name = "filetransfer_filesystem", + deps = [ + ":filetransfer_bin_pkg", + ":filetransfer_config_pkg", + ], +) + +py_logging_itf_test( + name = "test_filetransfer", + srcs = ["test_filetransfer.py"], + filesystem = ":filetransfer_filesystem", + deps = ["//score/test/itf:dlt_parser"], +) diff --git a/score/test/itf/filetransfer/etc/logging.json b/score/test/itf/filetransfer/etc/logging.json new file mode 100644 index 00000000..067456b4 --- /dev/null +++ b/score/test/itf/filetransfer/etc/logging.json @@ -0,0 +1,6 @@ +{ + "appId": "FTEA", + "appDesc": "File Transfer Example App", + "logMode": "kRemote", + "logLevel": "kVerbose" +} diff --git a/score/test/itf/filetransfer/filetransfer_app.cpp b/score/test/itf/filetransfer/filetransfer_app.cpp new file mode 100644 index 00000000..ba497cf0 --- /dev/null +++ b/score/test/itf/filetransfer/filetransfer_app.cpp @@ -0,0 +1,78 @@ +// ******************************************************************************* +// Copyright (c) 2025 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +#include "score/datarouter/dlt_filetransfer_trigger_lib/include/file_transfer.h" +#include "score/mw/log/logger.h" +#include "score/mw/log/logging.h" + +#include +#include +#include +#include +#include + +namespace log = score::mw::log; + +namespace { + +const std::string kTestFileContent = + "This is test content for file transfer integration test.\n" + "Line 2 of test data.\n" + "Line 3 of test data.\n"; + +void CreateTestFile(const std::string& path) { + std::ofstream out(path); + out << kTestFileContent; +} + +} // namespace + +int main() { + log::Logger& logger = log::CreateLogger("FTEA", "File Transfer Example App"); + + logger.LogInfo() << "File Transfer Example Application" << "initialize"; + + // Create a test file to transfer + const std::string original_file = "/tmp/filetransfer_test_file.txt"; + CreateTestFile(original_file); + logger.LogInfo() << "Created test file:" << original_file; + + // Initialize file transfer + score::logging::FileTransfer file_transfer("FTEA", "FMSG"); + + logger.LogInfo() << "File Transfer Example Application" << "DoFileTransfer"; + + // Transfer multiple copies of the file + constexpr int kNumTransfers = 50; + for (int i = 0; i < kNumTransfers; ++i) { + std::stringstream filename; + filename << "/tmp/filetransfer_test_" << i << ".txt"; + + std::error_code ec; + std::filesystem::copy(original_file, filename.str(), ec); + if (ec) { + logger.LogError() << "Failed to copy file:" << ec.message(); + continue; + } + + file_transfer.TransferFile(filename.str(), false); + logger.LogInfo() << "Transferred file:" << filename.str(); + } + + logger.LogInfo() << "File Transfer Example Application" << "done"; + + // Wait for logs to be processed + sleep(2); + + return 0; +} diff --git a/score/test/itf/filetransfer/test_filetransfer.py b/score/test/itf/filetransfer/test_filetransfer.py new file mode 100644 index 00000000..89853250 --- /dev/null +++ b/score/test/itf/filetransfer/test_filetransfer.py @@ -0,0 +1,94 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test for DLT file transfer. + +Verifies that the filetransfer_app correctly creates test files and invokes +the FileTransfer API via the datarouter. The verbose log messages confirming +each transfer are received via dlt-receive. + +Note: The datarouter's file transfer feature flag may be disabled in the +default configuration, in which case the FLST/FLDA/FLFI protocol messages +are not emitted. This test verifies the app-side transfer invocations and +that the test files are created on the target filesystem. +""" + +import logging + +import pytest +from dlt_parser import parse_messages + + +LOGGER = logging.getLogger(__name__) + +APP_ID = "FTEA" +NUM_TRANSFERS = 50 + + +def test_filetransfer(target, datarouter_on_target, dlt_capture): + """Verify that file transfer DLT messages are sent and received. + + The filetransfer_app creates test files and sends them via the + FileTransfer API. We verify: + 1. The app's lifecycle log messages are received via UDP + 2. All NUM_TRANSFERS transfers are confirmed by app-level log messages + 3. The test files exist on the target filesystem + """ + with dlt_capture() as receiver: + target.execute("cd /opt/test_apps/filetransfer && ./bin/filetransfer_app") + + output = receiver.get_output() + LOGGER.info(f"DLT output length: {len(output)} chars") + + messages = parse_messages(output, APP_ID) + LOGGER.info(f"App message count: {len(messages)}") + + assert len(messages) > 0, "No DLT messages received from filetransfer_app" + + app_payloads = "\n".join(m.payload for m in messages) + + # Verify lifecycle messages + assert "initialize" in app_payloads, "Missing 'initialize' message" + assert "DoFileTransfer" in app_payloads, "Missing 'DoFileTransfer' message" + assert "done" in app_payloads, "Missing 'done' message" + + # Verify transfer confirmations from the app + transfer_msgs = [m for m in messages if "Transferred file" in m.payload] + assert len(transfer_msgs) == NUM_TRANSFERS, ( + f"Expected {NUM_TRANSFERS} transfer confirmations, got {len(transfer_msgs)}" + ) + + # Verify the test files were created on the target filesystem + exit_code, ls_output = target.execute( + "ls /tmp/filetransfer_test_[0-9]*.txt | wc -l" + ) + file_count = int(ls_output.strip()) + assert file_count == NUM_TRANSFERS, ( + f"Expected {NUM_TRANSFERS} test files on target, found {file_count}" + ) + + +@pytest.mark.skip( + reason="file_transfer_impl not available in this repo — FLST/FLDA/FLFI protocol messages are not emitted" +) +def test_filetransfer_protocol_verification(target, datarouter_on_target, dlt_capture): + """Verify DLT file transfer protocol messages (FLST/FLDA/FLFI) and hash integrity. + + This test verifies the low-level DLT file transfer protocol, including: + - FLST (file transfer start) messages with correct file metadata + - FLDA (file transfer data) messages containing file content + - FLFI (file transfer finish) messages with MD5 hash verification + + Requires file_transfer_impl/ to be present and file_transfer=True in .bazelrc. + Currently blocked because file_transfer_impl/ does not exist in this repo. + """ From 216f6f5389f9fffee88b9a29127cf0359e92f652 Mon Sep 17 00:00:00 2001 From: Jakub Zaborowski Date: Thu, 21 May 2026 06:34:07 +0200 Subject: [PATCH 09/11] Fix review findings --- score/datarouter/BUILD | 9 +-- .../dlt_filetransfer_trigger_lib/BUILD | 2 +- score/mw/log/legacy_non_verbose_api/BUILD | 2 +- score/test/{itf => integration}/BUILD | 34 ++------- score/test/{itf => integration}/defs.bzl | 6 +- score/test/{itf => integration}/dlt_parser.py | 0 .../{itf => integration}/filetransfer/BUILD | 4 +- .../filetransfer/etc/logging.json | 0 .../filetransfer/filetransfer_app.cpp | 0 .../filetransfer/test_filetransfer.py | 0 score/test/{itf => integration}/filters/BUILD | 43 +---------- .../filters/etc/class-id.json | 0 .../filters/etc/filtertest_logging.json | 0 .../filters/etc/logging.json | 0 .../filters/filtertest.cpp | 0 .../{itf => integration}/filters/filtertest.h | 0 .../filters/mwfiltertest.cpp | 0 .../filters/test_datarouter_filters.py | 0 .../filters/test_mw_verbose_filters.py | 0 .../{itf => integration}/logging_plugin.py | 0 score/test/{itf => integration}/mw_log/BUILD | 4 +- .../mw_log/etc/logging.json | 0 .../mw_log/logging_app.cpp | 0 .../mw_log/test_mw_log.py | 0 .../{itf => integration}/mw_log_kfile/BUILD | 4 +- .../mw_log_kfile/dlt_generator.cpp | 0 .../mw_log_kfile/etc/logging.json | 0 .../mw_log_kfile/test_mw_log_kfile.py | 0 score/test/itf/filters/arafiltertest.cpp | 75 ------------------- .../itf/filters/test_ara_verbose_filters.py | 54 ------------- 30 files changed, 22 insertions(+), 215 deletions(-) rename score/test/{itf => integration}/BUILD (73%) rename score/test/{itf => integration}/defs.bzl (94%) rename score/test/{itf => integration}/dlt_parser.py (100%) rename score/test/{itf => integration}/filetransfer/BUILD (91%) rename score/test/{itf => integration}/filetransfer/etc/logging.json (100%) rename score/test/{itf => integration}/filetransfer/filetransfer_app.cpp (100%) rename score/test/{itf => integration}/filetransfer/test_filetransfer.py (100%) rename score/test/{itf => integration}/filters/BUILD (75%) rename score/test/{itf => integration}/filters/etc/class-id.json (100%) rename score/test/{itf => integration}/filters/etc/filtertest_logging.json (100%) rename score/test/{itf => integration}/filters/etc/logging.json (100%) rename score/test/{itf => integration}/filters/filtertest.cpp (100%) rename score/test/{itf => integration}/filters/filtertest.h (100%) rename score/test/{itf => integration}/filters/mwfiltertest.cpp (100%) rename score/test/{itf => integration}/filters/test_datarouter_filters.py (100%) rename score/test/{itf => integration}/filters/test_mw_verbose_filters.py (100%) rename score/test/{itf => integration}/logging_plugin.py (100%) rename score/test/{itf => integration}/mw_log/BUILD (92%) rename score/test/{itf => integration}/mw_log/etc/logging.json (100%) rename score/test/{itf => integration}/mw_log/logging_app.cpp (100%) rename score/test/{itf => integration}/mw_log/test_mw_log.py (100%) rename score/test/{itf => integration}/mw_log_kfile/BUILD (92%) rename score/test/{itf => integration}/mw_log_kfile/dlt_generator.cpp (100%) rename score/test/{itf => integration}/mw_log_kfile/etc/logging.json (100%) rename score/test/{itf => integration}/mw_log_kfile/test_mw_log_kfile.py (100%) delete mode 100644 score/test/itf/filters/arafiltertest.cpp delete mode 100644 score/test/itf/filters/test_ara_verbose_filters.py diff --git a/score/datarouter/BUILD b/score/datarouter/BUILD index a99db96b..869bd5ec 100644 --- a/score/datarouter/BUILD +++ b/score/datarouter/BUILD @@ -367,22 +367,19 @@ filegroup( "//platform/aas/tools/sctf:__subpackages__", "//pqr/abc/abc-lmn/config/project/cpu/pas/datarouter:__pkg__", "//score/datarouter/test:__subpackages__", - "//score/test/itf:__subpackages__", + "//score/test/integration:__subpackages__", ], ) filegroup( - name = "all_config_files", + name = "integration_config_files", srcs = [ - "etc/key_value_storage_list.json", "etc/log-channels.json", "etc/logging.json", - "etc/persistent-database-override.json", - "etc/persistent-logging.json", "etc/raw-channels.json", ], visibility = [ - "//score/test/itf:__subpackages__", + "//score/test/integration:__subpackages__", ], ) diff --git a/score/datarouter/dlt_filetransfer_trigger_lib/BUILD b/score/datarouter/dlt_filetransfer_trigger_lib/BUILD index 7f1c1a00..8df3b423 100644 --- a/score/datarouter/dlt_filetransfer_trigger_lib/BUILD +++ b/score/datarouter/dlt_filetransfer_trigger_lib/BUILD @@ -43,7 +43,7 @@ cc_library( "//platform/aas/pas/datarouterconf/src/services:__pkg__", "//platform/aas/test/pas:__subpackages__", "//score/datarouter/test:__subpackages__", - "//score/test/itf:__subpackages__", + "//score/test/integration:__subpackages__", "@score_baselibs//score/logging:__pkg__", ], deps = [ diff --git a/score/mw/log/legacy_non_verbose_api/BUILD b/score/mw/log/legacy_non_verbose_api/BUILD index bbdd96b8..11e86b8b 100644 --- a/score/mw/log/legacy_non_verbose_api/BUILD +++ b/score/mw/log/legacy_non_verbose_api/BUILD @@ -36,7 +36,7 @@ cc_library( visibility = [ "//platform/aas/ara/log:__subpackages__", "//score/mw/log:__subpackages__", - "//score/test/itf:__subpackages__", + "//score/test/integration:__subpackages__", "@score_baselibs//score/mw/log:__subpackages__", "@score_logging//score/datarouter:__subpackages__", ], diff --git a/score/test/itf/BUILD b/score/test/integration/BUILD similarity index 73% rename from score/test/itf/BUILD rename to score/test/integration/BUILD index 3689de99..11c2f891 100644 --- a/score/test/itf/BUILD +++ b/score/test/integration/BUILD @@ -18,36 +18,14 @@ load("@score_itf//bazel:py_itf_plugin.bzl", "py_itf_plugin") # ============================================================================= # Shared base layers (included in every test image by the macro) # ============================================================================= - -# --- DLT daemon binaries (from @score_itf) --- pkg_tar( - name = "dlt_bins_pkg", + name = "dlt_pkg", + visibility = ["//score/test/integration:__subpackages__"], srcs = [ - "@score_itf//third_party/dlt:dlt-adaptor-stdin", - "@score_itf//third_party/dlt:dlt-daemon", "@score_itf//third_party/dlt:dlt-receive", ], - package_dir = "usr/bin", -) - -pkg_tar( - name = "dlt_conf_pkg", - srcs = [ - "@score_itf//third_party/dlt:dlt-daemon-conf", - ], - package_dir = "etc", -) - -pkg_tar( - name = "dlt_pkg", - visibility = ["//score/test/itf:__subpackages__"], - deps = [ - ":dlt_bins_pkg", - ":dlt_conf_pkg", - ], ) -# --- Datarouter binary + config --- pkg_tar( name = "datarouter_bin_pkg", srcs = ["//score/datarouter"], @@ -56,14 +34,14 @@ pkg_tar( pkg_tar( name = "datarouter_conf_pkg", - srcs = ["//score/datarouter:all_config_files"], + srcs = ["//score/datarouter:integration_config_files"], package_dir = "opt/datarouter", strip_prefix = "/score/datarouter", ) pkg_tar( name = "datarouter_pkg", - visibility = ["//score/test/itf:__subpackages__"], + visibility = ["//score/test/integration:__subpackages__"], deps = [ ":datarouter_bin_pkg", ":datarouter_conf_pkg", @@ -78,7 +56,7 @@ py_library( name = "dlt_parser", srcs = ["dlt_parser.py"], imports = ["."], - visibility = ["//score/test/itf:__subpackages__"], + visibility = ["//score/test/integration:__subpackages__"], ) py_library( @@ -94,5 +72,5 @@ py_itf_plugin( "logging_plugin", ], py_library = ":logging_plugin_lib", - visibility = ["//score/test/itf:__subpackages__"], + visibility = ["//score/test/integration:__subpackages__"], ) diff --git a/score/test/itf/defs.bzl b/score/test/integration/defs.bzl similarity index 94% rename from score/test/itf/defs.bzl rename to score/test/integration/defs.bzl index 4efc41b1..10814688 100644 --- a/score/test/itf/defs.bzl +++ b/score/test/integration/defs.bzl @@ -40,8 +40,8 @@ def py_logging_itf_test(name, srcs, filesystem, **kwargs): name = image_name, base = "@ubuntu_24_04", tars = [ - "//score/test/itf:dlt_pkg", - "//score/test/itf:datarouter_pkg", + "//score/test/integration:dlt_pkg", + "//score/test/integration:datarouter_pkg", filesystem, ], ) @@ -75,7 +75,7 @@ def py_logging_itf_test(name, srcs, filesystem, **kwargs): plugins = [ "@score_itf//score/itf/plugins:docker_plugin", "@score_itf//score/itf/plugins:dlt_plugin", - "//score/test/itf:logging_plugin", + "//score/test/integration:logging_plugin", ], env = {"DOCKER_HOST": ""}, **kwargs diff --git a/score/test/itf/dlt_parser.py b/score/test/integration/dlt_parser.py similarity index 100% rename from score/test/itf/dlt_parser.py rename to score/test/integration/dlt_parser.py diff --git a/score/test/itf/filetransfer/BUILD b/score/test/integration/filetransfer/BUILD similarity index 91% rename from score/test/itf/filetransfer/BUILD rename to score/test/integration/filetransfer/BUILD index 8371a96f..9a53260f 100644 --- a/score/test/itf/filetransfer/BUILD +++ b/score/test/integration/filetransfer/BUILD @@ -12,7 +12,7 @@ # ******************************************************************************* load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/itf:defs.bzl", "py_logging_itf_test") +load("//score/test/integration:defs.bzl", "py_logging_itf_test") cc_binary( name = "filetransfer_app", @@ -47,5 +47,5 @@ py_logging_itf_test( name = "test_filetransfer", srcs = ["test_filetransfer.py"], filesystem = ":filetransfer_filesystem", - deps = ["//score/test/itf:dlt_parser"], + deps = ["//score/test/integration:dlt_parser"], ) diff --git a/score/test/itf/filetransfer/etc/logging.json b/score/test/integration/filetransfer/etc/logging.json similarity index 100% rename from score/test/itf/filetransfer/etc/logging.json rename to score/test/integration/filetransfer/etc/logging.json diff --git a/score/test/itf/filetransfer/filetransfer_app.cpp b/score/test/integration/filetransfer/filetransfer_app.cpp similarity index 100% rename from score/test/itf/filetransfer/filetransfer_app.cpp rename to score/test/integration/filetransfer/filetransfer_app.cpp diff --git a/score/test/itf/filetransfer/test_filetransfer.py b/score/test/integration/filetransfer/test_filetransfer.py similarity index 100% rename from score/test/itf/filetransfer/test_filetransfer.py rename to score/test/integration/filetransfer/test_filetransfer.py diff --git a/score/test/itf/filters/BUILD b/score/test/integration/filters/BUILD similarity index 75% rename from score/test/itf/filters/BUILD rename to score/test/integration/filters/BUILD index 475844e7..2567c7d1 100644 --- a/score/test/itf/filters/BUILD +++ b/score/test/integration/filters/BUILD @@ -13,7 +13,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary") load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/itf:defs.bzl", "py_logging_itf_test") +load("//score/test/integration:defs.bzl", "py_logging_itf_test") cc_binary( name = "mwfiltertest", @@ -21,14 +21,6 @@ cc_binary( deps = ["//score/mw/log"], ) -cc_binary( - name = "arafiltertest", - srcs = ["arafiltertest.cpp"], - deps = ["//score/mw/log"], -) - -# --- Per-test filesystems --- - pkg_tar( name = "mwfiltertest_pkg", srcs = [":mwfiltertest"], @@ -49,45 +41,14 @@ pkg_tar( ], ) -pkg_tar( - name = "arafiltertest_pkg", - srcs = [":arafiltertest"], - package_dir = "opt/test_apps/arafiltertest/bin", -) - -pkg_tar( - name = "arafiltertest_config_pkg", - srcs = ["etc/logging.json"], - package_dir = "opt/test_apps/arafiltertest/etc", -) - -pkg_tar( - name = "arafiltertest_filesystem", - deps = [ - ":arafiltertest_config_pkg", - ":arafiltertest_pkg", - ], -) - -# --- Test targets --- - py_logging_itf_test( name = "test_mw_verbose_filters", srcs = ["test_mw_verbose_filters.py"], filesystem = ":mwfiltertest_filesystem", - deps = ["//score/test/itf:dlt_parser"], + deps = ["//score/test/integration:dlt_parser"], ) -py_logging_itf_test( - name = "test_ara_verbose_filters", - srcs = ["test_ara_verbose_filters.py"], - filesystem = ":arafiltertest_filesystem", - deps = ["//score/test/itf:dlt_parser"], -) - -# --- Non-verbose (TRACE) filter test --- # NOTE: Requires --//score/datarouter/build_configuration_flags:enable_nonverbose_dlt=True - cc_binary( name = "filtertest", srcs = [ diff --git a/score/test/itf/filters/etc/class-id.json b/score/test/integration/filters/etc/class-id.json similarity index 100% rename from score/test/itf/filters/etc/class-id.json rename to score/test/integration/filters/etc/class-id.json diff --git a/score/test/itf/filters/etc/filtertest_logging.json b/score/test/integration/filters/etc/filtertest_logging.json similarity index 100% rename from score/test/itf/filters/etc/filtertest_logging.json rename to score/test/integration/filters/etc/filtertest_logging.json diff --git a/score/test/itf/filters/etc/logging.json b/score/test/integration/filters/etc/logging.json similarity index 100% rename from score/test/itf/filters/etc/logging.json rename to score/test/integration/filters/etc/logging.json diff --git a/score/test/itf/filters/filtertest.cpp b/score/test/integration/filters/filtertest.cpp similarity index 100% rename from score/test/itf/filters/filtertest.cpp rename to score/test/integration/filters/filtertest.cpp diff --git a/score/test/itf/filters/filtertest.h b/score/test/integration/filters/filtertest.h similarity index 100% rename from score/test/itf/filters/filtertest.h rename to score/test/integration/filters/filtertest.h diff --git a/score/test/itf/filters/mwfiltertest.cpp b/score/test/integration/filters/mwfiltertest.cpp similarity index 100% rename from score/test/itf/filters/mwfiltertest.cpp rename to score/test/integration/filters/mwfiltertest.cpp diff --git a/score/test/itf/filters/test_datarouter_filters.py b/score/test/integration/filters/test_datarouter_filters.py similarity index 100% rename from score/test/itf/filters/test_datarouter_filters.py rename to score/test/integration/filters/test_datarouter_filters.py diff --git a/score/test/itf/filters/test_mw_verbose_filters.py b/score/test/integration/filters/test_mw_verbose_filters.py similarity index 100% rename from score/test/itf/filters/test_mw_verbose_filters.py rename to score/test/integration/filters/test_mw_verbose_filters.py diff --git a/score/test/itf/logging_plugin.py b/score/test/integration/logging_plugin.py similarity index 100% rename from score/test/itf/logging_plugin.py rename to score/test/integration/logging_plugin.py diff --git a/score/test/itf/mw_log/BUILD b/score/test/integration/mw_log/BUILD similarity index 92% rename from score/test/itf/mw_log/BUILD rename to score/test/integration/mw_log/BUILD index 9131921c..86b6a3d3 100644 --- a/score/test/itf/mw_log/BUILD +++ b/score/test/integration/mw_log/BUILD @@ -12,7 +12,7 @@ # ******************************************************************************* load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/itf:defs.bzl", "py_logging_itf_test") +load("//score/test/integration:defs.bzl", "py_logging_itf_test") cc_binary( name = "logging_app", @@ -45,7 +45,7 @@ py_logging_itf_test( srcs = ["test_mw_log.py"], filesystem = ":logging_app_filesystem", deps = [ - "//score/test/itf:dlt_parser", + "//score/test/integration:dlt_parser", "@score_itf//third_party/python_dlt", ], ) diff --git a/score/test/itf/mw_log/etc/logging.json b/score/test/integration/mw_log/etc/logging.json similarity index 100% rename from score/test/itf/mw_log/etc/logging.json rename to score/test/integration/mw_log/etc/logging.json diff --git a/score/test/itf/mw_log/logging_app.cpp b/score/test/integration/mw_log/logging_app.cpp similarity index 100% rename from score/test/itf/mw_log/logging_app.cpp rename to score/test/integration/mw_log/logging_app.cpp diff --git a/score/test/itf/mw_log/test_mw_log.py b/score/test/integration/mw_log/test_mw_log.py similarity index 100% rename from score/test/itf/mw_log/test_mw_log.py rename to score/test/integration/mw_log/test_mw_log.py diff --git a/score/test/itf/mw_log_kfile/BUILD b/score/test/integration/mw_log_kfile/BUILD similarity index 92% rename from score/test/itf/mw_log_kfile/BUILD rename to score/test/integration/mw_log_kfile/BUILD index bee7add3..fd69f019 100644 --- a/score/test/itf/mw_log_kfile/BUILD +++ b/score/test/integration/mw_log_kfile/BUILD @@ -12,7 +12,7 @@ # ******************************************************************************* load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/itf:defs.bzl", "py_logging_itf_test") +load("//score/test/integration:defs.bzl", "py_logging_itf_test") cc_binary( name = "dlt_generator", @@ -45,7 +45,7 @@ py_logging_itf_test( srcs = ["test_mw_log_kfile.py"], filesystem = ":dlt_generator_filesystem", deps = [ - "//score/test/itf:dlt_parser", + "//score/test/integration:dlt_parser", "@score_itf//third_party/python_dlt", ], ) diff --git a/score/test/itf/mw_log_kfile/dlt_generator.cpp b/score/test/integration/mw_log_kfile/dlt_generator.cpp similarity index 100% rename from score/test/itf/mw_log_kfile/dlt_generator.cpp rename to score/test/integration/mw_log_kfile/dlt_generator.cpp diff --git a/score/test/itf/mw_log_kfile/etc/logging.json b/score/test/integration/mw_log_kfile/etc/logging.json similarity index 100% rename from score/test/itf/mw_log_kfile/etc/logging.json rename to score/test/integration/mw_log_kfile/etc/logging.json diff --git a/score/test/itf/mw_log_kfile/test_mw_log_kfile.py b/score/test/integration/mw_log_kfile/test_mw_log_kfile.py similarity index 100% rename from score/test/itf/mw_log_kfile/test_mw_log_kfile.py rename to score/test/integration/mw_log_kfile/test_mw_log_kfile.py diff --git a/score/test/itf/filters/arafiltertest.cpp b/score/test/itf/filters/arafiltertest.cpp deleted file mode 100644 index b43e526d..00000000 --- a/score/test/itf/filters/arafiltertest.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// ******************************************************************************* -// Copyright (c) 2025 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// ******************************************************************************* - -#include "score/mw/log/logger.h" -#include "score/mw/log/logging.h" - -#include - -// With filtering configured for this app in the attached logging.json file, -// totally 22 ( 1 + 2 + 3 + 4 + 5 + 6 + 1 = 22) messages should be visible in DLT -int main() -{ - score::mw::log::Logger logger_1{score::mw::log::CreateLogger("FAT", "Fatal")}; - logger_1.LogFatal() << "Fatal message"; - logger_1.LogError() << "Error message"; - logger_1.LogWarn() << "Warn message"; - logger_1.LogInfo() << "Info message"; - logger_1.LogDebug() << "Debug message"; - logger_1.LogVerbose() << "Verbose message"; - - score::mw::log::Logger logger_2{score::mw::log::CreateLogger("ERR", "Error")}; - logger_2.LogFatal() << "Fatal message"; - logger_2.LogError() << "Error message"; - logger_2.LogWarn() << "Warn message"; - logger_2.LogInfo() << "Info message"; - logger_2.LogDebug() << "Debug message"; - logger_2.LogVerbose() << "Verbose message"; - - score::mw::log::Logger logger_3{score::mw::log::CreateLogger("WRN", "Warn")}; - logger_3.LogFatal() << "Fatal message"; - logger_3.LogError() << "Error message"; - logger_3.LogWarn() << "Warn message"; - logger_3.LogInfo() << "Info message"; - logger_3.LogDebug() << "Debug message"; - logger_3.LogVerbose() << "Verbose message"; - - score::mw::log::Logger logger_4{score::mw::log::CreateLogger("INF", "Info")}; - logger_4.LogFatal() << "Fatal message"; - logger_4.LogError() << "Error message"; - logger_4.LogWarn() << "Warn message"; - logger_4.LogInfo() << "Info message"; - logger_4.LogDebug() << "Debug message"; - logger_4.LogVerbose() << "Verbose message"; - - score::mw::log::Logger logger_5{score::mw::log::CreateLogger("DBG", "Debug")}; - logger_5.LogFatal() << "Fatal message"; - logger_5.LogError() << "Error message"; - logger_5.LogWarn() << "Warn message"; - logger_5.LogInfo() << "Info message"; - logger_5.LogDebug() << "Debug message"; - logger_5.LogVerbose() << "Verbose message"; - - score::mw::log::Logger logger_6{score::mw::log::CreateLogger("VBS", "Verbose")}; - logger_6.LogFatal() << "Fatal message"; - logger_6.LogError() << "Error message"; - logger_6.LogWarn() << "Warn message"; - logger_6.LogInfo() << "Info message"; - logger_6.LogDebug() << "Debug message"; - logger_6.LogVerbose() << "Verbose message"; - - score::mw::log::LogFatal() << "LogFatal"; - - sleep(1); - return 0; -} diff --git a/score/test/itf/filters/test_ara_verbose_filters.py b/score/test/itf/filters/test_ara_verbose_filters.py deleted file mode 100644 index 51e484b2..00000000 --- a/score/test/itf/filters/test_ara_verbose_filters.py +++ /dev/null @@ -1,54 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* - -"""Integration test for mw::log verbose log-level filtering (instance Logger API). - -Same verification as test_mw_verbose_filters but exercises the AUTOSAR-style -CreateLogger() instance API instead of free functions. -""" - -import logging - -from dlt_parser import count_messages_by_context - - -LOGGER = logging.getLogger(__name__) - -TOTAL_VERBOSE_MESSAGES = 22 -TEST_APP_ID = "TAP" -CONTEXT_IDS = {"FAT", "ERR", "WRN", "INF", "DBG", "VBS"} - - -def test_ara_verbose_filters(target, datarouter_on_target, dlt_capture): - """Verify per-context verbose log-level filtering with instance Logger API. - - Same expected counts as test_mw_verbose_filters: - FAT=1, ERR=2, WRN=3, INF=4, DBG=5, VBS=6, total=22 - """ - with dlt_capture() as receiver: - target.execute("cd /opt/test_apps/arafiltertest && ./bin/arafiltertest") - - output = receiver.get_output() - LOGGER.info(f"DLT output length: {len(output)} chars") - - counts, total = count_messages_by_context(output, TEST_APP_ID, CONTEXT_IDS) - - assert counts.get("FAT", 0) == 1, f"FAT: expected 1, got {counts.get('FAT', 0)}" - assert counts.get("ERR", 0) == 2, f"ERR: expected 2, got {counts.get('ERR', 0)}" - assert counts.get("WRN", 0) == 3, f"WRN: expected 3, got {counts.get('WRN', 0)}" - assert counts.get("INF", 0) == 4, f"INF: expected 4, got {counts.get('INF', 0)}" - assert counts.get("DBG", 0) == 5, f"DBG: expected 5, got {counts.get('DBG', 0)}" - assert counts.get("VBS", 0) == 6, f"VBS: expected 6, got {counts.get('VBS', 0)}" - assert total == TOTAL_VERBOSE_MESSAGES, ( - f"Total: expected {TOTAL_VERBOSE_MESSAGES}, got {total}" - ) From 14ae76f112c1d57a3b7bf35905037cf00d094619 Mon Sep 17 00:00:00 2001 From: rahulsasingh Date: Thu, 21 May 2026 06:53:20 +0200 Subject: [PATCH 10/11] Address review comments: rename to component, remove dlt_parser - Move score/test/integration/ -> score/test/component/ to distinguish from nightly integration tests (reviewer: rmaddikery) - Rename integration_config_files -> integration_test_config_files in score/datarouter/BUILD (reviewer: rmaddikery) - Remove custom dlt_parser.py; refactor all tests to use DltLogRecord from score_itf (score.itf.plugins.dlt.dlt_window) via download_dlt() helper in logging_plugin.py (reviewer: rmaddikery) --- score/datarouter/BUILD | 6 +- .../dlt_filetransfer_trigger_lib/BUILD | 2 +- score/mw/log/legacy_non_verbose_api/BUILD | 2 +- score/test/{integration => component}/BUILD | 15 +-- .../test/{integration => component}/defs.bzl | 6 +- .../filetransfer/BUILD | 4 +- .../filetransfer/etc/logging.json | 0 .../filetransfer/filetransfer_app.cpp | 0 .../filetransfer/test_filetransfer.py | 32 ++---- .../{integration => component}/filters/BUILD | 3 +- .../filters/etc/class-id.json | 0 .../filters/etc/filtertest_logging.json | 0 .../filters/etc/logging.json | 0 .../filters/filtertest.cpp | 0 .../filters/filtertest.h | 0 .../filters/mwfiltertest.cpp | 0 .../filters/test_datarouter_filters.py | 0 .../filters/test_mw_verbose_filters.py | 25 ++--- .../logging_plugin.py | 0 .../{integration => component}/mw_log/BUILD | 4 +- .../mw_log/etc/logging.json | 0 .../mw_log/logging_app.cpp | 0 .../mw_log/test_mw_log.py | 66 +++---------- .../mw_log_kfile/BUILD | 4 +- .../mw_log_kfile/dlt_generator.cpp | 0 .../mw_log_kfile/etc/logging.json | 0 .../mw_log_kfile/test_mw_log_kfile.py | 34 ++----- score/test/integration/dlt_parser.py | 99 ------------------- 28 files changed, 61 insertions(+), 241 deletions(-) rename score/test/{integration => component}/BUILD (82%) rename score/test/{integration => component}/defs.bzl (94%) rename score/test/{integration => component}/filetransfer/BUILD (91%) rename score/test/{integration => component}/filetransfer/etc/logging.json (100%) rename score/test/{integration => component}/filetransfer/filetransfer_app.cpp (100%) rename score/test/{integration => component}/filetransfer/test_filetransfer.py (72%) rename score/test/{integration => component}/filters/BUILD (96%) rename score/test/{integration => component}/filters/etc/class-id.json (100%) rename score/test/{integration => component}/filters/etc/filtertest_logging.json (100%) rename score/test/{integration => component}/filters/etc/logging.json (100%) rename score/test/{integration => component}/filters/filtertest.cpp (100%) rename score/test/{integration => component}/filters/filtertest.h (100%) rename score/test/{integration => component}/filters/mwfiltertest.cpp (100%) rename score/test/{integration => component}/filters/test_datarouter_filters.py (100%) rename score/test/{integration => component}/filters/test_mw_verbose_filters.py (72%) rename score/test/{integration => component}/logging_plugin.py (100%) rename score/test/{integration => component}/mw_log/BUILD (92%) rename score/test/{integration => component}/mw_log/etc/logging.json (100%) rename score/test/{integration => component}/mw_log/logging_app.cpp (100%) rename score/test/{integration => component}/mw_log/test_mw_log.py (70%) rename score/test/{integration => component}/mw_log_kfile/BUILD (92%) rename score/test/{integration => component}/mw_log_kfile/dlt_generator.cpp (100%) rename score/test/{integration => component}/mw_log_kfile/etc/logging.json (100%) rename score/test/{integration => component}/mw_log_kfile/test_mw_log_kfile.py (78%) delete mode 100644 score/test/integration/dlt_parser.py diff --git a/score/datarouter/BUILD b/score/datarouter/BUILD index 869bd5ec..1dd58f29 100644 --- a/score/datarouter/BUILD +++ b/score/datarouter/BUILD @@ -367,19 +367,19 @@ filegroup( "//platform/aas/tools/sctf:__subpackages__", "//pqr/abc/abc-lmn/config/project/cpu/pas/datarouter:__pkg__", "//score/datarouter/test:__subpackages__", - "//score/test/integration:__subpackages__", + "//score/test/component:__subpackages__", ], ) filegroup( - name = "integration_config_files", + name = "integration_test_config_files", srcs = [ "etc/log-channels.json", "etc/logging.json", "etc/raw-channels.json", ], visibility = [ - "//score/test/integration:__subpackages__", + "//score/test/component:__subpackages__", ], ) diff --git a/score/datarouter/dlt_filetransfer_trigger_lib/BUILD b/score/datarouter/dlt_filetransfer_trigger_lib/BUILD index 8df3b423..928d4101 100644 --- a/score/datarouter/dlt_filetransfer_trigger_lib/BUILD +++ b/score/datarouter/dlt_filetransfer_trigger_lib/BUILD @@ -43,7 +43,7 @@ cc_library( "//platform/aas/pas/datarouterconf/src/services:__pkg__", "//platform/aas/test/pas:__subpackages__", "//score/datarouter/test:__subpackages__", - "//score/test/integration:__subpackages__", + "//score/test/component:__subpackages__", "@score_baselibs//score/logging:__pkg__", ], deps = [ diff --git a/score/mw/log/legacy_non_verbose_api/BUILD b/score/mw/log/legacy_non_verbose_api/BUILD index 11e86b8b..dca3d4ca 100644 --- a/score/mw/log/legacy_non_verbose_api/BUILD +++ b/score/mw/log/legacy_non_verbose_api/BUILD @@ -36,7 +36,7 @@ cc_library( visibility = [ "//platform/aas/ara/log:__subpackages__", "//score/mw/log:__subpackages__", - "//score/test/integration:__subpackages__", + "//score/test/component:__subpackages__", "@score_baselibs//score/mw/log:__subpackages__", "@score_logging//score/datarouter:__subpackages__", ], diff --git a/score/test/integration/BUILD b/score/test/component/BUILD similarity index 82% rename from score/test/integration/BUILD rename to score/test/component/BUILD index 11c2f891..0241f230 100644 --- a/score/test/integration/BUILD +++ b/score/test/component/BUILD @@ -20,10 +20,10 @@ load("@score_itf//bazel:py_itf_plugin.bzl", "py_itf_plugin") # ============================================================================= pkg_tar( name = "dlt_pkg", - visibility = ["//score/test/integration:__subpackages__"], srcs = [ "@score_itf//third_party/dlt:dlt-receive", ], + visibility = ["//score/test/component:__subpackages__"], ) pkg_tar( @@ -34,14 +34,14 @@ pkg_tar( pkg_tar( name = "datarouter_conf_pkg", - srcs = ["//score/datarouter:integration_config_files"], + srcs = ["//score/datarouter:integration_test_config_files"], package_dir = "opt/datarouter", strip_prefix = "/score/datarouter", ) pkg_tar( name = "datarouter_pkg", - visibility = ["//score/test/integration:__subpackages__"], + visibility = ["//score/test/component:__subpackages__"], deps = [ ":datarouter_bin_pkg", ":datarouter_conf_pkg", @@ -52,13 +52,6 @@ pkg_tar( # Shared Python libraries and plugin # ============================================================================= -py_library( - name = "dlt_parser", - srcs = ["dlt_parser.py"], - imports = ["."], - visibility = ["//score/test/integration:__subpackages__"], -) - py_library( name = "logging_plugin_lib", srcs = ["logging_plugin.py"], @@ -72,5 +65,5 @@ py_itf_plugin( "logging_plugin", ], py_library = ":logging_plugin_lib", - visibility = ["//score/test/integration:__subpackages__"], + visibility = ["//score/test/component:__subpackages__"], ) diff --git a/score/test/integration/defs.bzl b/score/test/component/defs.bzl similarity index 94% rename from score/test/integration/defs.bzl rename to score/test/component/defs.bzl index 10814688..f4bc3cb5 100644 --- a/score/test/integration/defs.bzl +++ b/score/test/component/defs.bzl @@ -40,8 +40,8 @@ def py_logging_itf_test(name, srcs, filesystem, **kwargs): name = image_name, base = "@ubuntu_24_04", tars = [ - "//score/test/integration:dlt_pkg", - "//score/test/integration:datarouter_pkg", + "//score/test/component:dlt_pkg", + "//score/test/component:datarouter_pkg", filesystem, ], ) @@ -75,7 +75,7 @@ def py_logging_itf_test(name, srcs, filesystem, **kwargs): plugins = [ "@score_itf//score/itf/plugins:docker_plugin", "@score_itf//score/itf/plugins:dlt_plugin", - "//score/test/integration:logging_plugin", + "//score/test/component:logging_plugin", ], env = {"DOCKER_HOST": ""}, **kwargs diff --git a/score/test/integration/filetransfer/BUILD b/score/test/component/filetransfer/BUILD similarity index 91% rename from score/test/integration/filetransfer/BUILD rename to score/test/component/filetransfer/BUILD index 9a53260f..1b7e6fe5 100644 --- a/score/test/integration/filetransfer/BUILD +++ b/score/test/component/filetransfer/BUILD @@ -11,8 +11,9 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/integration:defs.bzl", "py_logging_itf_test") +load("//score/test/component:defs.bzl", "py_logging_itf_test") cc_binary( name = "filetransfer_app", @@ -47,5 +48,4 @@ py_logging_itf_test( name = "test_filetransfer", srcs = ["test_filetransfer.py"], filesystem = ":filetransfer_filesystem", - deps = ["//score/test/integration:dlt_parser"], ) diff --git a/score/test/integration/filetransfer/etc/logging.json b/score/test/component/filetransfer/etc/logging.json similarity index 100% rename from score/test/integration/filetransfer/etc/logging.json rename to score/test/component/filetransfer/etc/logging.json diff --git a/score/test/integration/filetransfer/filetransfer_app.cpp b/score/test/component/filetransfer/filetransfer_app.cpp similarity index 100% rename from score/test/integration/filetransfer/filetransfer_app.cpp rename to score/test/component/filetransfer/filetransfer_app.cpp diff --git a/score/test/integration/filetransfer/test_filetransfer.py b/score/test/component/filetransfer/test_filetransfer.py similarity index 72% rename from score/test/integration/filetransfer/test_filetransfer.py rename to score/test/component/filetransfer/test_filetransfer.py index 89853250..9e27a09b 100644 --- a/score/test/integration/filetransfer/test_filetransfer.py +++ b/score/test/component/filetransfer/test_filetransfer.py @@ -26,7 +26,7 @@ import logging import pytest -from dlt_parser import parse_messages +from logging_plugin import download_dlt LOGGER = logging.getLogger(__name__) @@ -36,26 +36,17 @@ def test_filetransfer(target, datarouter_on_target, dlt_capture): - """Verify that file transfer DLT messages are sent and received. - - The filetransfer_app creates test files and sends them via the - FileTransfer API. We verify: - 1. The app's lifecycle log messages are received via UDP - 2. All NUM_TRANSFERS transfers are confirmed by app-level log messages - 3. The test files exist on the target filesystem - """ + """Verify that file transfer DLT messages are sent and received.""" with dlt_capture() as receiver: target.execute("cd /opt/test_apps/filetransfer && ./bin/filetransfer_app") - output = receiver.get_output() - LOGGER.info(f"DLT output length: {len(output)} chars") - - messages = parse_messages(output, APP_ID) + record = download_dlt(target, receiver.dlt_file) + messages = record.find(query=dict(apid=APP_ID)) LOGGER.info(f"App message count: {len(messages)}") assert len(messages) > 0, "No DLT messages received from filetransfer_app" - app_payloads = "\n".join(m.payload for m in messages) + app_payloads = "\n".join(str(m.payload) for m in messages) # Verify lifecycle messages assert "initialize" in app_payloads, "Missing 'initialize' message" @@ -63,7 +54,7 @@ def test_filetransfer(target, datarouter_on_target, dlt_capture): assert "done" in app_payloads, "Missing 'done' message" # Verify transfer confirmations from the app - transfer_msgs = [m for m in messages if "Transferred file" in m.payload] + transfer_msgs = [m for m in messages if "Transferred file" in str(m.payload)] assert len(transfer_msgs) == NUM_TRANSFERS, ( f"Expected {NUM_TRANSFERS} transfer confirmations, got {len(transfer_msgs)}" ) @@ -82,13 +73,4 @@ def test_filetransfer(target, datarouter_on_target, dlt_capture): reason="file_transfer_impl not available in this repo — FLST/FLDA/FLFI protocol messages are not emitted" ) def test_filetransfer_protocol_verification(target, datarouter_on_target, dlt_capture): - """Verify DLT file transfer protocol messages (FLST/FLDA/FLFI) and hash integrity. - - This test verifies the low-level DLT file transfer protocol, including: - - FLST (file transfer start) messages with correct file metadata - - FLDA (file transfer data) messages containing file content - - FLFI (file transfer finish) messages with MD5 hash verification - - Requires file_transfer_impl/ to be present and file_transfer=True in .bazelrc. - Currently blocked because file_transfer_impl/ does not exist in this repo. - """ + """Verify DLT file transfer protocol messages (FLST/FLDA/FLFI) and hash integrity.""" diff --git a/score/test/integration/filters/BUILD b/score/test/component/filters/BUILD similarity index 96% rename from score/test/integration/filters/BUILD rename to score/test/component/filters/BUILD index 2567c7d1..0e065e4e 100644 --- a/score/test/integration/filters/BUILD +++ b/score/test/component/filters/BUILD @@ -13,7 +13,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary") load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/integration:defs.bzl", "py_logging_itf_test") +load("//score/test/component:defs.bzl", "py_logging_itf_test") cc_binary( name = "mwfiltertest", @@ -45,7 +45,6 @@ py_logging_itf_test( name = "test_mw_verbose_filters", srcs = ["test_mw_verbose_filters.py"], filesystem = ":mwfiltertest_filesystem", - deps = ["//score/test/integration:dlt_parser"], ) # NOTE: Requires --//score/datarouter/build_configuration_flags:enable_nonverbose_dlt=True diff --git a/score/test/integration/filters/etc/class-id.json b/score/test/component/filters/etc/class-id.json similarity index 100% rename from score/test/integration/filters/etc/class-id.json rename to score/test/component/filters/etc/class-id.json diff --git a/score/test/integration/filters/etc/filtertest_logging.json b/score/test/component/filters/etc/filtertest_logging.json similarity index 100% rename from score/test/integration/filters/etc/filtertest_logging.json rename to score/test/component/filters/etc/filtertest_logging.json diff --git a/score/test/integration/filters/etc/logging.json b/score/test/component/filters/etc/logging.json similarity index 100% rename from score/test/integration/filters/etc/logging.json rename to score/test/component/filters/etc/logging.json diff --git a/score/test/integration/filters/filtertest.cpp b/score/test/component/filters/filtertest.cpp similarity index 100% rename from score/test/integration/filters/filtertest.cpp rename to score/test/component/filters/filtertest.cpp diff --git a/score/test/integration/filters/filtertest.h b/score/test/component/filters/filtertest.h similarity index 100% rename from score/test/integration/filters/filtertest.h rename to score/test/component/filters/filtertest.h diff --git a/score/test/integration/filters/mwfiltertest.cpp b/score/test/component/filters/mwfiltertest.cpp similarity index 100% rename from score/test/integration/filters/mwfiltertest.cpp rename to score/test/component/filters/mwfiltertest.cpp diff --git a/score/test/integration/filters/test_datarouter_filters.py b/score/test/component/filters/test_datarouter_filters.py similarity index 100% rename from score/test/integration/filters/test_datarouter_filters.py rename to score/test/component/filters/test_datarouter_filters.py diff --git a/score/test/integration/filters/test_mw_verbose_filters.py b/score/test/component/filters/test_mw_verbose_filters.py similarity index 72% rename from score/test/integration/filters/test_mw_verbose_filters.py rename to score/test/component/filters/test_mw_verbose_filters.py index d7574d9d..a362a445 100644 --- a/score/test/integration/filters/test_mw_verbose_filters.py +++ b/score/test/component/filters/test_mw_verbose_filters.py @@ -24,14 +24,13 @@ import logging -from dlt_parser import count_messages_by_context - +from logging_plugin import download_dlt LOGGER = logging.getLogger(__name__) TOTAL_VERBOSE_MESSAGES = 22 TEST_APP_ID = "TAP" -CONTEXT_IDS = {"FAT", "ERR", "WRN", "INF", "DBG", "VBS"} +CONTEXT_IDS = ["FAT", "ERR", "WRN", "INF", "DBG", "VBS"] def test_mw_verbose_filters(target, datarouter_on_target, dlt_capture): @@ -49,17 +48,19 @@ def test_mw_verbose_filters(target, datarouter_on_target, dlt_capture): with dlt_capture() as receiver: target.execute("cd /opt/test_apps/mwfiltertest && ./bin/mwfiltertest") - output = receiver.get_output() - LOGGER.info(f"DLT output length: {len(output)} chars") + record = download_dlt(target, receiver.dlt_file) + + def count(ctx): + return len(record.find(query=dict(apid=TEST_APP_ID, ctid=ctx))) - counts, total = count_messages_by_context(output, TEST_APP_ID, CONTEXT_IDS) + assert count("FAT") == 1, f"FAT: expected 1, got {count('FAT')}" + assert count("ERR") == 2, f"ERR: expected 2, got {count('ERR')}" + assert count("WRN") == 3, f"WRN: expected 3, got {count('WRN')}" + assert count("INF") == 4, f"INF: expected 4, got {count('INF')}" + assert count("DBG") == 5, f"DBG: expected 5, got {count('DBG')}" + assert count("VBS") == 6, f"VBS: expected 6, got {count('VBS')}" - assert counts.get("FAT", 0) == 1, f"FAT: expected 1, got {counts.get('FAT', 0)}" - assert counts.get("ERR", 0) == 2, f"ERR: expected 2, got {counts.get('ERR', 0)}" - assert counts.get("WRN", 0) == 3, f"WRN: expected 3, got {counts.get('WRN', 0)}" - assert counts.get("INF", 0) == 4, f"INF: expected 4, got {counts.get('INF', 0)}" - assert counts.get("DBG", 0) == 5, f"DBG: expected 5, got {counts.get('DBG', 0)}" - assert counts.get("VBS", 0) == 6, f"VBS: expected 6, got {counts.get('VBS', 0)}" + total = sum(count(ctx) for ctx in CONTEXT_IDS) assert total == TOTAL_VERBOSE_MESSAGES, ( f"Total: expected {TOTAL_VERBOSE_MESSAGES}, got {total}" ) diff --git a/score/test/integration/logging_plugin.py b/score/test/component/logging_plugin.py similarity index 100% rename from score/test/integration/logging_plugin.py rename to score/test/component/logging_plugin.py diff --git a/score/test/integration/mw_log/BUILD b/score/test/component/mw_log/BUILD similarity index 92% rename from score/test/integration/mw_log/BUILD rename to score/test/component/mw_log/BUILD index 86b6a3d3..71b9a217 100644 --- a/score/test/integration/mw_log/BUILD +++ b/score/test/component/mw_log/BUILD @@ -11,8 +11,9 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/integration:defs.bzl", "py_logging_itf_test") +load("//score/test/component:defs.bzl", "py_logging_itf_test") cc_binary( name = "logging_app", @@ -45,7 +46,6 @@ py_logging_itf_test( srcs = ["test_mw_log.py"], filesystem = ":logging_app_filesystem", deps = [ - "//score/test/integration:dlt_parser", "@score_itf//third_party/python_dlt", ], ) diff --git a/score/test/integration/mw_log/etc/logging.json b/score/test/component/mw_log/etc/logging.json similarity index 100% rename from score/test/integration/mw_log/etc/logging.json rename to score/test/component/mw_log/etc/logging.json diff --git a/score/test/integration/mw_log/logging_app.cpp b/score/test/component/mw_log/logging_app.cpp similarity index 100% rename from score/test/integration/mw_log/logging_app.cpp rename to score/test/component/mw_log/logging_app.cpp diff --git a/score/test/integration/mw_log/test_mw_log.py b/score/test/component/mw_log/test_mw_log.py similarity index 70% rename from score/test/integration/mw_log/test_mw_log.py rename to score/test/component/mw_log/test_mw_log.py index 180e4e67..7719fa89 100644 --- a/score/test/integration/mw_log/test_mw_log.py +++ b/score/test/component/mw_log/test_mw_log.py @@ -24,7 +24,7 @@ import tempfile import dlt.dlt as python_dlt -from dlt_parser import parse_messages +from logging_plugin import download_dlt LOGGER = logging.getLogger(__name__) @@ -32,16 +32,15 @@ LOGGING_APP_ID = "EXA" LOGGING_APP_CMD = "cd /opt/test_apps/logging_app && ./bin/logging_app" -# Expected substrings that must appear in the DLT output from our app. -# These match the structured content of each message emitted by logging_app.cpp -# as formatted by dlt-receive -a text output. -# NOTE: dlt-receive -a renders bool as 1/0 (not True/False), -# UINT64_MAX as -1 (signed), and raw buffers as hex bytes. -VALUES_TO_CHECK_REMOTE = [ +# Expected substrings for DLT binary file output parsed by python-dlt. +# Differs from dlt-receive -a (remote) in: +# - UINT64_MAX renders as 18446744073709551615 (unsigned, not -1) +# - log_raw_buffer renders as 72'61'77 (apostrophe-separated hex) +VALUES_TO_CHECK_FILE = [ "Logging Application DoLogging", "val_bool 1", "val_uint8t 123 val_uint16t 1234 val_uint32t 12345 val_uint64t 123456", - "val_uint8tmax 255 val_uint16tmax 65535 val_uint32tmax 4294967295 val_uint64tmax -1", + "val_uint8tmax 255 val_uint16tmax 65535 val_uint32tmax 4294967295 val_uint64tmax 18446744073709551615", "val_int8t -34 val_int16t -14576 val_int32t -2147483640 val_int64t -9223372036854775700", "val_int8tmax 127 val_int16tmax 32767 val_int32tmax 2147483647 val_int64tmax 9223372036854775807", "val_int8tmin -128 val_int16tmin -32768 val_int32tmin -2147483648 val_int64tmin -9223372036854775808", @@ -55,11 +54,6 @@ ] # Expected substrings for console output (captured from the app's stdout). -# Console output differs from dlt-receive -a in several ways: -# - val_bool renders as True (not 1) -# - UINT64_MAX renders as 18446744073709551615 (unsigned) not -1 -# - val_double has more decimal places (93454.600000) -# - log_raw_buffer renders as contiguous hex string (726177) VALUES_TO_CHECK_CONSOLE = [ "Logging Application DoLogging", "val_bool True", @@ -77,56 +71,27 @@ "log_slog2_message slog2_message", ] -# Expected substrings for DLT binary file output parsed by python-dlt. -# Differs from dlt-receive -a (remote) in: -# - UINT64_MAX renders as 18446744073709551615 (unsigned, not -1) -# - log_raw_buffer renders as 72'61'77 (apostrophe-separated hex) -VALUES_TO_CHECK_FILE = [ - "Logging Application DoLogging", - "val_bool 1", - "val_uint8t 123 val_uint16t 1234 val_uint32t 12345 val_uint64t 123456", - "val_uint8tmax 255 val_uint16tmax 65535 val_uint32tmax 4294967295 val_uint64tmax 18446744073709551615", - "val_int8t -34 val_int16t -14576 val_int32t -2147483640 val_int64t -9223372036854775700", - "val_int8tmax 127 val_int16tmax 32767 val_int32tmax 2147483647 val_int64tmax 9223372036854775807", - "val_int8tmin -128 val_int16tmin -32768 val_int32tmin -2147483648 val_int64tmin -9223372036854775808", - "val_int8tminplusint8t -94 val_int16tminplusint16t -18192 val_int32tminplusint32t -8 val_int64tminplusint64t -108", - "val_string Logging", - "val_double 93454.6", - "log_hex_8 10 log_hex_16 9876 log_hex_32 543210987 log_hex_64 654321098765432109", - "log_bin_8 8 log_bin_16 9012 log_bin_32 3456789012 log_bin_64 3456789012345678901", - "log_raw_buffer", - "log_slog2_message slog2_message", -] - def test_mw_log_remote_logging(target, datarouter_on_target, dlt_capture): """Verify all data types are correctly logged and received via DLT.""" with dlt_capture() as receiver: target.execute(LOGGING_APP_CMD) - output = receiver.get_output() - LOGGER.info(f"DLT output length: {len(output)} chars") - - messages = parse_messages(output, LOGGING_APP_ID) + record = download_dlt(target, receiver.dlt_file) + messages = record.find(query=dict(apid=LOGGING_APP_ID)) LOGGER.info(f"Received {len(messages)} messages from {LOGGING_APP_ID}") for msg in messages: LOGGER.info(f" [{msg.ctid}] {msg.payload}") assert len(messages) > 0, "No DLT messages received from logging_app" - app_output = "\n".join(msg.payload for msg in messages) - missing = [v for v in VALUES_TO_CHECK_REMOTE if v not in app_output] + app_output = "\n".join(str(msg.payload) for msg in messages) + missing = [v for v in VALUES_TO_CHECK_FILE if v not in app_output] assert not missing, f"Missing expected values in DLT output: {missing}" def test_mw_log_console_logging(target, datarouter_on_target): - """Verify all data types are correctly logged to console (stdout). - - The app writes DLT-formatted log lines to stdout when logMode includes - kConsole. Console rendering differs from dlt-receive -a in how certain - types are formatted (unsigned vs signed integers, binary representations, - raw buffer hex encoding, double precision). - """ + """Verify all data types are correctly logged to console (stdout).""" proc = target.execute_async( "/opt/test_apps/logging_app/bin/logging_app", cwd="/opt/test_apps/logging_app", @@ -143,12 +108,7 @@ def test_mw_log_console_logging(target, datarouter_on_target): def test_mw_log_file_logging(target, datarouter_on_target): - """Verify all data types are correctly logged to a .dlt file on disk. - - The app writes DLT binary messages to /tmp/EXA.dlt when logMode includes - kFile. The test downloads the file and parses it with python-dlt to verify - that all expected values are present in the message payloads. - """ + """Verify all data types are correctly logged to a .dlt file on disk.""" target.execute(LOGGING_APP_CMD) with tempfile.TemporaryDirectory() as tmpdir: diff --git a/score/test/integration/mw_log_kfile/BUILD b/score/test/component/mw_log_kfile/BUILD similarity index 92% rename from score/test/integration/mw_log_kfile/BUILD rename to score/test/component/mw_log_kfile/BUILD index fd69f019..cc8381e4 100644 --- a/score/test/integration/mw_log_kfile/BUILD +++ b/score/test/component/mw_log_kfile/BUILD @@ -11,8 +11,9 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_pkg//pkg:tar.bzl", "pkg_tar") -load("//score/test/integration:defs.bzl", "py_logging_itf_test") +load("//score/test/component:defs.bzl", "py_logging_itf_test") cc_binary( name = "dlt_generator", @@ -45,7 +46,6 @@ py_logging_itf_test( srcs = ["test_mw_log_kfile.py"], filesystem = ":dlt_generator_filesystem", deps = [ - "//score/test/integration:dlt_parser", "@score_itf//third_party/python_dlt", ], ) diff --git a/score/test/integration/mw_log_kfile/dlt_generator.cpp b/score/test/component/mw_log_kfile/dlt_generator.cpp similarity index 100% rename from score/test/integration/mw_log_kfile/dlt_generator.cpp rename to score/test/component/mw_log_kfile/dlt_generator.cpp diff --git a/score/test/integration/mw_log_kfile/etc/logging.json b/score/test/component/mw_log_kfile/etc/logging.json similarity index 100% rename from score/test/integration/mw_log_kfile/etc/logging.json rename to score/test/component/mw_log_kfile/etc/logging.json diff --git a/score/test/integration/mw_log_kfile/test_mw_log_kfile.py b/score/test/component/mw_log_kfile/test_mw_log_kfile.py similarity index 78% rename from score/test/integration/mw_log_kfile/test_mw_log_kfile.py rename to score/test/component/mw_log_kfile/test_mw_log_kfile.py index 74637b43..fe108860 100644 --- a/score/test/integration/mw_log_kfile/test_mw_log_kfile.py +++ b/score/test/component/mw_log_kfile/test_mw_log_kfile.py @@ -25,8 +25,7 @@ import tempfile import dlt.dlt as python_dlt - -from dlt_parser import parse_messages +from logging_plugin import download_dlt LOGGER = logging.getLogger(__name__) @@ -63,13 +62,7 @@ def _verify_kfile_messages(target, expected): def test_mw_log_kfile(target, datarouter_on_target, dlt_capture): - """Verify kFile logging produces the expected number of messages. - - Runs dlt_generator with 100 iterations, each producing 6 log messages - (Fatal, Error, Warn, Info, Verbose, Debug). Verifies the exact count - from the on-disk .dlt file. Remote DLT output via UDP is logged for - diagnostics but not asserted exactly. - """ + """Verify kFile logging produces the expected number of messages.""" expected = ITERATIONS * MESSAGES_PER_ITERATION with dlt_capture() as receiver: @@ -79,25 +72,16 @@ def test_mw_log_kfile(target, datarouter_on_target, dlt_capture): ) # Log remote DLT count for diagnostics (UDP is inherently lossy) - output = receiver.get_output() - messages = parse_messages(output, APP_ID) - remote_count = sum(1 for m in messages if DEFAULT_MESSAGE in m.payload) + record = download_dlt(target, receiver.dlt_file) + messages = record.find(query=dict(apid=APP_ID)) + remote_count = sum(1 for m in messages if DEFAULT_MESSAGE in str(m.payload)) LOGGER.info(f"Remote DLT message count: {remote_count} / {expected} expected") _verify_kfile_messages(target, expected) def test_mw_log_kfile_multiple_threads(target, datarouter_on_target, dlt_capture): - """Verify kFile logging with multiple threads. - - Runs dlt_generator with 4 threads and 100 iterations each, producing - 4 * 6 * 100 = 2400 messages total. Verifies the exact count from the - on-disk .dlt file (written directly by the datarouter from shared memory). - - Remote DLT output via UDP is logged for diagnostics but not asserted - exactly, because UDP multicast can truncate or drop messages under - concurrent load — this is inherent to the protocol, not a bug. - """ + """Verify kFile logging with multiple threads.""" threads = 4 expected = threads * ITERATIONS * MESSAGES_PER_ITERATION @@ -108,9 +92,9 @@ def test_mw_log_kfile_multiple_threads(target, datarouter_on_target, dlt_capture ) # Log remote DLT count for diagnostics (UDP is inherently lossy) - output = receiver.get_output() - messages = parse_messages(output, APP_ID) - remote_count = sum(1 for m in messages if DEFAULT_MESSAGE in m.payload) + record = download_dlt(target, receiver.dlt_file) + messages = record.find(query=dict(apid=APP_ID)) + remote_count = sum(1 for m in messages if DEFAULT_MESSAGE in str(m.payload)) LOGGER.info(f"Remote DLT message count: {remote_count} / {expected} expected") _verify_kfile_messages(target, expected) diff --git a/score/test/integration/dlt_parser.py b/score/test/integration/dlt_parser.py deleted file mode 100644 index d6c607fb..00000000 --- a/score/test/integration/dlt_parser.py +++ /dev/null @@ -1,99 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2025 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* - -"""Structured parser for ``dlt-receive -a`` text output. - -DLT text lines produced by ``dlt-receive -a`` have the form:: - - - -Field positions can vary (some fields may be absent in non-extended -headers), but the *apid* and *ctid* fields always appear as a -whitespace-separated pair. DLT pads short IDs to 4 characters with -``-`` (e.g. ``TAP`` → ``TAP-``). - -This module provides helpers that work on the *text* output captured by -``dlt-receive -a --stdout-flush`` (which is what ``dlt_on_target`` -returns via ``receiver.get_output()``). -""" - -from collections import defaultdict -from dataclasses import dataclass, field - - -@dataclass -class DltMessage: - """A single parsed DLT message.""" - - apid: str - ctid: str - payload: str - raw_line: str - - -def parse_messages(dlt_output: str, app_id: str) -> list[DltMessage]: - """Parse DLT text output and return messages matching *app_id*. - - Args: - dlt_output: Full text output from ``dlt-receive -a``. - app_id: Application ID to filter on (without padding). - - Returns: - List of :class:`DltMessage` instances whose *apid* matches *app_id*. - """ - messages: list[DltMessage] = [] - for line in dlt_output.splitlines(): - parts = line.split() - for i, part in enumerate(parts): - if part.rstrip("-") == app_id and i + 1 < len(parts): - ctid = parts[i + 1].rstrip("-") - # Everything after apid and ctid is the payload - payload = " ".join(parts[i + 2 :]) if i + 2 < len(parts) else "" - messages.append( - DltMessage( - apid=app_id, - ctid=ctid, - payload=payload, - raw_line=line, - ) - ) - break - return messages - - -def count_messages_by_context( - dlt_output: str, - app_id: str, - context_ids: set[str] | None = None, -) -> tuple[dict[str, int], int]: - """Count messages per context ID for a given application. - - Args: - dlt_output: Full text output from ``dlt-receive -a``. - app_id: Application ID to filter on. - context_ids: Optional set of context IDs to include in the - per-context breakdown. Messages with other context IDs are - still included in the total count. - - Returns: - A ``(counts, total)`` tuple where *counts* maps context ID to - message count and *total* is the overall number of messages from - *app_id*. - """ - counts: dict[str, int] = defaultdict(int) - total = 0 - for msg in parse_messages(dlt_output, app_id): - total += 1 - if context_ids is None or msg.ctid in context_ids: - counts[msg.ctid] += 1 - return dict(counts), total From 750be304a165c639cc10d6c50ccdc027f210c7fe Mon Sep 17 00:00:00 2001 From: rahulsasingh Date: Thu, 21 May 2026 06:54:06 +0200 Subject: [PATCH 11/11] coverage: exclude component/integration tests from coverage run Component tests require a Docker daemon to execute and cannot produce LCOV coverage data in CI. Exclude them via tag filter instead. The py_logging_itf_test macro tags all tests with 'integration'. --- .bazelrc | 1 + .github/workflows/coverage_report.yml | 2 +- .../filetransfer/filetransfer_app.cpp | 25 +++++++++---------- score/test/component/filters/filtertest.cpp | 7 ++---- score/test/component/filters/filtertest.h | 7 ++---- score/test/component/filters/mwfiltertest.cpp | 25 +++++++++---------- score/test/component/mw_log/logging_app.cpp | 25 +++++++++---------- .../component/mw_log_kfile/dlt_generator.cpp | 25 +++++++++---------- 8 files changed, 54 insertions(+), 63 deletions(-) diff --git a/.bazelrc b/.bazelrc index 24afacc2..394bb5d6 100644 --- a/.bazelrc +++ b/.bazelrc @@ -42,6 +42,7 @@ common --//score/datarouter/build_configuration_flags:use_local_vlan=True # ignored-attributes warnings (string_comparison_adaptor.h, text_format.h, etc.) build --copt=-Wno-deprecated-declarations build --copt=-Wno-ignored-attributes +build --per_file_copt=external/score_itf++_repo_rules+dlt_daemon/src/shared/dlt_shm\.c@-Wno-missing-prototypes # Base QNX config (shared flags) common:qnx --credential_helper=*.qnx.com=%workspace%/scripts/internal/qnx_creds.py diff --git a/.github/workflows/coverage_report.yml b/.github/workflows/coverage_report.yml index 2b0f3435..14670750 100644 --- a/.github/workflows/coverage_report.yml +++ b/.github/workflows/coverage_report.yml @@ -27,4 +27,4 @@ jobs: uses: eclipse-score/cicd-workflows/.github/workflows/cpp-coverage.yml@main with: bazel-target: "//..." - extra-bazel-flags: "--lockfile_mode=error" + extra-bazel-flags: "--lockfile_mode=error --test_tag_filters=-integration" diff --git a/score/test/component/filetransfer/filetransfer_app.cpp b/score/test/component/filetransfer/filetransfer_app.cpp index ba497cf0..eaad1b1c 100644 --- a/score/test/component/filetransfer/filetransfer_app.cpp +++ b/score/test/component/filetransfer/filetransfer_app.cpp @@ -1,16 +1,15 @@ -// ******************************************************************************* -// Copyright (c) 2025 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// ******************************************************************************* - +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ #include "score/datarouter/dlt_filetransfer_trigger_lib/include/file_transfer.h" #include "score/mw/log/logger.h" #include "score/mw/log/logging.h" diff --git a/score/test/component/filters/filtertest.cpp b/score/test/component/filters/filtertest.cpp index 475bb054..98c81a1d 100644 --- a/score/test/component/filters/filtertest.cpp +++ b/score/test/component/filters/filtertest.cpp @@ -1,5 +1,4 @@ -/******************************************************************************* - * +/******************************************************************************** * Copyright (c) 2025 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -10,9 +9,7 @@ * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 - ******************************************************************************* - */ - + ********************************************************************************/ #include "filtertest.h" #include diff --git a/score/test/component/filters/filtertest.h b/score/test/component/filters/filtertest.h index e18e0153..e860cb9a 100644 --- a/score/test/component/filters/filtertest.h +++ b/score/test/component/filters/filtertest.h @@ -1,5 +1,4 @@ -/******************************************************************************* - * +/******************************************************************************** * Copyright (c) 2025 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -10,9 +9,7 @@ * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 - ******************************************************************************* - */ - + ********************************************************************************/ #ifndef FILTERTEST_H #define FILTERTEST_H diff --git a/score/test/component/filters/mwfiltertest.cpp b/score/test/component/filters/mwfiltertest.cpp index fda166f2..9ce8256a 100644 --- a/score/test/component/filters/mwfiltertest.cpp +++ b/score/test/component/filters/mwfiltertest.cpp @@ -1,16 +1,15 @@ -// ******************************************************************************* -// Copyright (c) 2025 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// ******************************************************************************* - +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ #include "score/mw/log/logging.h" #include diff --git a/score/test/component/mw_log/logging_app.cpp b/score/test/component/mw_log/logging_app.cpp index e37e8b50..b036a17f 100644 --- a/score/test/component/mw_log/logging_app.cpp +++ b/score/test/component/mw_log/logging_app.cpp @@ -1,16 +1,15 @@ -// ******************************************************************************* -// Copyright (c) 2025 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// ******************************************************************************* - +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ #include "score/mw/log/logging.h" #include diff --git a/score/test/component/mw_log_kfile/dlt_generator.cpp b/score/test/component/mw_log_kfile/dlt_generator.cpp index c159c7fe..3e93aa88 100644 --- a/score/test/component/mw_log_kfile/dlt_generator.cpp +++ b/score/test/component/mw_log_kfile/dlt_generator.cpp @@ -1,16 +1,15 @@ -// ******************************************************************************* -// Copyright (c) 2025 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// ******************************************************************************* - +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ #include "score/mw/log/logger.h" #include "score/mw/log/logging.h"