From 16395165dbdf8afad46ce15c1f81483c646d6c41 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Thu, 1 Jun 2023 16:23:33 -0400 Subject: [PATCH] Add separate hookable tracing module (#26986) * Starting with some basic class declarations * Start defining macros for building things * implement a convenience method for scoping traces * Restyle * Prepare for some testing infrastructure for tracing * Make code compile * Implement some backend support * Restyle * We now have simple tracing unit tests * More unit tests that work * Add chip thread locking assertions * more documentation * Restyle * Make spellchecker happy * Restyle * Minor comment fix * Code review updates * add numbers to scopes * Add numeric values to instant tracing values * Fix uniqueness for scopes * Use std::vector and algorithm equals to make tidy happy --------- Co-authored-by: Andrei Litvin --- .github/.wordlist.txt | 1 + src/BUILD.gn | 1 + src/tracing/BUILD.gn | 42 +++++++ src/tracing/README.md | 44 ++++++++ src/tracing/backend.h | 69 ++++++++++++ src/tracing/log_declares.h | 32 ++++++ src/tracing/macros.h | 84 ++++++++++++++ src/tracing/registry.cpp | 114 +++++++++++++++++++ src/tracing/registry.h | 77 +++++++++++++ src/tracing/scope.h | 62 ++++++++++ src/tracing/scopes.h | 120 ++++++++++++++++++++ src/tracing/tests/BUILD.gn | 33 ++++++ src/tracing/tests/TestTracing.cpp | 181 ++++++++++++++++++++++++++++++ 13 files changed, 860 insertions(+) create mode 100644 src/tracing/BUILD.gn create mode 100644 src/tracing/README.md create mode 100644 src/tracing/backend.h create mode 100644 src/tracing/log_declares.h create mode 100644 src/tracing/macros.h create mode 100644 src/tracing/registry.cpp create mode 100644 src/tracing/registry.h create mode 100644 src/tracing/scope.h create mode 100644 src/tracing/scopes.h create mode 100644 src/tracing/tests/BUILD.gn create mode 100644 src/tracing/tests/TestTracing.cpp diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index 82e88caf568625..4823bb6d03c834 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -121,6 +121,7 @@ AXXXF AYNJV babaf backend +backends backticks backtrace BallastConfiguration diff --git a/src/BUILD.gn b/src/BUILD.gn index b58da12e39f349..26cf7c085938dd 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -94,6 +94,7 @@ if (chip_build_tests) { "${chip_root}/src/lib/support/tests", "${chip_root}/src/protocols/secure_channel/tests", "${chip_root}/src/system/tests", + "${chip_root}/src/tracing/tests", "${chip_root}/src/transport/tests", ] } diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn new file mode 100644 index 00000000000000..673f5adc260833 --- /dev/null +++ b/src/tracing/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +declare_args() { + matter_enable_tracing_support = true +} + +config("tracing_enabled") { + defines = [ "MATTER_TRACING_ENABLED" ] +} + +static_library("tracing") { + sources = [ + "backend.h", + "log_declares.h", + "macros.h", + "registry.cpp", + "registry.h", + "scope.h", + "scopes.h", + ] + + public_deps = [ "${chip_root}/src/lib/support" ] + + if (matter_enable_tracing_support) { + public_configs = [ ":tracing_enabled" ] + } +} diff --git a/src/tracing/README.md b/src/tracing/README.md new file mode 100644 index 00000000000000..6eb9323ad01150 --- /dev/null +++ b/src/tracing/README.md @@ -0,0 +1,44 @@ +# Matter tracing + +This library provides a runtime-configurable tracing and logging infrastructure +for matter. + +## Types of data + +### Tracing + +Tracing is mostly intended for following execution flow and measuring time spent +for various operations. They are: + +- _scoped_ where separate begin and end events are emitted _or_ + +- _instant_ where a single notable event is emitted, representing a point in + time of a notable event + +Tracing and instant values are set to know enumeration values at compile time, +to allow implementation of backends that require compile-time strings for their +tracing. + +### Data Logging + +Data logging provides the tracing module the opportunity to report input/output +data for matter data processing. + +The data logging is generally limited in count and covers: + +- _Messages_, specifically sent matter requests and received matter responses + +- _DNSSD_ operations as they are a core component of matter, specifically + attempts to discover nodes as well as when a node is discovered or fails + discovery. + +## Usage + +Backends are defined by extending `chip::Tracing::Backend` in `backend.h` and +registering it via functions in `registry.h` + +Actual usage is controlled using `macros.h` (and for convenience `scope.h` +provides scoped begin/end invocations). + +tracing macros can be completely made a `noop` by setting +``matter_enable_tracing_support=false` when compiling. diff --git a/src/tracing/backend.h b/src/tracing/backend.h new file mode 100644 index 00000000000000..bc6501dbf6b4be --- /dev/null +++ b/src/tracing/backend.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include + +namespace chip { +namespace Tracing { + +/// Represents a generic tracing back-end. +/// +/// Derived from an intrusive list base as multiple +/// tracing back-ends may exist per application. +class Backend : public ::chip::IntrusiveListNodeBase<> +{ +public: + virtual ~Backend() = default; + + /// Begin a trace for the specified scope. + /// + /// Scopes must be completed by a corresponding + /// TraceEnd call. + virtual void TraceBegin(Scope scope) = 0; + + /// Tracing end assumes completing a previously + /// started scope with TraceBegin and nesting is assumed. + /// + /// Expect scopes like: + /// TraceBegin(Foo) + /// TraceBegin(Bar) + /// TraceEnd(Bar) + /// TraceEnd(Foo) + /// + /// The following is NOT acceptable: + /// TraceBegin(Foo) + /// TraceBegin(Bar) + /// TraceEnd(Foo) + /// TraceEnd(Bar) + virtual void TraceEnd(Scope scope) = 0; + + /// Trace a zero-sized event + virtual void TraceInstant(Instant instant) = 0; + + virtual void LogMessageSend(MessageSendInfo &) { TraceInstant(Instant::Log_MessageSend); } + virtual void LogMessageReceived(MessageReceiveInfo &) { TraceInstant(Instant::Log_MessageReceived); } + + virtual void LogNodeLookup(NodeLookupInfo &) { TraceInstant(Instant::Log_NodeLookup); } + virtual void LogNodeDiscovered(NodeDiscoveredInfo &) { TraceInstant(Instant::Log_NodeDiscovered); } + virtual void LogNodeDiscoveryFailed(NodeDiscoveryFailedInfo &) { TraceInstant(Instant::Log_NodeDiscoveryFailed); } +}; + +} // namespace Tracing +} // namespace chip diff --git a/src/tracing/log_declares.h b/src/tracing/log_declares.h new file mode 100644 index 00000000000000..8cc4e11a7e2cb3 --- /dev/null +++ b/src/tracing/log_declares.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace chip { +namespace Tracing { + +// These structures are forward-declared so that tracing itself has no direct dependencies +// on actual types. This allows tracing to be used anywhere lib/support could be used. + +struct MessageSendInfo; +struct MessageReceiveInfo; +struct NodeLookupInfo; +struct NodeDiscoveredInfo; +struct NodeDiscoveryFailedInfo; + +} // namespace Tracing +} // namespace chip diff --git a/src/tracing/macros.h b/src/tracing/macros.h new file mode 100644 index 00000000000000..3b024e147bd2f4 --- /dev/null +++ b/src/tracing/macros.h @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#ifndef MATTER_TRACING_ENABLED + +#define _MATTER_TRACE_DISABLE \ + do \ + { \ + } while (false) + +#define MATTER_TRACE_BEGIN(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) +#define MATTER_TRACE_END(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) + +#define MATTER_TRACE_INSTANT(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) + +#define MATTER_LOG_MESSAGE_SEND(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) +#define MATTER_LOG_MESSAGE_RECEIVED(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) + +#define MATTER_LOG_NODE_LOOKUP(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) +#define MATTER_LOG_NODE_DISCOVERED(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) +#define MATTER_LOG_NODE_DISCOVERY_FAILED(...) _MATTER_TRACE_DISABLE(__VA_ARGS__) + +#else // MATTER_TRACING_ENABLED + +#include +#include +#include + +#define MATTER_TRACE_BEGIN(scope) ::chip::Tracing::Internal::Begin(scope) +#define MATTER_TRACE_END(scope) ::chip::Tracing::Internal::End(scope) +#define MATTER_TRACE_INSTANT(scope) ::chip::Tracing::Internal::Instant(scope) + +#define MATTER_LOG_MESSAGE_SEND(...) \ + do \ + { \ + ::chip::Tracing::MessageSendInfo _trace_data(__VA_ARGS__); \ + ::chip::Tracing::Internal::LogMessageSend(_trace_data); \ + } while (false) + +#define MATTER_LOG_MESSAGE_RECEIVED(...) \ + do \ + { \ + ::chip::Tracing::MessageReceivedInfo _trace_data(__VA_ARGS__); \ + ::chip::Tracing::Internal::LogMessageReceived(_trace_data); \ + } while (false) + +#define MATTER_LOG_NODE_LOOKUP(...) \ + do \ + { \ + ::chip::Tracing::NodeLookupInfo _trace_data(__VA_ARGS__); \ + ::chip::Tracing::Internal::LogNodeLookup(_trace_data); \ + } while (false) + +#define MATTER_LOG_NODE_DISCOVERED(...) \ + do \ + { \ + ::chip::Tracing::NodeDiscoveredInfo _trace_data(__VA_ARGS__); \ + ::chip::Tracing::Internal::LogNodeDiscovered(_trace_data); \ + } while (false) + +#define MATTER_LOG_NODE_DISCOVERY_FAILED(...) \ + do \ + { \ + ::chip::Tracing::NodeDiscoveryFailedInfo _trace_data(__VA_ARGS__); \ + ::chip::Tracing::Internal::LogNodeDiscoveryFailed(_trace_data); \ + } while (false) + +#endif diff --git a/src/tracing/registry.cpp b/src/tracing/registry.cpp new file mode 100644 index 00000000000000..f3497a27f2643f --- /dev/null +++ b/src/tracing/registry.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include +#include + +namespace chip { +namespace Tracing { +namespace { + +IntrusiveList gTracingBackends; + +} // namespace + +void Register(Backend & backend) +{ + assertChipStackLockedByCurrentThread(); + gTracingBackends.PushBack(&backend); +} + +void Unregister(Backend & backend) +{ + assertChipStackLockedByCurrentThread(); + gTracingBackends.Remove(&backend); +} + +#ifdef MATTER_TRACING_ENABLED + +namespace Internal { + +void Begin(::chip::Tracing::Scope scope) +{ + for (auto & backend : gTracingBackends) + { + backend.TraceBegin(scope); + } +} + +void End(::chip::Tracing::Scope scope) +{ + for (auto & backend : gTracingBackends) + { + backend.TraceEnd(scope); + } +} +void Instant(::chip::Tracing::Instant instant) +{ + for (auto & backend : gTracingBackends) + { + backend.TraceInstant(instant); + } +} + +void LogMessageSend(::chip::Tracing::MessageSendInfo & info) +{ + for (auto & backend : gTracingBackends) + { + backend.LogMessageSend(info); + } +} + +void LogMessageReceived(::chip::Tracing::MessageReceiveInfo & info) +{ + for (auto & backend : gTracingBackends) + { + backend.LogMessageReceived(info); + } +} + +void LogNodeLookup(::chip::Tracing::NodeLookupInfo & info) +{ + for (auto & backend : gTracingBackends) + { + backend.LogNodeLookup(info); + } +} + +void LogNodeDiscovered(::chip::Tracing::NodeDiscoveredInfo & info) +{ + for (auto & backend : gTracingBackends) + { + backend.LogNodeDiscovered(info); + } +} + +void LogNodeDiscoveryFailed(::chip::Tracing::NodeDiscoveryFailedInfo & info) +{ + for (auto & backend : gTracingBackends) + { + backend.LogNodeDiscoveryFailed(info); + } +} + +} // namespace Internal + +#endif // MATTTER_TRACING_ENABLED + +} // namespace Tracing +} // namespace chip diff --git a/src/tracing/registry.h b/src/tracing/registry.h new file mode 100644 index 00000000000000..b1596144dbc00f --- /dev/null +++ b/src/tracing/registry.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace chip { +namespace Tracing { + +/// Registers a tracing backend to receive trace and logging data +/// Until it is unregistered +/// +/// All tracing backends MUST be unregistered before the application +/// exits. Consider using [ScopedRegistration] +/// +/// MUST be called with the Matter thread lock held (from the Matter main loop or +/// at application main) +void Register(Backend & backend); + +/// Unregister a backend from receiving tracing/logging data +/// +/// MUST be called with the Matter thread lock held (from the Matter main loop or +/// at application main) +void Unregister(Backend & backend); + +/// Convenience class to apply Register/Unregister automatically +/// for a backend. +/// +/// This ensures the "MUST unregister before application exit" +/// is always met. +/// +/// Prefer to use this class instead of direct register/unregister. +class ScopedRegistration +{ +public: + ScopedRegistration(Backend & backend) : mBackend(&backend) { Register(*mBackend); } + ~ScopedRegistration() { Unregister(*mBackend); } + +private: + Backend * mBackend; +}; + +#ifdef MATTER_TRACING_ENABLED + +// Internal calls, that will delegate to appropriate backends as needed +namespace Internal { + +void Begin(::chip::Tracing::Scope scope); +void End(::chip::Tracing::Scope scope); +void Instant(::chip::Tracing::Instant instant); + +void LogMessageSend(::chip::Tracing::MessageSendInfo & info); +void LogMessageReceived(::chip::Tracing::MessageReceiveInfo & info); +void LogNodeLookup(::chip::Tracing::NodeLookupInfo & info); +void LogNodeDiscovered(::chip::Tracing::NodeDiscoveredInfo & info); +void LogNodeDiscoveryFailed(::chip::Tracing::NodeDiscoveryFailedInfo & info); + +} // namespace Internal + +#endif // MATTTER_TRACING_ENABLED + +} // namespace Tracing +} // namespace chip diff --git a/src/tracing/scope.h b/src/tracing/scope.h new file mode 100644 index 00000000000000..a636d2511d0dc8 --- /dev/null +++ b/src/tracing/scope.h @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace chip { +namespace Tracing { + +/// Convenience class for RAII for scoped tracing +/// +/// Usage: +/// { +/// ::chip::Tracing::Scoped scope(::chip::Tracing::Scope::CASESession_SendSigma1); +/// // TRACE_BEGIN called here +/// +/// // ... add code here +/// +/// } // TRACE_END called here +class Scoped +{ +public: + inline Scoped(Scope scope) : mScope(scope) { MATTER_TRACE_BEGIN(scope); } + inline ~Scoped() { MATTER_TRACE_END(mScope); } + +private: + Scope mScope; +}; + +} // namespace Tracing +} // namespace chip + +#define _CONCAT_IMPL(a, b) a##b +#define _MACRO_CONCAT(a, b) _CONCAT_IMPL(a, b) + +/// convenience macro to create a tracing scope +/// +/// Usage: +/// { +/// MATTER_TRACE_SCOPE(::chip::Tracing::Scope::CASESession_SendSigma1); +/// // TRACE_BEGIN called here +/// +/// // ... add code here +/// +/// } // TRACE_END called here +#define MATTER_TRACE_SCOPE(scope) ::chip::Tracing::Scoped _MACRO_CONCAT(_trace_scope, __COUNTER__)(scope) diff --git a/src/tracing/scopes.h b/src/tracing/scopes.h new file mode 100644 index 00000000000000..f184d7fc521b27 --- /dev/null +++ b/src/tracing/scopes.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace chip { +namespace Tracing { + +/// Trace scopes defined as an enumeration, since various tracing back-ends +/// may need to use constant strings for tracing. +/// +/// As a result, tracing scopes in CHIP are from a known list. +enum class Scope +{ + UndefinedDoNotUse = 0, + + CASESession_EstablishSession = 1, + CASESession_HandleSigma1 = 2, + CASESession_HandleSigma1_and_SendSigma2 = 3, + CASESession_HandleSigma2 = 4, + CASESession_HandleSigma2_and_SendSigma3 = 5, + CASESession_HandleSigma2Resume = 6, + CASESession_HandleSigma3 = 7, + CASESession_SendSigma1 = 8, + CASESession_SendSigma2 = 9, + CASESession_SendSigma2Resume = 10, + CASESession_SendSigma3 = 11, + DeviceCommissioner_Commission = 12, + DeviceCommissioner_CommissioningStageComplete = 13, + DeviceCommissioner_continueCommissioningDevice = 14, + DeviceCommissioner_EstablishPASEConnection = 15, + DeviceCommissioner_FindCommissioneeDevice = 16, + DeviceCommissioner_IssueNOCChain = 17, + DeviceCommissioner_OnAddNOCFailureResponse = 18, + DeviceCommissioner_OnAttestationFailureResponse = 19, + DeviceCommissioner_OnAttestationResponse = 20, + DeviceCommissioner_OnCertificateChainFailureResponse = 21, + DeviceCommissioner_OnCertificateChainResponse = 22, + DeviceCommissioner_OnCSRFailureResponse = 23, + DeviceCommissioner_OnDeviceAttestationInformationVerification = 24, + DeviceCommissioner_OnDeviceNOCChainGeneration = 25, + DeviceCommissioner_OnOperationalCertificateAddResponse = 26, + DeviceCommissioner_OnOperationalCertificateSigningRequest = 27, + DeviceCommissioner_OnOperationalCredentialsProvisioningCompletion = 28, + DeviceCommissioner_OnRootCertFailureResponse = 29, + DeviceCommissioner_OnRootCertSuccessResponse = 30, + DeviceCommissioner_PairDevice = 31, + DeviceCommissioner_ProcessOpCSR = 32, + DeviceCommissioner_SendAttestationRequestCommand = 33, + DeviceCommissioner_SendCertificateChainRequestCommand = 34, + DeviceCommissioner_SendOperationalCertificate = 35, + DeviceCommissioner_SendOperationalCertificateSigningRequestCommand = 36, + DeviceCommissioner_SendTrustedRootCertificate = 37, + DeviceCommissioner_UnpairDevice = 38, + DeviceCommissioner_ValidateAttestationInfo = 39, + DeviceCommissioner_ValidateCSR = 40, + GeneralCommissioning_ArmFailSafe = 41, + GeneralCommissioning_CommissioningComplete = 42, + GeneralCommissioning_SetRegulatoryConfig = 43, + NetworkCommissioning_HandleAddOrUpdateThreadNetwork = 44, + NetworkCommissioning_HandleAddOrUpdateWiFiNetwork = 45, + NetworkCommissioning_HandleConnectNetwork = 46, + NetworkCommissioning_HandleRemoveNetwork = 47, + NetworkCommissioning_HandleReorderNetwork = 48, + NetworkCommissioning_HandleScanNetwork = 49, + OperationalCredentials_AddNOC = 50, + OperationalCredentials_AddTrustedRootCertificate = 51, + OperationalCredentials_AttestationRequest = 52, + OperationalCredentials_CertificateChainRequest = 53, + OperationalCredentials_CSRRequest = 54, + OperationalCredentials_RemoveFabric = 55, + OperationalCredentials_UpdateFabricLabel = 56, + OperationalCredentials_UpdateNOC = 57, + PASESession_GeneratePASEVerifier = 58, + PASESession_HandleMsg1_and_SendMsg2 = 59, + PASESession_HandleMsg2_and_SendMsg3 = 60, + PASESession_HandleMsg3 = 61, + PASESession_HandlePBKDFParamRequest = 62, + PASESession_HandlePBKDFParamResponse = 63, + PASESession_Pair = 64, + PASESession_SendMsg1 = 65, + PASESession_SendPBKDFParamRequest = 66, + PASESession_SendPBKDFParamResponse = 67, + PASESession_SetupSpake2p = 68, +}; + +/// An event that happened at an instant (like a zero sized scope) +enum class Instant +{ + UndefinedDoNotUse = 0, + + // General instant notifications + Resolve_TxtNotApplicable = 1, + Resolve_Ipv4NotApplicable = 2, + Resolve_Ipv6NotApplicable = 3, + + // Used if and only if default "Log*" requests + // are not implemented in the backend. + Log_MessageSend = 1000, + Log_MessageReceived = 1001, + Log_NodeLookup = 1002, + Log_NodeDiscovered = 1003, + Log_NodeDiscoveryFailed = 1004, +}; + +} // namespace Tracing +} // namespace chip diff --git a/src/tracing/tests/BUILD.gn b/src/tracing/tests/BUILD.gn new file mode 100644 index 00000000000000..674f33ec5b3c78 --- /dev/null +++ b/src/tracing/tests/BUILD.gn @@ -0,0 +1,33 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/nlunit_test.gni") + +import("${chip_root}/build/chip/chip_test_suite.gni") + +chip_test_suite("tests") { + output_name = "libTracingTests" + + test_sources = [ "TestTracing.cpp" ] + sources = [] + + public_deps = [ + "${chip_root}/src/lib/support:testing", + "${chip_root}/src/platform", + "${chip_root}/src/tracing", + "${nlunit_test_root}:nlunit-test", + ] +} diff --git a/src/tracing/tests/TestTracing.cpp b/src/tracing/tests/TestTracing.cpp new file mode 100644 index 00000000000000..2026f376daa3ab --- /dev/null +++ b/src/tracing/tests/TestTracing.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include + +#include +#include + +using namespace chip; +using namespace chip::Tracing; + +namespace { + +// This keeps a log of all received trace items +class LoggingTraceBackend : public Backend +{ +public: + enum class TraceEventType + { + BEGIN, + END + }; + + struct ReceivedTraceEvent + { + TraceEventType type; + Scope scope; + + bool operator==(const ReceivedTraceEvent & other) const { return (type == other.type) && (scope == other.scope); } + }; + + LoggingTraceBackend() {} + const std::vector & traces() const { return mTraces; } + + // Implementation + void TraceBegin(Scope scope) override { mTraces.push_back(ReceivedTraceEvent{ TraceEventType::BEGIN, scope }); } + + void TraceEnd(Scope scope) override { mTraces.push_back(ReceivedTraceEvent{ TraceEventType::END, scope }); } + + void TraceInstant(Instant instant) override + { + // NOT SUPPORTED HERE + } + +private: + std::vector mTraces; +}; + +void TestBasicTracing(nlTestSuite * inSuite, void * inContext) +{ + LoggingTraceBackend backend; + + { + ScopedRegistration scope(backend); + + MATTER_TRACE_SCOPE(Scope::CASESession_SendSigma1); + { + MATTER_TRACE_SCOPE(Scope::CASESession_SendSigma2); + + // direct scope begin/end (not usual, but should work) + MATTER_TRACE_BEGIN(Scope::OperationalCredentials_AddNOC); + MATTER_TRACE_BEGIN(Scope::OperationalCredentials_UpdateNOC); + MATTER_TRACE_END(Scope::OperationalCredentials_UpdateNOC); + MATTER_TRACE_END(Scope::OperationalCredentials_AddNOC); + } + { + MATTER_TRACE_SCOPE(Scope::CASESession_SendSigma3); + } + } + + std::vector expected = { + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma1 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma2 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::OperationalCredentials_AddNOC }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::OperationalCredentials_UpdateNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::OperationalCredentials_UpdateNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::OperationalCredentials_AddNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma2 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma1 }, + }; + + NL_TEST_ASSERT(inSuite, backend.traces().size() == expected.size()); + NL_TEST_ASSERT(inSuite, std::equal(backend.traces().begin(), backend.traces().end(), expected.begin(), expected.end())); +} + +void TestMultipleBackends(nlTestSuite * inSuite, void * inContext) +{ + LoggingTraceBackend b1; + LoggingTraceBackend b2; + LoggingTraceBackend b3; + + { + ScopedRegistration register1(b1); + MATTER_TRACE_SCOPE(Scope::CASESession_SendSigma1); + + { + ScopedRegistration register2(b2); + MATTER_TRACE_SCOPE(Scope::CASESession_SendSigma2); + + { + ScopedRegistration register3(b3); + MATTER_TRACE_SCOPE(Scope::CASESession_SendSigma3); + } + { + MATTER_TRACE_SCOPE(Scope::OperationalCredentials_AddNOC); + } + } + } + + std::vector expected1 = { + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma1 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma2 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::OperationalCredentials_AddNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::OperationalCredentials_AddNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma2 }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma1 }, + }; + + NL_TEST_ASSERT(inSuite, b1.traces().size() == expected1.size()); + NL_TEST_ASSERT(inSuite, std::equal(b1.traces().begin(), b1.traces().end(), expected1.begin(), expected1.end())); + + std::vector expected2 = { + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma2 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::OperationalCredentials_AddNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::OperationalCredentials_AddNOC }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma2 }, + }; + + NL_TEST_ASSERT(inSuite, b2.traces().size() == expected2.size()); + NL_TEST_ASSERT(inSuite, std::equal(b2.traces().begin(), b2.traces().end(), expected2.begin(), expected2.end())); + + std::vector expected3 = { + { LoggingTraceBackend::TraceEventType::BEGIN, Scope::CASESession_SendSigma3 }, + { LoggingTraceBackend::TraceEventType::END, Scope::CASESession_SendSigma3 }, + }; + + NL_TEST_ASSERT(inSuite, b3.traces().size() == expected3.size()); + NL_TEST_ASSERT(inSuite, std::equal(b3.traces().begin(), b3.traces().end(), expected3.begin(), expected3.end())); +} + +const nlTest sTests[] = { + NL_TEST_DEF("BasicTracing", TestBasicTracing), // + NL_TEST_DEF("BasicMultipleBackends", TestMultipleBackends), // + NL_TEST_SENTINEL() // +}; + +} // namespace + +int TestTracing() +{ + nlTestSuite theSuite = { "Tracing tests", &sTests[0], nullptr, nullptr }; + + // Run test suit againt one context. + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestTracing)