|  | /* | 
|  | *    Copyright (c) 2024 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 <pw_unit_test/framework.h> | 
|  |  | 
|  | #include <lib/core/StringBuilderAdapters.h> | 
|  | #include <tracing/backend.h> | 
|  | #include <tracing/metric_event.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | using namespace chip; | 
|  | using namespace chip::Tracing; | 
|  |  | 
|  | namespace chip { | 
|  | namespace Tracing { | 
|  |  | 
|  | static bool operator==(const MetricEvent & lhs, const MetricEvent & rhs) | 
|  | { | 
|  | if (&lhs == &rhs) | 
|  | { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (lhs.type() == rhs.type() && std::string(lhs.key()) == std::string(rhs.key()) && lhs.ValueType() == rhs.ValueType()) | 
|  | { | 
|  | switch (lhs.ValueType()) | 
|  | { | 
|  | case MetricEvent::Value::Type::kInt32: | 
|  | return lhs.ValueInt32() == rhs.ValueInt32(); | 
|  |  | 
|  | case MetricEvent::Value::Type::kUInt32: | 
|  | return lhs.ValueUInt32() == rhs.ValueUInt32(); | 
|  |  | 
|  | case MetricEvent::Value::Type::kChipErrorCode: | 
|  | return lhs.ValueErrorCode() == rhs.ValueErrorCode(); | 
|  |  | 
|  | case MetricEvent::Value::Type::kUndefined: | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  | } // namespace Tracing | 
|  | } // namespace chip | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // This keeps a log of all received trace items | 
|  | class MetricEventBackend : public Backend | 
|  | { | 
|  | public: | 
|  | MetricEventBackend() {} | 
|  | const std::vector<MetricEvent> & GetMetricEvents() const { return mMetricEvents; } | 
|  |  | 
|  | // Implementation | 
|  | virtual void LogMetricEvent(const MetricEvent & event) { mMetricEvents.push_back(event); } | 
|  |  | 
|  | private: | 
|  | std::vector<MetricEvent> mMetricEvents; | 
|  | }; | 
|  |  | 
|  | TEST(TestMetricEvents, TestBasicMetricEvent) | 
|  | { | 
|  |  | 
|  | { | 
|  | MetricEvent event(MetricEvent::Type::kInstantEvent, "instant_event"); | 
|  | EXPECT_EQ(event.type(), MetricEvent::Type::kInstantEvent); | 
|  | EXPECT_EQ(std::string(event.key()), std::string("instant_event")); | 
|  | EXPECT_EQ(event.ValueType(), MetricEvent::Value::Type::kUndefined); | 
|  | } | 
|  |  | 
|  | { | 
|  | MetricEvent event(MetricEvent::Type::kBeginEvent, "begin_event"); | 
|  | EXPECT_EQ(event.type(), MetricEvent::Type::kBeginEvent); | 
|  | EXPECT_EQ(std::string(event.key()), std::string("begin_event")); | 
|  | EXPECT_EQ(event.ValueType(), MetricEvent::Value::Type::kUndefined); | 
|  | } | 
|  |  | 
|  | { | 
|  | MetricEvent event(MetricEvent::Type::kEndEvent, "end_event"); | 
|  | EXPECT_EQ(event.type(), MetricEvent::Type::kEndEvent); | 
|  | EXPECT_EQ(std::string(event.key()), std::string("end_event")); | 
|  | EXPECT_EQ(event.ValueType(), MetricEvent::Value::Type::kUndefined); | 
|  | } | 
|  |  | 
|  | { | 
|  | MetricEvent event(MetricEvent::Type::kEndEvent, "end_event_with_int32_value", int32_t(42)); | 
|  | EXPECT_EQ(event.type(), MetricEvent::Type::kEndEvent); | 
|  | EXPECT_EQ(std::string(event.key()), std::string("end_event_with_int32_value")); | 
|  | EXPECT_EQ(event.ValueType(), MetricEvent::Value::Type::kInt32); | 
|  | EXPECT_EQ(event.ValueInt32(), 42); | 
|  | } | 
|  |  | 
|  | { | 
|  | MetricEvent event(MetricEvent::Type::kEndEvent, "end_event_with_uint32_value", uint32_t(42)); | 
|  | EXPECT_EQ(event.type(), MetricEvent::Type::kEndEvent); | 
|  | EXPECT_EQ(std::string(event.key()), std::string("end_event_with_uint32_value")); | 
|  | EXPECT_EQ(event.ValueType(), MetricEvent::Value::Type::kUInt32); | 
|  | EXPECT_EQ(event.ValueUInt32(), 42u); | 
|  | } | 
|  |  | 
|  | { | 
|  | MetricEvent event(MetricEvent::Type::kEndEvent, "end_event_with_error_value", CHIP_ERROR_BUSY); | 
|  | EXPECT_EQ(event.type(), MetricEvent::Type::kEndEvent); | 
|  | EXPECT_EQ(std::string(event.key()), std::string("end_event_with_error_value")); | 
|  | EXPECT_EQ(event.ValueType(), MetricEvent::Value::Type::kChipErrorCode); | 
|  | EXPECT_EQ(chip::ChipError(event.ValueErrorCode()), CHIP_ERROR_BUSY); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestInstantMetricEvent) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  |  | 
|  | { | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | MATTER_LOG_METRIC("event1"); | 
|  | MATTER_LOG_METRIC("event2"); | 
|  | MATTER_LOG_METRIC("event3"); | 
|  | } | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1"), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event2"), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event3"), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestBeginEndMetricEvent) | 
|  | { | 
|  | MetricEventBackend backend1; | 
|  | MetricEventBackend backend2; | 
|  |  | 
|  | { | 
|  | ScopedRegistration scope1(backend1); | 
|  | { | 
|  |  | 
|  | MATTER_LOG_METRIC_BEGIN("event1"); | 
|  | MATTER_LOG_METRIC_BEGIN("event2"); | 
|  | MATTER_LOG_METRIC_END("event2", 53); | 
|  | MATTER_LOG_METRIC_END("event1"); | 
|  | } | 
|  |  | 
|  | std::vector<MetricEvent> expected1 = { | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event1"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event2", 53), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event1"), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend1.GetMetricEvents().size(), expected1.size()); | 
|  | EXPECT_TRUE( | 
|  | std::equal(backend1.GetMetricEvents().begin(), backend1.GetMetricEvents().end(), expected1.begin(), expected1.end())); | 
|  |  | 
|  | { | 
|  | ScopedRegistration scope2(backend2); | 
|  |  | 
|  | MATTER_LOG_METRIC_BEGIN("event1"); | 
|  | MATTER_LOG_METRIC_BEGIN("event2"); | 
|  | MATTER_LOG_METRIC_BEGIN("event3"); | 
|  | MATTER_LOG_METRIC_BEGIN("event4"); | 
|  | MATTER_LOG_METRIC_END("event3", CHIP_ERROR_UNKNOWN_KEY_TYPE); | 
|  | MATTER_LOG_METRIC_END("event1", 91u); | 
|  | MATTER_LOG_METRIC_END("event2", 53); | 
|  | MATTER_LOG_METRIC_END("event4"); | 
|  | } | 
|  |  | 
|  | std::vector<MetricEvent> expected2 = { | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event1"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event4"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_UNKNOWN_KEY_TYPE), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event1", 91u), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event2", 53), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event4"), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend2.GetMetricEvents().size(), expected2.size()); | 
|  | EXPECT_TRUE( | 
|  | std::equal(backend2.GetMetricEvents().begin(), backend2.GetMetricEvents().end(), expected2.begin(), expected2.end())); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestScopedMetricEvent) | 
|  | { | 
|  | MetricEventBackend backend1; | 
|  | MetricEventBackend backend2; | 
|  | MetricEventBackend backend3; | 
|  | chip::ChipError err1 = CHIP_NO_ERROR; | 
|  | chip::ChipError err2 = CHIP_NO_ERROR; | 
|  | chip::ChipError err3 = CHIP_NO_ERROR; | 
|  | chip::ChipError err4 = CHIP_NO_ERROR; | 
|  |  | 
|  | { | 
|  | ScopedRegistration scope1(backend1); | 
|  | { | 
|  | MATTER_LOG_METRIC_SCOPE("event1", err1); | 
|  | err1 = CHIP_ERROR_BUSY; | 
|  | { | 
|  | ScopedRegistration scope2(backend2); | 
|  | MATTER_LOG_METRIC_SCOPE("event2", err2); | 
|  | err2 = CHIP_ERROR_BAD_REQUEST; | 
|  |  | 
|  | { | 
|  | ScopedRegistration scope3(backend3); | 
|  | MATTER_LOG_METRIC_SCOPE("event3", err3); | 
|  | err3 = CHIP_ERROR_EVENT_ID_FOUND; | 
|  | } | 
|  | { | 
|  | MATTER_LOG_METRIC_SCOPE("event4", err4); | 
|  | err4 = CHIP_ERROR_BUFFER_TOO_SMALL; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | std::vector<MetricEvent> expected1 = { | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event1"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_EVENT_ID_FOUND), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event4"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event4", CHIP_ERROR_BUFFER_TOO_SMALL), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event2", CHIP_ERROR_BAD_REQUEST), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event1", CHIP_ERROR_BUSY), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend1.GetMetricEvents().size(), expected1.size()); | 
|  | EXPECT_TRUE( | 
|  | std::equal(backend1.GetMetricEvents().begin(), backend1.GetMetricEvents().end(), expected1.begin(), expected1.end())); | 
|  |  | 
|  | std::vector<MetricEvent> expected2 = { | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_EVENT_ID_FOUND), | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event4"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event4", CHIP_ERROR_BUFFER_TOO_SMALL), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event2", CHIP_ERROR_BAD_REQUEST), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend2.GetMetricEvents().size(), expected2.size()); | 
|  | EXPECT_TRUE( | 
|  | std::equal(backend2.GetMetricEvents().begin(), backend2.GetMetricEvents().end(), expected2.begin(), expected2.end())); | 
|  |  | 
|  | std::vector<MetricEvent> expected3 = { | 
|  | MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), | 
|  | MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_EVENT_ID_FOUND), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend3.GetMetricEvents().size(), expected3.size()); | 
|  | EXPECT_TRUE( | 
|  | std::equal(backend3.GetMetricEvents().begin(), backend3.GetMetricEvents().end(), expected3.begin(), expected3.end())); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int DoubleOf(int input) | 
|  | { | 
|  | return input * 2; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestVerifyOrExitWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  | chip::ChipError err = CHIP_NO_ERROR; | 
|  |  | 
|  | VerifyOrExitWithMetric("event0", DoubleOf(2) == 4, err = CHIP_ERROR_BAD_REQUEST); | 
|  | VerifyOrExitWithMetric("event1", DoubleOf(3) == 9, err = CHIP_ERROR_INCORRECT_STATE); | 
|  |  | 
|  | exit: | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestSuccessOrExitWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  | chip::ChipError err = CHIP_NO_ERROR; | 
|  |  | 
|  | SuccessOrExitWithMetric("event1", err = CHIP_NO_ERROR); | 
|  | SuccessOrExitWithMetric("event2", err = CHIP_ERROR_BUSY); | 
|  | SuccessOrExitWithMetric("event3", err = CHIP_NO_ERROR); | 
|  |  | 
|  | exit: | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BUSY), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(err, CHIP_ERROR_BUSY); | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(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; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestReturnErrorOnFailureWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | CHIP_ERROR err = InvokeReturnErrorOnFailureWithMetric("event0", CHIP_NO_ERROR); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | err = InvokeReturnErrorOnFailureWithMetric("event1", CHIP_ERROR_INCORRECT_STATE); | 
|  | EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); | 
|  |  | 
|  | err = InvokeReturnErrorOnFailureWithMetric("event2", CHIP_ERROR_BAD_REQUEST); | 
|  | EXPECT_EQ(err, CHIP_ERROR_BAD_REQUEST); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(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; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestReturnLogErrorOnFailureWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | CHIP_ERROR err = InvokeReturnLogErrorOnFailureWithMetric("event0", CHIP_NO_ERROR); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | err = InvokeReturnLogErrorOnFailureWithMetric("event1", CHIP_ERROR_INCORRECT_STATE); | 
|  | EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); | 
|  |  | 
|  | err = InvokeReturnLogErrorOnFailureWithMetric("event2", CHIP_ERROR_BAD_REQUEST); | 
|  | EXPECT_EQ(err, CHIP_ERROR_BAD_REQUEST); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(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; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestReturnOnFailureWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | InvokeReturnOnFailureWithMetric("event0", CHIP_NO_ERROR); | 
|  |  | 
|  | InvokeReturnOnFailureWithMetric("event1", CHIP_ERROR_INCORRECT_STATE); | 
|  |  | 
|  | InvokeReturnOnFailureWithMetric("event2", CHIP_ERROR_BAD_REQUEST); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | static void InvokeVerifyOrReturnWithMetric(MetricKey key, bool result) | 
|  | { | 
|  | VerifyOrReturnWithMetric(key, result); | 
|  | return; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestInvokeVerifyOrReturnWithMetric) | 
|  | { | 
|  | 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<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", false), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event3", false), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(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; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestVerifyOrReturnErrorWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | CHIP_ERROR err = InvokeVerifyOrReturnErrorWithMetric("event0", DoubleOf(2) == 4, CHIP_ERROR_BAD_REQUEST); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | err = InvokeVerifyOrReturnErrorWithMetric("event1", DoubleOf(3) == 9, CHIP_ERROR_ACCESS_DENIED); | 
|  | EXPECT_EQ(err, CHIP_ERROR_ACCESS_DENIED); | 
|  |  | 
|  | err = InvokeVerifyOrReturnErrorWithMetric("event2", DoubleOf(4) == 8, CHIP_ERROR_BUSY); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | err = InvokeVerifyOrReturnErrorWithMetric("event3", DoubleOf(5) == 11, CHIP_ERROR_CANCELLED); | 
|  | EXPECT_EQ(err, CHIP_ERROR_CANCELLED); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_ACCESS_DENIED), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event3", CHIP_ERROR_CANCELLED), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | template <typename return_code_type> | 
|  | static return_code_type InvokeVerifyOrReturnValueWithMetric(MetricKey key, bool expr, return_code_type retval) | 
|  | { | 
|  | VerifyOrReturnValueWithMetric(key, expr, retval); | 
|  | return return_code_type(); | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestVerifyOrReturnValueWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | auto retval = InvokeVerifyOrReturnValueWithMetric("event0", DoubleOf(2) == 4, 0); | 
|  | EXPECT_EQ(retval, 0); | 
|  |  | 
|  | auto err = InvokeVerifyOrReturnValueWithMetric("event1", DoubleOf(3) == 9, CHIP_ERROR_ACCESS_DENIED); | 
|  | EXPECT_EQ(err, CHIP_ERROR_ACCESS_DENIED); | 
|  |  | 
|  | err = InvokeVerifyOrReturnValueWithMetric("event2", DoubleOf(4) == 8, CHIP_ERROR_BAD_REQUEST); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | retval = InvokeVerifyOrReturnValueWithMetric("event3", DoubleOf(5) == 11, 16); | 
|  | EXPECT_EQ(retval, 16); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_ACCESS_DENIED), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event3", 16), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(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; | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestVerifyOrReturnLogErrorWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | auto err = InvokeVerifyOrReturnLogErrorWithMetric("event0", DoubleOf(2) == 4, CHIP_NO_ERROR); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | err = InvokeVerifyOrReturnLogErrorWithMetric("event1", DoubleOf(3) == 9, CHIP_ERROR_CANCELLED); | 
|  | EXPECT_EQ(err, CHIP_ERROR_CANCELLED); | 
|  |  | 
|  | err = InvokeVerifyOrReturnLogErrorWithMetric("event2", DoubleOf(4) == 8, CHIP_NO_ERROR); | 
|  | EXPECT_EQ(err, CHIP_NO_ERROR); | 
|  |  | 
|  | err = InvokeVerifyOrReturnLogErrorWithMetric("event3", DoubleOf(5) == 11, CHIP_ERROR_BAD_REQUEST); | 
|  | EXPECT_EQ(err, CHIP_ERROR_BAD_REQUEST); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_CANCELLED), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event3", CHIP_ERROR_BAD_REQUEST), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestExitNowWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  | chip::ChipError err = CHIP_NO_ERROR; | 
|  |  | 
|  | ExitNowWithMetric("event0", err = CHIP_ERROR_BUSY); | 
|  |  | 
|  | exit: | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event0"), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(err, CHIP_ERROR_BUSY); | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestLogErrorOnFailureWithMetric) | 
|  | { | 
|  | 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<MetricEvent> 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), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | TEST(TestMetricEvents, TestVerifyOrDoWithMetric) | 
|  | { | 
|  | MetricEventBackend backend; | 
|  | ScopedRegistration scope(backend); | 
|  |  | 
|  | VerifyOrDoWithMetric("event0", DoubleOf(2) == 5, 11); | 
|  | VerifyOrDoWithMetric("event1", DoubleOf(3) == 6, 12); | 
|  | VerifyOrDoWithMetric("event2", DoubleOf(4) == 7, CHIP_ERROR_BAD_REQUEST, MATTER_LOG_METRIC("event4", 10)); | 
|  | VerifyOrDoWithMetric("event3", DoubleOf(5) == 8, 13); | 
|  | VerifyOrDoWithMetric("event5", DoubleOf(6) == 12, 14); | 
|  |  | 
|  | std::vector<MetricEvent> expected = { | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event0", 11), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BAD_REQUEST), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event4", 10), | 
|  | MetricEvent(MetricEvent::Type::kInstantEvent, "event3", 13), | 
|  | }; | 
|  |  | 
|  | EXPECT_EQ(backend.GetMetricEvents().size(), expected.size()); | 
|  | EXPECT_TRUE(std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); | 
|  | } | 
|  |  | 
|  | } // namespace |