From 9343d3a02cde8d3148f25d855d8d8447f61329b1 Mon Sep 17 00:00:00 2001 From: Anush Nadathur Date: Wed, 13 Mar 2024 14:19:35 -0700 Subject: [PATCH] Added macro variants with metric support matching the ones in CodeUtils (#32553) - Added Verify/Return/Log/Succ/Exit XYZ WithMetric macro variants for use in metrics - Added unit tests for these macro variants --- src/tracing/metric_macros.h | 376 ++++++++++++++++++++++++- src/tracing/tests/TestMetricEvents.cpp | 335 +++++++++++++++++++++- 2 files changed, 700 insertions(+), 11 deletions(-) diff --git a/src/tracing/metric_macros.h b/src/tracing/metric_macros.h index 4ff85f353701b3..26dde8cd3230a0 100644 --- a/src/tracing/metric_macros.h +++ b/src/tracing/metric_macros.h @@ -27,13 +27,258 @@ #if MATTER_TRACING_ENABLED /** - * @def SuccessOrExitWithMetric(kMetriKey, error) + * @def ReturnErrorOnFailureWithMetric(kMetricKey, expr) + * + * @brief + * This macros emits the specified metric with error code and returns the error code, + * if the expression returns an error. For a CHIP_ERROR expression, this means any value + * other than CHIP_NO_ERROR. For an integer expression, this means non-zero. + * + * Example usage: + * + * @code + * ReturnErrorOnFailureWithMetric(kMetricKey, channel->SendMsg(msg)); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * does not evaluate to CHIP_NO_ERROR. Value of the metric is to the + * result of the expression. + * @param[in] expr An expression to be tested. + */ +#define ReturnErrorOnFailureWithMetric(kMetricKey, expr) \ + do \ + { \ + auto __err = (expr); \ + if (!::chip::ChipError::IsSuccess(__err)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, __err); \ + return __err; \ + } \ + } while (false) + +/** + * @def ReturnLogErrorOnFailureWithMetric(kMetricKey, expr) + * + * @brief + * Returns the error code if the expression returns something different + * than CHIP_NO_ERROR. In addition, a metric is emitted with the specified metric key and + * error code as the value of the metric. + * + * Example usage: + * + * @code + * ReturnLogErrorOnFailureWithMetric(kMetricKey, channel->SendMsg(msg)); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * does not evaluate to CHIP_NO_ERROR. Value of the metric is to the + * result of the expression. + * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR. + */ +#define ReturnLogErrorOnFailureWithMetric(kMetricKey, expr) \ + do \ + { \ + CHIP_ERROR __err = (expr); \ + if (__err != CHIP_NO_ERROR) \ + { \ + MATTER_LOG_METRIC(kMetricKey, __err); \ + ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \ + return __err; \ + } \ + } while (false) + +/** + * @def ReturnOnFailureWithMetric(kMetricKey, expr) + * + * @brief + * Returns if the expression returns an error. For a CHIP_ERROR expression, this means any value other + * than CHIP_NO_ERROR. For an integer expression, this means non-zero. If the expression evaluates to + * anything but CHIP_NO_ERROR, a metric with the specified key is emitted along with error as the value. + * + * Example usage: + * + * @code + * ReturnOnFailureWithMetric(kMetricKey, channel->SendMsg(msg)); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * does not evaluate to CHIP_NO_ERROR. Value of the metric is to the + * result of the expression. + * @param[in] expr An expression to be tested. + */ +#define ReturnOnFailureWithMetric(kMetricKey, expr) \ + do \ + { \ + auto __err = (expr); \ + if (!::chip::ChipError::IsSuccess(__err)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, __err); \ + return; \ + } \ + } while (false) + +/** + * @def VerifyOrReturnWithMetric(kMetricKey, expr, ...) + * + * @brief + * Returns from the void function if expression evaluates to false. If the expression evaluates + * to false, a metric with the specified key is emitted. + * + * Example usage: + * + * @code + * VerifyOrReturnWithMetric(kMetricKey, param != nullptr, LogError("param is nullptr")); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * to false. Value of the metric is set to false. + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] ... Statements to execute before returning. Optional. + */ +#define VerifyOrReturnWithMetric(kMetricKey, expr, ...) \ + do \ + { \ + if (!(expr)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, false); \ + __VA_ARGS__; \ + return; \ + } \ + } while (false) + +/** + * @def VerifyOrReturnErrorWithMetric(kMetricKey, expr, code, ...) + * + * @brief + * Returns a specified error code if expression evaluates to false. If the expression evaluates + * to false, a metric with the specified key is emitted with the value set to the code. + * + * Example usage: + * + * @code + * VerifyOrReturnErrorWithMetric(kMetricKey, param != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * to false. Value of the metric is to code. + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] code A value to return if @a expr is false. + * @param[in] ... Statements to execute before returning. Optional. + */ +#define VerifyOrReturnErrorWithMetric(kMetricKey, expr, code, ...) \ + VerifyOrReturnValueWithMetric(kMetricKey, expr, code, ##__VA_ARGS__) + +/** + * @def VerifyOrReturnValueWithMetric(kMetricKey, expr, value, ...) + * + * @brief + * Returns a specified value if expression evaluates to false. If the expression evaluates + * to false, a metric with the specified key is emitted with the value set to value. + * + * Example usage: + * + * @code + * VerifyOrReturnValueWithMetric(kMetricKey, param != nullptr, Foo()); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * to false. Value of the metric is to value. + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] value A value to return if @a expr is false. + * @param[in] ... Statements to execute before returning. Optional. + */ +#define VerifyOrReturnValueWithMetric(kMetricKey, expr, value, ...) \ + do \ + { \ + if (!(expr)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, value); \ + __VA_ARGS__; \ + return (value); \ + } \ + } while (false) + +/** + * @def VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) + * + * @brief + * Returns and print a specified error code if expression evaluates to false. + * If the expression evaluates to false, a metric with the specified key is emitted + * with the value set to code. + * + * Example usage: + * + * @code + * VerifyOrReturnLogErrorWithMetric(kMetricKey, param != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * to false. Value of the metric is to code. + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] code A value to return if @a expr is false. + */ +#if CHIP_CONFIG_ERROR_SOURCE +#define VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) \ + do \ + { \ + if (!(expr)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, code); \ + ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(code), __FILE__, __LINE__); \ + return code; \ + } \ + } while (false) +#else // CHIP_CONFIG_ERROR_SOURCE +#define VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) \ + do \ + { \ + if (!(expr)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, code); \ + ChipLogError(NotSpecified, "%s:%d false: %" CHIP_ERROR_FORMAT, #expr, __LINE__, code.Format()); \ + return code; \ + } \ + } while (false) +#endif // CHIP_CONFIG_ERROR_SOURCE + +/** + * @def ReturnErrorCodeWithMetricIf(kMetricKey, expr, code) + * + * @brief + * Returns a specified error code if expression evaluates to true + * If the expression evaluates to true, a metric with the specified key is emitted + * with the value set to code. + * + * Example usage: + * + * @code + * ReturnErrorCodeWithMetricIf(kMetricKey, state == kInitialized, CHIP_NO_ERROR); + * ReturnErrorCodeWithMetricIf(kMetricKey, state == kInitialized, CHIP_ERROR_INCORRECT_STATE); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * to true. Value of the metric is to code. + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] code A value to return if @a expr is false. + */ +#define ReturnErrorCodeWithMetricIf(kMetricKey, expr, code) \ + do \ + { \ + if (expr) \ + { \ + MATTER_LOG_METRIC(kMetricKey, code); \ + return code; \ + } \ + } while (false) + +/** + * @def SuccessOrExitWithMetric(kMetricKey, error) * * @brief * This checks for the specified error, which is expected to * commonly be successful (CHIP_NO_ERROR), and branches to * the local label 'exit' if the error is not success. - * If error is not a success, a metric with key kMetriKey is emitted with + * If error is not a success, a metric with key kMetricKey is emitted with * the error code as the value of the metric. * * Example Usage: @@ -100,9 +345,110 @@ #define VerifyOrExitWithMetric(kMetricKey, aCondition, anAction) \ nlEXPECT_ACTION(aCondition, exit, MATTER_LOG_METRIC((kMetricKey), (anAction))) -/* - * Utility Macros to support optional arguments for MATTER_LOG_METRIC_XYZ macros +/** + * @def ExitNowWithMetric(kMetricKey, ...) + * + * @brief + * This unconditionally executes @a ... and branches to the local + * label 'exit'. In addition a metric is emitted with the specified key. + * + * @note The use of this interface implies neither success nor + * failure for the overall exit status of the enclosing function + * body. + * + * Example Usage: + * + * @code + * CHIP_ERROR ReadAll(Reader& reader) + * { + * CHIP_ERROR err; + * + * while (true) + * { + * err = reader.ReadNext(); + * if (err == CHIP_ERROR_AT_END) + * ExitNowWithMetric(kMetricKey, err = CHIP_NO_ERROR); + * SuccessOrExit(err); + * DoSomething(); + * } + * + * exit: + * return err; + * } + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted. + * @param[in] ... Statements to execute. Optional. */ +#define ExitNowWithMetric(kMetricKey, ...) \ + do \ + { \ + MATTER_LOG_METRIC(kMetricKey); \ + __VA_ARGS__; \ + goto exit; \ + } while (0) + +/** + * @def LogErrorOnFailureWithMetric(kMetricKey, expr) + * + * @brief + * Logs a message if the expression returns something different than CHIP_NO_ERROR. + * In addition, a metric is emitted with the specified key and value set to result + * of the expression in case it evaluates to anything other than CHIP_NO_ERROR. + * + * Example usage: + * + * @code + * LogErrorOnFailureWithMetric(kMetricKey, channel->SendMsg(msg)); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates + * does not evaluate to CHIP_NO_ERROR. Value of the metric is to the + * result of the expression. + * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR. + */ +#define LogErrorOnFailureWithMetric(kMetricKey, expr) \ + do \ + { \ + CHIP_ERROR __err = (expr); \ + if (__err != CHIP_NO_ERROR) \ + { \ + MATTER_LOG_METRIC(kMetricKey, __err); \ + ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \ + } \ + } while (false) + +/** + * @def VerifyOrDoWithMetric(kMetricKey, expr, ...) + * + * @brief + * Do something if expression evaluates to false. If the expression evaluates to false a metric + * with the specified key is emitted with value set to false. + * + * Example usage: + * + * @code + * VerifyOrDoWithMetric(param != nullptr, LogError("param is nullptr")); + * @endcode + * + * @param[in] kMetricKey Metric key for the metric event to be emitted. + * Value of the metric is set to false. + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] ... Statements to execute. + */ +#define VerifyOrDoWithMetric(kMetricKey, expr, ...) \ + do \ + { \ + if (!(expr)) \ + { \ + MATTER_LOG_METRIC(kMetricKey, false); \ + __VA_ARGS__; \ + } \ + } while (false) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Utility Macros to support optional arguments for MATTER_LOG_METRIC_XYZ macros +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Utility to always return the 4th argument from macro parameters #define __GET_4TH_ARG(_a1, _a2, _a3, _a4, ...) _a4 @@ -222,10 +568,32 @@ // Remap Success, Return, and Verify macros to the ones without metrics //////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define ReturnErrorOnFailureWithMetric(kMetricKey, expr) ReturnErrorOnFailure(expr) + +#define ReturnLogErrorOnFailureWithMetric(kMetricKey, expr) ReturnLogErrorOnFailure(expr) + +#define ReturnOnFailureWithMetric(kMetricKey, expr) ReturnOnFailure(expr) + +#define VerifyOrReturnWithMetric(kMetricKey, expr, ...) VerifyOrReturn(expr, ##__VA_ARGS__) + +#define VerifyOrReturnErrorWithMetric(kMetricKey, expr, code, ...) VerifyOrReturnValue(expr, code, ##__VA_ARGS__) + +#define VerifyOrReturnValueWithMetric(kMetricKey, expr, value, ...) VerifyOrReturnValue(expr, value, ##__VA_ARGS__) + +#define VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) VerifyOrReturnLogError(expr, code) + +#define ReturnErrorCodeWithMetricIf(kMetricKey, expr, code) ReturnErrorCodeIf(expr, code) + #define SuccessOrExitWithMetric(kMetricKey, aStatus) SuccessOrExit(aStatus) #define VerifyOrExitWithMetric(kMetricKey, aCondition, anAction) VerifyOrExit(aCondition, anAction) +#define ExitNowWithMetric(kMetricKey, ...) ExitNow(##__VA_ARGS__) + +#define LogErrorOnFailureWithMetric(kMetricKey, expr) LogErrorOnFailure(expr) + +#define VerifyOrDoWithMetric(kMetricKey, expr, ...) VerifyOrDo(expr, ##__VA_ARGS__) + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Map all MATTER_LOG_METRIC_XYZ macros to noops //////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/tracing/tests/TestMetricEvents.cpp b/src/tracing/tests/TestMetricEvents.cpp index c52a5fc91b9e93..72e159df7cf7fa 100644 --- a/src/tracing/tests/TestMetricEvents.cpp +++ b/src/tracing/tests/TestMetricEvents.cpp @@ -324,14 +324,335 @@ void TestSuccessOrExitWithMetric(nlTestSuite * inSuite, void * inContext) inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); } +static CHIP_ERROR InvokeReturnErrorOnFailureWithMetric(MetricKey key, const CHIP_ERROR & error) +{ + ReturnErrorOnFailureWithMetric(key, error); + return CHIP_NO_ERROR; +} + +void TestReturnErrorOnFailureWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + CHIP_ERROR err = InvokeReturnErrorOnFailureWithMetric("event0", CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = InvokeReturnErrorOnFailureWithMetric("event1", CHIP_ERROR_INCORRECT_STATE); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INCORRECT_STATE); + + err = InvokeReturnErrorOnFailureWithMetric("event2", CHIP_ERROR_BAD_REQUEST); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BAD_REQUEST); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +static CHIP_ERROR InvokeReturnLogErrorOnFailureWithMetric(MetricKey key, const CHIP_ERROR & error) +{ + ReturnLogErrorOnFailureWithMetric(key, error); + return CHIP_NO_ERROR; +} + +void TestReturnLogErrorOnFailureWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + CHIP_ERROR err = InvokeReturnLogErrorOnFailureWithMetric("event0", CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = InvokeReturnLogErrorOnFailureWithMetric("event1", CHIP_ERROR_INCORRECT_STATE); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INCORRECT_STATE); + + err = InvokeReturnLogErrorOnFailureWithMetric("event2", CHIP_ERROR_BAD_REQUEST); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BAD_REQUEST); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +static void InvokeReturnOnFailureWithMetric(MetricKey key, const CHIP_ERROR & error) +{ + ReturnOnFailureWithMetric(key, error); + return; +} + +void TestReturnOnFailureWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + InvokeReturnOnFailureWithMetric("event0", CHIP_NO_ERROR); + + InvokeReturnOnFailureWithMetric("event1", CHIP_ERROR_INCORRECT_STATE); + + InvokeReturnOnFailureWithMetric("event2", CHIP_ERROR_BAD_REQUEST); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +static void InvokeVerifyOrReturnWithMetric(MetricKey key, bool result) +{ + VerifyOrReturnWithMetric(key, result); + return; +} + +void TestInvokeVerifyOrReturnWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + InvokeVerifyOrReturnWithMetric("event0", DoubleOf(2) == 4); + InvokeVerifyOrReturnWithMetric("event1", DoubleOf(3) == 9); + InvokeVerifyOrReturnWithMetric("event2", DoubleOf(4) == 8); + InvokeVerifyOrReturnWithMetric("event3", DoubleOf(5) == 11); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", false), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3", false), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +static CHIP_ERROR InvokeVerifyOrReturnErrorWithMetric(MetricKey key, bool expr, const CHIP_ERROR & error) +{ + VerifyOrReturnErrorWithMetric(key, expr, error); + return CHIP_NO_ERROR; +} + +void TestVerifyOrReturnErrorWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + CHIP_ERROR err = InvokeVerifyOrReturnErrorWithMetric("event0", DoubleOf(2) == 4, CHIP_ERROR_BAD_REQUEST); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = InvokeVerifyOrReturnErrorWithMetric("event1", DoubleOf(3) == 9, CHIP_ERROR_ACCESS_DENIED); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_ACCESS_DENIED); + + err = InvokeVerifyOrReturnErrorWithMetric("event2", DoubleOf(4) == 8, CHIP_ERROR_BUSY); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = InvokeVerifyOrReturnErrorWithMetric("event3", DoubleOf(5) == 11, CHIP_ERROR_CANCELLED); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_CANCELLED); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_ACCESS_DENIED), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3", CHIP_ERROR_CANCELLED), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +template +static return_code_type InvokeVerifyOrReturnValueWithMetric(MetricKey key, bool expr, return_code_type retval) +{ + VerifyOrReturnValueWithMetric(key, expr, retval); + return return_code_type(); +} + +void TestVerifyOrReturnValueWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + auto retval = InvokeVerifyOrReturnValueWithMetric("event0", DoubleOf(2) == 4, 0); + NL_TEST_ASSERT(inSuite, retval == 0); + + auto err = InvokeVerifyOrReturnValueWithMetric("event1", DoubleOf(3) == 9, CHIP_ERROR_ACCESS_DENIED); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_ACCESS_DENIED); + + err = InvokeVerifyOrReturnValueWithMetric("event2", DoubleOf(4) == 8, CHIP_ERROR_BAD_REQUEST); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + retval = InvokeVerifyOrReturnValueWithMetric("event3", DoubleOf(5) == 11, 16); + NL_TEST_ASSERT(inSuite, retval == 16); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_ACCESS_DENIED), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3", 16), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +static CHIP_ERROR InvokeVerifyOrReturnLogErrorWithMetric(MetricKey key, bool expr, const CHIP_ERROR & error) +{ + VerifyOrReturnLogErrorWithMetric(key, expr, error); + return CHIP_NO_ERROR; +} + +void TestVerifyOrReturnLogErrorWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + auto err = InvokeVerifyOrReturnLogErrorWithMetric("event0", DoubleOf(2) == 4, CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = InvokeVerifyOrReturnLogErrorWithMetric("event1", DoubleOf(3) == 9, CHIP_ERROR_CANCELLED); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_CANCELLED); + + err = InvokeVerifyOrReturnLogErrorWithMetric("event2", DoubleOf(4) == 8, CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = InvokeVerifyOrReturnLogErrorWithMetric("event3", DoubleOf(5) == 11, CHIP_ERROR_BAD_REQUEST); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BAD_REQUEST); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_CANCELLED), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3", CHIP_ERROR_BAD_REQUEST), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +template +static return_code_type InvokeReturnErrorCodeWithMetricIf(MetricKey key, bool expr, const return_code_type & code) +{ + ReturnErrorCodeWithMetricIf(key, expr, code); + return return_code_type(); +} + +void TestReturnErrorCodeWithMetricIf(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + auto err = InvokeReturnErrorCodeWithMetricIf("event0", DoubleOf(2) == 4, CHIP_ERROR_DUPLICATE_KEY_ID); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_DUPLICATE_KEY_ID); + + auto retval = InvokeReturnErrorCodeWithMetricIf("event1", DoubleOf(3) == 9, 11); + NL_TEST_ASSERT(inSuite, retval == 0); + + retval = InvokeReturnErrorCodeWithMetricIf("event2", DoubleOf(4) == 8, 22); + NL_TEST_ASSERT(inSuite, retval == 22); + + err = InvokeReturnErrorCodeWithMetricIf("event3", DoubleOf(5) == 11, CHIP_ERROR_ACCESS_DENIED); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event0", CHIP_ERROR_DUPLICATE_KEY_ID), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", 22), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +void TestExitNowWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + chip::ChipError err = CHIP_NO_ERROR; + + ExitNowWithMetric("event0", err = CHIP_ERROR_BUSY); + +exit: + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event0"), + }; + + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BUSY); + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +void TestLogErrorOnFailureWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + LogErrorOnFailureWithMetric("event0", CHIP_ERROR_BAD_REQUEST); + LogErrorOnFailureWithMetric("event1", CHIP_NO_ERROR); + LogErrorOnFailureWithMetric("event2", CHIP_ERROR_DATA_NOT_ALIGNED); + LogErrorOnFailureWithMetric("event3", CHIP_ERROR_BUSY); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event0", CHIP_ERROR_BAD_REQUEST), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_DATA_NOT_ALIGNED), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3", CHIP_ERROR_BUSY), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +void TestVerifyOrDoWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + + VerifyOrDoWithMetric("event0", DoubleOf(2) == 5); + VerifyOrDoWithMetric("event1", DoubleOf(3) == 6); + VerifyOrDoWithMetric("event2", DoubleOf(4) == 7, MATTER_LOG_METRIC("event4", 10)); + VerifyOrDoWithMetric("event3", DoubleOf(5) == 8); + VerifyOrDoWithMetric("event5", DoubleOf(6) == 12); + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event0", false), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", false), + MetricEvent(MetricEvent::Type::kInstantEvent, "event4", 10), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3", false), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + static const nlTest sMetricTests[] = { - NL_TEST_DEF("BasicMetricEvent", TestBasicMetricEvent), // - NL_TEST_DEF("InstantMetricEvent", TestInstantMetricEvent), // - NL_TEST_DEF("BeginEndMetricEvent", TestBeginEndMetricEvent), // - NL_TEST_DEF("ScopedMetricEvent", TestScopedMetricEvent), // - NL_TEST_DEF("VerifyOrExitWithMetric", TestVerifyOrExitWithMetric), // - NL_TEST_DEF("SuccessOrExitWithMetric", TestSuccessOrExitWithMetric), // - NL_TEST_SENTINEL() // + NL_TEST_DEF("BasicMetricEvent", TestBasicMetricEvent), // + NL_TEST_DEF("InstantMetricEvent", TestInstantMetricEvent), // + NL_TEST_DEF("BeginEndMetricEvent", TestBeginEndMetricEvent), // + NL_TEST_DEF("ScopedMetricEvent", TestScopedMetricEvent), // + NL_TEST_DEF("VerifyOrExitWithMetric", TestVerifyOrExitWithMetric), // + NL_TEST_DEF("SuccessOrExitWithMetric", TestSuccessOrExitWithMetric), // + NL_TEST_DEF("ReturnErrorOnFailureWithMetric", TestReturnErrorOnFailureWithMetric), // + NL_TEST_DEF("ReturnLogErrorOnFailureWithMetric", TestReturnLogErrorOnFailureWithMetric), // + NL_TEST_DEF("ReturnOnFailureWithMetric", TestReturnOnFailureWithMetric), // + NL_TEST_DEF("VerifyOrReturnWithMetric", TestInvokeVerifyOrReturnWithMetric), // + NL_TEST_DEF("VerifyOrReturnErrorWithMetric", TestVerifyOrReturnErrorWithMetric), // + NL_TEST_DEF("VerifyOrReturnValueWithMetric", TestVerifyOrReturnValueWithMetric), // + NL_TEST_DEF("VerifyOrReturnLogErrorWithMetric", TestVerifyOrReturnLogErrorWithMetric), // + NL_TEST_DEF("ReturnErrorCodeWithMetricIf", TestReturnErrorCodeWithMetricIf), // + NL_TEST_DEF("ExitNowWithMetric", TestExitNowWithMetric), // + NL_TEST_DEF("LogErrorOnFailureWithMetric", TestLogErrorOnFailureWithMetric), // + NL_TEST_DEF("VerifyOrDoWithMetric", TestVerifyOrDoWithMetric), // + NL_TEST_SENTINEL() // }; } // namespace