diff --git a/docs/components/mw_log/detailed_design/_assets/mw_log_recorders.puml b/docs/components/mw_log/detailed_design/_assets/mw_log_recorders.puml new file mode 100644 index 00000000..79c9147e --- /dev/null +++ b/docs/components/mw_log/detailed_design/_assets/mw_log_recorders.puml @@ -0,0 +1,188 @@ +' ******************************************************************************* +' Copyright (c) 2026 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 +' ******************************************************************************* + +@startuml mw_log_recorders + +' NOTE: this is a manual copy of the source of truth at +' score/mw/log/design/backend/mw_log_recorders.puml. Keep both in sync. + +' Interface +interface "mw::log::Recorder" as Recorder { + + StartRecord(ctx:std::string_view, log_level:LogLevel) : score::cpp::optional + + StopRecord(slot:SlotHandle&): void + + Log(const SlotHandle&, const T data) - family of functions + + IsLogEnabled(const LogLevel&, const std::string_view): bool +} + +' Interface +interface "mw::log::detail::Backend" as Backend { + + ReserveSlot() : score::cpp::optional + + FlushSlot(slot : const SlotHandle&) + + GetLogRecord(slot : const SlotHandle&): LogRecord& +} + +' Recorder implementations +class "mw::log::detail::FileRecorder" as FileRecorder { + - backend_ : std::unique_ptr + - config_ : Configuration + __ + + FileRecorder(const detail::Configuration&,\n std::unique_ptr) + + StartRecord(ctx:std::string_view, const LogLevel): score::cpp::optional + + StopRecord(const SlotHandle&): void + + IsLogEnabled(const LogLevel&, const std::string_view): bool + + Log(const SlotHandle&, T data) - family of functions +} + +class "mw::log::detail::TextRecorder" as TextRecorder { + - backend_ : std::unique_ptr + - config_ : Configuration + - check_log_level_for_console_: bool + __ + + TextRecorder(const detail::Configuration&,\n std::unique_ptr,\n const bool) + + StartRecord(ctx:std::string_view, const LogLevel): score::cpp::optional + + StopRecord(const SlotHandle&): void + + IsLogEnabled(const LogLevel&, const std::string_view): bool + + Log(const SlotHandle&, T data) - family of functions +} + +class "mw::log::detail::DataRouterRecorder" as DataRouterRecorder { +} + +class "mw::log::detail::CompositeRecorder" as CompositeRecorder { + - recorders_ : std::vector> + __ + + CompositeRecorder(std::vector> recorders) + + StartRecord(const std::string_view, const LogLevel): score::cpp::optional + + StopRecord(slot:SlotHandle&): void + + GetRecorders(): std::vector>& + + IsLogEnabled(const LogLevel&, const std::string_view): bool + + Log(const SlotHandle&, const T) - family of functions +} + +class "mw::log::detail::EmptyRecorder" as EmptyRecorder { + + StartRecord(const std::string_view, const LogLevel):\n score::cpp::optional + + StopRecord(const SlotHandle&): void + + IsLogEnabled(const LogLevel&, const std::string_view): bool + + Log(const SlotHandle&, T data) - family of functions +} + +class "mw::log::detail::RecorderMock" as RecorderMock #pink { +} + +' Backend implementations +class "mw::log::detail::FileOutputBackend" as FileOutputBackend { +} + +class "mw::log::detail::SlogBackend" as SlogBackend { + - app_id_: std::string + - buffer_: CircularAllocator + - slog_buffer_: slog2_buffer_t + - slog_buffer_config_: slog2_buffer_set_config_t + - slog2_instance_: std::unique_ptr + __ + + SlogBackend(const std::size_t,\n const LogRecord&,\n const std::string_view,\n std::unique_ptr) + + ReserveSlot(): score::cpp::optional + + FlushSlot(const SlotHandle&): void + + GetLogRecord(const SlotHandle&): LogRecord& + __ + - Init(verbosity: std::uint8_t) : void +} + +class "mw::log::detail::DataRouterBackend" as DataRouterBackend { +} + +class "mw::log::detail::BackendMock" as BackendMock #pink { +} + +' Helper classes +class "DltArgumentCounter" as DltArgumentCounter { + - counter_ : std::uint8_t& + __ + DltArgumentCounter(std::uint8_t&) + __ + + TryAddArgument(add_argument_callback) : AddArgumentResult +} + +class "mw::log::detail::TextFormat" as TextFormat { + {static} + PutFormattedTime(VerbosePayload&) : void + {static} + TerminateLog(VerbosePayload&) : void + {static} + Log(VerbosePayload&, const T, const IntegerRepresentation) : void\n - family of functions + {static} + Log(VerbosePayload&, const T) : void\n - family of functions +} + +class "mw::log::detail::DLTFormat" as DLTFormat { + + Log(VerbosePayload&, const bool): AddArgumentResult + + Log(VerbosePayload&, T, const IntegerRepresentation):\n AddArgumentResult - family of functions +} + +class "mw::log::detail::CircularAllocator" as CircularAllocator { +} + +class "mw::log::detail::LogRecord" as LogRecord { +} + +' External dependencies +class "OSAL::fcntl" as fcntl { +} + +class "OSAL::Unistd" as Unistd { +} + +' Relationships - Recorder interface +FileRecorder .up.|> Recorder +TextRecorder .up.|> Recorder +DataRouterRecorder .up.|> Recorder +CompositeRecorder .up.|> Recorder +EmptyRecorder .up.|> Recorder +RecorderMock .up.|> Recorder + +' Relationships - Backend interface +FileOutputBackend .up.|> Backend +SlogBackend .up.|> Backend +DataRouterBackend .up.|> Backend +BackendMock .up.|> Backend + +' Composition relationships +FileRecorder *-- Backend +FileRecorder *-- DltArgumentCounter +TextRecorder *-- Backend +TextRecorder *-- DltArgumentCounter +DataRouterRecorder *-- Backend + +' Dependencies +FileRecorder ..> TextFormat : Log +FileRecorder ..> DLTFormat : uses +TextRecorder ..> TextFormat : Log +DataRouterRecorder ..> DLTFormat : uses +TextRecorder ..> DLTFormat : uses + +' Backend composition +SlogBackend *-- CircularAllocator +SlogBackend --> LogRecord : uses + +' External dependencies +FileRecorder ..> fcntl : open\nSetNonBlocking / fctrl call +FileRecorder ..> Unistd : close + +' Notes +note bottom of Recorder + Refer Recorder.h for all the Log(const SlotHandle&, const T data) + - family of functions +end note + +note top of TextFormat + Refer text_format.h for all the Log(...) + - family of functions +end note + +@enduml diff --git a/docs/components/mw_log/detailed_design/index.rst b/docs/components/mw_log/detailed_design/index.rst index fad767bd..eb176e4a 100644 --- a/docs/components/mw_log/detailed_design/index.rst +++ b/docs/components/mw_log/detailed_design/index.rst @@ -18,7 +18,7 @@ Detailed Design The backend composition and recorder relationships are shown below: -.. uml:: ../../../../score/mw/log/design/backend/mw_log_recorders.puml +.. uml:: _assets/mw_log_recorders.puml .. toctree:: :maxdepth: 1 diff --git a/docs/verification_report/stats.rst b/docs/verification_report/stats.rst index 08b80d41..8e00eb10 100644 --- a/docs/verification_report/stats.rst +++ b/docs/verification_report/stats.rst @@ -20,13 +20,19 @@ Quality Stats Overview -------- +*Scoped to requirements owned by this repository (this repo's own* +``comp_req`` *needs). Requirements pulled in from external repositories +(score_baselibs, score_platform, score_process) that this project links +against for traceability purposes are excluded, since they are not owned +or maintained here.* + .. needpie:: Requirements Status :labels: not valid, valid but not tested, valid and tested :colors: red,yellow, green - type == 'comp_req' and status == 'invalid' - type == 'comp_req' and testlink == '' and (status == 'valid' or status == 'invalid') - type == 'comp_req' and testlink != '' and (status == 'valid' or status == 'invalid') + type == 'comp_req' and is_external == False and status == 'invalid' + type == 'comp_req' and is_external == False and testlink == '' and (status == 'valid' or status == 'invalid') + type == 'comp_req' and is_external == False and testlink != '' and (status == 'valid' or status == 'invalid') In Detail --------- @@ -40,8 +46,8 @@ In Detail :labels: not valid, valid :colors: red, orange, green - type == 'comp_req' and status == 'invalid' - type == 'comp_req' and status == 'valid' + type == 'comp_req' and is_external == False and status == 'invalid' + type == 'comp_req' and is_external == False and status == 'valid' .. grid-item-card:: @@ -49,8 +55,8 @@ In Detail :labels: no codelink, with codelink :colors: red, green - type == 'comp_req' and source_code_link == '' - type == 'comp_req' and source_code_link != '' + type == 'comp_req' and is_external == False and source_code_link == '' + type == 'comp_req' and is_external == False and source_code_link != '' .. grid-item-card:: diff --git a/score/datarouter/test/ut/ut_logging/test_dltchannel.cpp b/score/datarouter/test/ut/ut_logging/test_dltchannel.cpp index 239b583c..6d03bec3 100644 --- a/score/datarouter/test/ut/ut_logging/test_dltchannel.cpp +++ b/score/datarouter/test/ut/ut_logging/test_dltchannel.cpp @@ -92,6 +92,11 @@ class DltChannelTest : public ::testing::Test TEST_F(DltChannelTest, WhenCreatedDefault) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_multiple_channels"); + RecordProperty("Description", "Check that a DLT log channel can be constructed with default parameters."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + testing::StrictMock outputs; UdpStreamOutput::Tester::Instance() = &outputs; EXPECT_CALL(outputs, construct(_, nullptr, 3490U, Eq(std::string("")))).Times(1); @@ -133,6 +138,11 @@ TEST_F(DltChannelTest, WhenSendingNonverboseTwice) TEST_F(DltChannelTest, WhenSendingVerboseTwice) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_verbose_messages"); + RecordProperty("Description", "Check that two verbose DLT messages sent in a row are correctly buffered and flushed."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + testing::StrictMock outputs; UdpStreamOutput::Tester::Instance() = &outputs; mmsghdr mmsghdr_data; @@ -445,6 +455,11 @@ TEST_F(DltChannelTest, WhenSendingFTVerboseHitsSleepCondition) TEST_F(DltChannelTest, WhenLogLevelExceedsThreshold_Verbose) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_message_filtering"); + RecordProperty("Description", "Check that a verbose message whose log level exceeds the channel threshold is filtered out."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + testing::StrictMock outputs; UdpStreamOutput::Tester::Instance() = &outputs; @@ -466,6 +481,11 @@ TEST_F(DltChannelTest, WhenLogLevelExceedsThreshold_Verbose) TEST_F(DltChannelTest, WhenNonVerboseLogLevelExceedsThreshold) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_message_filtering"); + RecordProperty("Description", "Check that a non-verbose message whose log level exceeds the channel threshold is filtered out."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + testing::StrictMock outputs; UdpStreamOutput::Tester::Instance() = &outputs; diff --git a/score/datarouter/test/ut/ut_logging/test_dltserver.cpp b/score/datarouter/test/ut/ut_logging/test_dltserver.cpp index 5866614f..d7d495b5 100644 --- a/score/datarouter/test/ut/ut_logging/test_dltserver.cpp +++ b/score/datarouter/test/ut/ut_logging/test_dltserver.cpp @@ -149,6 +149,11 @@ class DltServerCreatedWithoutConfigFixture : public ::testing::Test TEST_F(DltServerCreatedWithoutConfigFixture, WhenCreatedDefault) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_server"); + RecordProperty("Description", "Check that the DLT server component can be constructed with a default config."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + DltLogServer dlt_server(s_config, read_callback.AsStdFunction(), write_callback.AsStdFunction(), true); } @@ -234,6 +239,11 @@ TEST_F(DltServerCreatedWithConfigFixture, FlushChannelsExpectNoThrowException) TEST_F(DltServerCreatedWithConfigFixture, GetQuotaCorrectAppNameExpectCorrectValue) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_bw_quota_config"); + RecordProperty("Description", "Check that the DLT bandwidth quota configured for an application is returned correctly."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + EXPECT_CALL(read_callback, Call()).Times(1).WillOnce(Return(p_config)); EXPECT_CALL(write_callback, Call(_)).Times(0); diff --git a/score/datarouter/test/ut/ut_logging/test_verbose_dlt.cpp b/score/datarouter/test/ut/ut_logging/test_verbose_dlt.cpp index 4ea05b63..9a45d730 100644 --- a/score/datarouter/test/ut/ut_logging/test_verbose_dlt.cpp +++ b/score/datarouter/test/ut/ut_logging/test_verbose_dlt.cpp @@ -32,6 +32,11 @@ class MockDltVerboseHandlerOutput : public DltVerboseHandler::IOutput TEST(DltVerboseHandlerTest, sendVerboseTest) { + RecordProperty("PartiallyVerifies", "comp_req__data_router__dlt_verbose_messages"); + RecordProperty("Description", "Check that a handled message is forwarded to the output as a verbose DLT message."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + MockDltVerboseHandlerOutput mock_dlt_output; ON_CALL(mock_dlt_output, IsOutputEnabled()).WillByDefault(Return(true)); DltVerboseHandler handler(mock_dlt_output); diff --git a/score/mw/log/backend/slog_registrant_test.cpp b/score/mw/log/backend/slog_registrant_test.cpp index 01f3268d..72514728 100644 --- a/score/mw/log/backend/slog_registrant_test.cpp +++ b/score/mw/log/backend/slog_registrant_test.cpp @@ -27,10 +27,11 @@ namespace TEST(SlogRegistrantTest, SlogBackendIsRegisteredAfterStaticInitialization) { + RecordProperty("PartiallyVerifies", "comp_req__log__system_backend_activation"); RecordProperty("Description", - "The slog backend registrant shall register a creator for LogMode::kSystem during static init."); - RecordProperty("TestType", "Verification of the control flow and data flow"); - RecordProperty("DerivationTechnique", "Analysis of functional dependencies"); + "The slog backend registrant is registered for LogMode::kSystem during static init."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); EXPECT_TRUE(IsBackendAvailable(LogMode::kSystem)); } diff --git a/score/mw/log/detail/data_router/data_router_backend_test.cpp b/score/mw/log/detail/data_router/data_router_backend_test.cpp index d9365bdc..6b18b89d 100644 --- a/score/mw/log/detail/data_router/data_router_backend_test.cpp +++ b/score/mw/log/detail/data_router/data_router_backend_test.cpp @@ -331,11 +331,14 @@ INSTANTIATE_TEST_SUITE_P(LogLevelSetCorrectly, TEST_F(DataRouterBackendFixture, LogLevelVerbose) { + RecordProperty("PartiallyVerifies", "comp_req__log__dlt_verbose_mode"); + RecordProperty("Description", "Check that a message logged at verbose level is sent in DLT verbose mode."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("ParentRequirement", "SCR-1633144"); RecordProperty("ASIL", "B"); RecordProperty("Description", "Verify the ability of logging verbose message."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); SimulateLogging(LogLevel::kVerbose); } diff --git a/score/mw/log/detail/data_router/remote_dlt_recorder_factory_test.cpp b/score/mw/log/detail/data_router/remote_dlt_recorder_factory_test.cpp index 1d1aee85..20b29dcd 100644 --- a/score/mw/log/detail/data_router/remote_dlt_recorder_factory_test.cpp +++ b/score/mw/log/detail/data_router/remote_dlt_recorder_factory_test.cpp @@ -77,11 +77,14 @@ class RecorderFactoryConfigFixture : public ::testing::Test TEST_F(RecorderFactoryConfigFixture, RemoteConfiguredShallReturnDataRouterRecorder) { + RecordProperty("PartiallyVerifies", "comp_req__log__local_allocation_strategy"); + RecordProperty("Description", "Check that the recorder factory creates a DataRouterRecorder using the provided memory resource when remote mode is configured."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("Requirement", "SCR-861534"); RecordProperty("ASIL", "B"); RecordProperty("Description", "RecorderFactory can create DataRouterRecorder if remote is configured."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); const Configuration config{}; auto recorder = diff --git a/score/mw/log/detail/data_router/shared_memory/common_test.cpp b/score/mw/log/detail/data_router/shared_memory/common_test.cpp index 1ce74107..e552faf0 100644 --- a/score/mw/log/detail/data_router/shared_memory/common_test.cpp +++ b/score/mw/log/detail/data_router/shared_memory/common_test.cpp @@ -36,11 +36,14 @@ TEST(CommonTests, TypesShallBeTriviallyCopyable) TEST(CommonTests, TypesShallBeLockFree) { + RecordProperty("PartiallyVerifies", "comp_req__log__avoid_locks"); + RecordProperty("Description", "Check that the atomic fields of the shared-memory data structure are lock-free."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("ParentRequirement", "SCR-861578"); RecordProperty("ASIL", "B"); RecordProperty("Description", "Checks data lock-free."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); score::mw::log::detail::SharedData data{}; ASSERT_TRUE(data.number_of_drops_buffer_full.is_lock_free()); diff --git a/score/mw/log/detail/data_router/shared_memory/shared_memory_reader_test.cpp b/score/mw/log/detail/data_router/shared_memory/shared_memory_reader_test.cpp index d251ab4c..dfe40e4d 100644 --- a/score/mw/log/detail/data_router/shared_memory/shared_memory_reader_test.cpp +++ b/score/mw/log/detail/data_router/shared_memory/shared_memory_reader_test.cpp @@ -85,11 +85,14 @@ class TypeInfoTest TEST_F(SharedMemoryReaderFixture, GetterShallReadSharedDataNumberOfDropsInvalidSize) { + RecordProperty("PartiallyVerifies", "comp_req__log__memory_bound_checking"); + RecordProperty("Description", "Check that the reader correctly reports the count of entries dropped due to invalid size, an explicit memory-boundary check."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("ParentRequirement", "SCR-861827, SCR-12206795"); RecordProperty("ASIL", "B"); RecordProperty("Description", "Verifies the ability of getting the number of drops invalid size value properly."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); static constexpr Length kNumberOfDrops{13UL}; shared_data.number_of_drops_invalid_size.store(kNumberOfDrops); diff --git a/score/mw/log/detail/data_router/shared_memory/writer_factory_test.cpp b/score/mw/log/detail/data_router/shared_memory/writer_factory_test.cpp index adf64b2b..c585a768 100644 --- a/score/mw/log/detail/data_router/shared_memory/writer_factory_test.cpp +++ b/score/mw/log/detail/data_router/shared_memory/writer_factory_test.cpp @@ -209,13 +209,18 @@ TEST(WriterFactory, MissingStdlibShallResultInEmptyOptional) TEST_F(WriterFactoryFixture, WhenTheFileExistsItShallBeUnlinked) { + RecordProperty("PartiallyVerifies", "comp_req__log__shm_file_permissions"); + RecordProperty("PartiallyVerifies", "comp_req__log__file_descriptor_flags"); + RecordProperty("Description", + "Check that an existing shared-memory file is unlinked before being re-created read-only."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("ParentRequirement", "SCR-1016729, SCR-26319707"); RecordProperty("ASIL", "B"); RecordProperty("Description", "Verifies the ability of unlink the exist file. The component shall set the FD_CLOEXEC (or " "O_CLOEXEC) flag on all the file descriptor it owns"); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); RecordProperty("Priority", "3"); WriterFactory writer(std::move(osal)); diff --git a/score/mw/log/detail/file_recorder/dlt_message_builder_test.cpp b/score/mw/log/detail/file_recorder/dlt_message_builder_test.cpp index 584b11f4..950ae2e6 100644 --- a/score/mw/log/detail/file_recorder/dlt_message_builder_test.cpp +++ b/score/mw/log/detail/file_recorder/dlt_message_builder_test.cpp @@ -64,12 +64,15 @@ class DltMessageBuilderFixture : public ::testing::Test TEST_F(DltMessageBuilderFixture, ShallDepleteAfterHeaderAndPayload) { + RecordProperty("PartiallyVerifies", "comp_req__log__autosar_log_trace_spec"); + RecordProperty("Description", "Check that the DLT message builder depletes after the header and payload spans are consumed."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("ParentRequirement", "SCR-1633236"); RecordProperty("AutosarRequirement", "PRS_Dlt_00405"); RecordProperty("ASIL", "B"); RecordProperty("Description", "Verifies Dlt will deplete after header and payload."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); unit_.SetNextMessage(log_record_); const auto first = unit_.GetNextSpan(); diff --git a/score/mw/log/detail/file_recorder/file_recorder_factory_test.cpp b/score/mw/log/detail/file_recorder/file_recorder_factory_test.cpp index 3056598f..d6daad47 100644 --- a/score/mw/log/detail/file_recorder/file_recorder_factory_test.cpp +++ b/score/mw/log/detail/file_recorder/file_recorder_factory_test.cpp @@ -54,13 +54,17 @@ class FileRecorderFactoryConfigFixture : public ::testing::Test TEST_F(FileRecorderFactoryConfigFixture, FileConfigurionShallCallFileCreationAndReturnFileRecorder) { + RecordProperty("PartiallyVerifies", "comp_req__log__file_descriptor_flags"); + RecordProperty("Description", + "Check that the file recorder factory opens the configured log file with the close-on-exec flag set."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("Requirement", "SCR-861534, SCR-26319707"); RecordProperty("ASIL", "B"); RecordProperty("Description", "RecorderFactory can create FileRecorder and fileCreation will be called if file is configured. The " "component shall set the FD_CLOEXEC (or O_CLOEXEC) flag on all the file descriptor it owns"); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); auto fcntl_mock = score::cpp::pmr::make_unique(memory_resource_); auto* fcntl_mock_raw_ptr = fcntl_mock.get(); diff --git a/score/mw/log/detail/file_recorder/file_recorder_test.cpp b/score/mw/log/detail/file_recorder/file_recorder_test.cpp index 9b3020e9..b3fc4434 100644 --- a/score/mw/log/detail/file_recorder/file_recorder_test.cpp +++ b/score/mw/log/detail/file_recorder/file_recorder_test.cpp @@ -154,11 +154,14 @@ class FileRecorderFixture : public ::testing::Test TEST_F(FileRecorderFixture, TooManyArgumentsWillYieldTruncatedLog) { + RecordProperty("PartiallyVerifies", "comp_req__log__local_allocation_strategy"); + RecordProperty("Description", "Check that logging more arguments than fit in the local buffer truncates the log instead of allocating from the heap."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); RecordProperty("Requirement", "SCR-861534, SCR-1016719"); RecordProperty("ASIL", "B"); RecordProperty("Description", "The log will be truncated in case of too many arguments."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); constexpr std::size_t kTypeInfoByteSizeAccordingToSpecification = 4; const std::size_t number_of_arguments = log_record_.GetLogEntry().payload.capacity() / diff --git a/score/mw/log/detail/slog/slog_backend_test.cpp b/score/mw/log/detail/slog/slog_backend_test.cpp index 9ca1558a..833567a2 100644 --- a/score/mw/log/detail/slog/slog_backend_test.cpp +++ b/score/mw/log/detail/slog/slog_backend_test.cpp @@ -78,10 +78,13 @@ struct SlogBackendFixture : ::testing::Test TEST_F(SlogBackendFixture, SlogRegister) { + RecordProperty("PartiallyVerifies", "comp_req__log__forward_to_system_logger"); + RecordProperty("Description", "Check that the system logger backend registers with slogger2 and forwards logs to it."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("ParentRequirement", "SCR-8017664"); RecordProperty("Description", "Verifies normal slog registering."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); EXPECT_CALL(*slog2_mock_raw_ptr_, slog2_register(_, _, _)); diff --git a/score/mw/log/detail/wait_free_producer_queue/linear_reader_test.cpp b/score/mw/log/detail/wait_free_producer_queue/linear_reader_test.cpp index 49196615..e1abedac 100644 --- a/score/mw/log/detail/wait_free_producer_queue/linear_reader_test.cpp +++ b/score/mw/log/detail/wait_free_producer_queue/linear_reader_test.cpp @@ -25,13 +25,14 @@ namespace TEST(LinearReaderTests, LengthExceedingMaxThresholdShouldReturnEmpty) { - RecordProperty("Requirement", "SCR-1016719"); - RecordProperty("ASIL", "B"); + RecordProperty("PartiallyVerifies", "comp_req__log__index_size_checking"); RecordProperty( "Description", - "The reader shall check if the length is valid and drop values that would lead to out of bounds access."); - RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); + "Check that the reader rejects a length exceeding the maximum threshold instead of accessing out of bounds."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Requirement", "SCR-1016719"); + RecordProperty("ASIL", "B"); constexpr auto kBufferSize = score::mw::log::detail::GetLengthOffsetBytes() * 2U; std::vector buffer(kBufferSize); diff --git a/score/mw/log/detail/wait_free_producer_queue/wait_free_alternating_writer_test.cpp b/score/mw/log/detail/wait_free_producer_queue/wait_free_alternating_writer_test.cpp index f944b263..acaa57a5 100644 --- a/score/mw/log/detail/wait_free_producer_queue/wait_free_alternating_writer_test.cpp +++ b/score/mw/log/detail/wait_free_producer_queue/wait_free_alternating_writer_test.cpp @@ -30,11 +30,14 @@ namespace TEST(WaitFreeAlternatingWriterTests, EnsureAtomicRequirements) { + RecordProperty("PartiallyVerifies", "comp_req__log__cross_locking"); + RecordProperty("Description", "Check that the atomic types used by the wait-free alternating writer are lock-free."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("Requirement", "SCR-861578,SCR-1016724,SCR-861550"); RecordProperty("ASIL", "B"); RecordProperty("Description", "The used atomic data types shall be lock free"); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); score::mw::log::detail::AlternatingControlBlock control_block{}; ASSERT_TRUE(control_block.switch_count_points_active_for_writing.is_lock_free()); diff --git a/score/mw/log/detail/wait_free_producer_queue/wait_free_linear_writer_test.cpp b/score/mw/log/detail/wait_free_producer_queue/wait_free_linear_writer_test.cpp index e56a7a13..884b7fc7 100644 --- a/score/mw/log/detail/wait_free_producer_queue/wait_free_linear_writer_test.cpp +++ b/score/mw/log/detail/wait_free_producer_queue/wait_free_linear_writer_test.cpp @@ -26,11 +26,14 @@ namespace TEST(WaitFreeLinearWriter, EnsureAtomicRequirements) { + RecordProperty("PartiallyVerifies", "comp_req__log__avoid_locks, comp_req__log__cross_locking"); + RecordProperty("Description", "Check that the atomic types used by the wait-free linear writer are lock-free."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); RecordProperty("Requirement", "SCR-861578, SCR-1016724"); RecordProperty("ASIL", "B"); RecordProperty("Description", "The used atomic data types shall be lock free"); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); score::mw::log::detail::LinearControlBlock control_block{}; ASSERT_TRUE(control_block.acquired_index.is_lock_free()); @@ -40,11 +43,14 @@ TEST(WaitFreeLinearWriter, EnsureAtomicRequirements) TEST(WaitFreeLinearWriter, WriteBufferFullShouldReturnExpectedData) { + RecordProperty("PartiallyVerifies", "comp_req__log__no_endless_loops"); + RecordProperty("Description", "Check that reading from a full write buffer terminates and returns the expected data instead of looping unbounded."); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); RecordProperty("Requirement", "SCR-861578, SCR-1016724, SCR-1016719, SCR-861550"); RecordProperty("ASIL", "B"); RecordProperty("Description", "Returning the expected data if the write buffer is full."); RecordProperty("TestingTechnique", "Requirements-based test"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); constexpr auto kBufferSize = 10U * 64U * 1024U; std::vector buffer(kBufferSize); diff --git a/score/test/component/datarouter/test_datarouter_filters.py b/score/test/component/datarouter/test_datarouter_filters.py index 1f21116e..3923adf2 100644 --- a/score/test/component/datarouter/test_datarouter_filters.py +++ b/score/test/component/datarouter/test_datarouter_filters.py @@ -31,6 +31,7 @@ import ctypes import logging +from attribute_plugin import add_test_properties from logging_plugin import download_dlt LOGGER = logging.getLogger(__name__) @@ -38,9 +39,17 @@ TOTAL_NONVERBOSE_MESSAGES = 11 +@add_test_properties( + fully_verifies=["comp_req__data_router__dlt_message_filtering"], + test_type="requirements-based", + derivation_technique="equivalence-classes", +) def test_datarouter_filters(target, datarouter_on_target, dlt_capture): """Verify per-context non-verbose log-level filtering via TRACE(). + Check that non-verbose (TRACE) messages are filtered per-context by the + configured log-level threshold. + Expected message counts per context group (type_id // 100): - group 1 (AAAA, kVerbose): 6 messages - group 2 (BBBB, kInfo): 4 messages diff --git a/score/test/component/defs.bzl b/score/test/component/defs.bzl index 8225006a..665f891a 100644 --- a/score/test/component/defs.bzl +++ b/score/test/component/defs.bzl @@ -112,6 +112,7 @@ def py_logging_itf_test(name, srcs, filesystem, filesystem_pkg, extra_oci_tars = srcs = srcs, plugins = [ "@score_itf//score/itf/plugins:dlt_plugin", + "@score_itf//score/itf/plugins:attribute_plugin", "//score/test/component:logging_plugin", ] + select({ "@platforms//os:qnx": ["@score_itf//score/itf/plugins:qemu_plugin"], diff --git a/score/test/component/mw_log/test_mw_log.py b/score/test/component/mw_log/test_mw_log.py index 7719fa89..ee2498af 100644 --- a/score/test/component/mw_log/test_mw_log.py +++ b/score/test/component/mw_log/test_mw_log.py @@ -24,6 +24,7 @@ import tempfile import dlt.dlt as python_dlt +from attribute_plugin import add_test_properties from logging_plugin import download_dlt @@ -72,8 +73,21 @@ ] +@add_test_properties( + fully_verifies=[ + "comp_req__log__send_to_datarouter", + "comp_req__log__autosar_log_trace_spec", + "comp_req__log__dlt_verbose_mode", + ], + test_type="requirements-based", + derivation_technique="requirements-analysis", +) def test_mw_log_remote_logging(target, datarouter_on_target, dlt_capture): - """Verify all data types are correctly logged and received via DLT.""" + """Verify all data types are correctly logged and received via DLT. + + Check that mw::log sends verbose messages of all supported data types to + datarouter and they are received via DLT. + """ with dlt_capture() as receiver: target.execute(LOGGING_APP_CMD) @@ -107,6 +121,14 @@ def test_mw_log_console_logging(target, datarouter_on_target): assert not missing, f"Missing expected values in console output: {missing}" +@add_test_properties( + fully_verifies=[ + "comp_req__log__autosar_log_trace_spec", + "comp_req__log__dlt_verbose_mode", + ], + test_type="requirements-based", + derivation_technique="requirements-analysis", +) def test_mw_log_file_logging(target, datarouter_on_target): """Verify all data types are correctly logged to a .dlt file on disk.""" target.execute(LOGGING_APP_CMD) diff --git a/score/test/component/mw_log/test_mw_log_filters.py b/score/test/component/mw_log/test_mw_log_filters.py index f7e39acf..0b0c62e3 100644 --- a/score/test/component/mw_log/test_mw_log_filters.py +++ b/score/test/component/mw_log/test_mw_log_filters.py @@ -24,6 +24,7 @@ import logging +from attribute_plugin import add_test_properties from logging_plugin import download_dlt LOGGER = logging.getLogger(__name__) @@ -33,9 +34,17 @@ CONTEXT_IDS = ["FAT", "ERR", "WRN", "INF", "DBG", "VBS"] +@add_test_properties( + fully_verifies=["comp_req__log__inactive_logstream"], + test_type="requirements-based", + derivation_technique="equivalence-classes", +) def test_mw_verbose_filters(target, datarouter_on_target, dlt_capture): """Verify per-context verbose log-level filtering with free-function API. + Check that LogStream objects below the configured per-context log level + threshold produce no output. + Expected message counts per context (based on configured log levels): - FAT (kFatal): 1 message (only Fatal passes) - ERR (kError): 2 messages (Fatal + Error pass)