diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 426e3c6865..82f2243c2a 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -586,8 +586,22 @@ void Server::GenerateShutDownEvent() PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().HandleServerShuttingDown(); }); } +void Server::PostFactoryResetEvent() +{ + DeviceLayer::ChipDeviceEvent event; + event.Type = DeviceLayer::DeviceEventType::kFactoryReset; + + CHIP_ERROR error = DeviceLayer::PlatformMgr().PostEvent(&event); + if (error != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Posting kFactoryReset event failed with %" CHIP_ERROR_FORMAT, error.Format()); + } +} + void Server::ScheduleFactoryReset() { + PostFactoryResetEvent(); + PlatformMgr().ScheduleWork([](intptr_t) { // Delete all fabrics and emit Leave event. GetInstance().GetFabricTable().DeleteAllFabrics(); diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 2f61197fce..2ebce83d0e 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -453,6 +453,8 @@ class Server void OnPlatformEvent(const DeviceLayer::ChipDeviceEvent & event); void CheckServerReadyEvent(); + void PostFactoryResetEvent(); + static void OnPlatformEventWrapper(const DeviceLayer::ChipDeviceEvent * event, intptr_t); #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 09dcb304ea..725558d833 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -216,6 +216,7 @@ chip_test_suite("tests") { "TestReadInteraction.cpp", "TestReportScheduler.cpp", "TestReportingEngine.cpp", + "TestServer.cpp", "TestStatusIB.cpp", "TestStatusResponseMessage.cpp", "TestTestEventTriggerDelegate.cpp", diff --git a/src/app/tests/TestServer.cpp b/src/app/tests/TestServer.cpp new file mode 100644 index 0000000000..a6caf36be5 --- /dev/null +++ b/src/app/tests/TestServer.cpp @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2025 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 { + +using namespace chip::DeviceLayer; + +namespace app { +namespace server { + +class TestServer : public ::testing::Test +{ +public: + static void SetUpTestSuite() + { + ASSERT_EQ(Platform::MemoryInit(), CHIP_NO_ERROR); + ASSERT_EQ(PlatformMgr().InitChipStack(), CHIP_NO_ERROR); + } + static void TearDownTestSuite() + { + Platform::MemoryShutdown(); + PlatformMgr().Shutdown(); + } +}; + +class TestEventHandler +{ +public: + ChipDeviceEvent mEvent{}; + + static void EventHandler(const ChipDeviceEvent * event, intptr_t arg) + { + reinterpret_cast(arg)->mEvent = *event; + } +}; + +TEST_F(TestServer, TestFactoryResetEvent) +{ + TestEventHandler handler; + PlatformMgr().AddEventHandler(TestEventHandler::EventHandler, reinterpret_cast(&handler)); + + Server::GetInstance().ScheduleFactoryReset(); + + PlatformMgr().ScheduleWork([](intptr_t) -> void { PlatformMgr().StopEventLoopTask(); }); + PlatformMgr().RunEventLoop(); + + EXPECT_EQ(handler.mEvent.Type, DeviceEventType::kFactoryReset); + + PlatformMgr().RemoveEventHandler(TestEventHandler::EventHandler, reinterpret_cast(&handler)); +} + +} // namespace server +} // namespace app +} // namespace chip diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index 09f4c46b65..df5958152e 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -255,6 +255,11 @@ enum PublicEventTypes * Signals that secure session is established. */ kSecureSessionEstablished, + + /** + * Signals that factory reset has started. + */ + kFactoryReset, }; /** diff --git a/src/platform/fake/PlatformManagerImpl.h b/src/platform/fake/PlatformManagerImpl.h index cf454d3c80..9651aee4ba 100644 --- a/src/platform/fake/PlatformManagerImpl.h +++ b/src/platform/fake/PlatformManagerImpl.h @@ -22,8 +22,10 @@ #pragma once -#include +#include +#include +#include #include namespace chip { @@ -44,11 +46,34 @@ class PlatformManagerImpl final : public PlatformManager private: // ===== Methods that implement the PlatformManager abstract interface. + struct EventHandler + { + PlatformManager::EventHandlerFunct Handler; + intptr_t Arg; + + bool operator==(const EventHandler & other) const { return Handler == other.Handler && Arg == other.Arg; } + }; + CHIP_ERROR _InitChipStack() { return CHIP_NO_ERROR; } void _Shutdown() {} - CHIP_ERROR _AddEventHandler(EventHandlerFunct handler, intptr_t arg = 0) { return CHIP_ERROR_NOT_IMPLEMENTED; } - void _RemoveEventHandler(EventHandlerFunct handler, intptr_t arg = 0) {} + CHIP_ERROR _AddEventHandler(EventHandlerFunct handler, intptr_t arg = 0) + { + EventHandler eventHandler = { .Handler = handler, .Arg = arg }; + if (std::find(mEventHandlers.begin(), mEventHandlers.end(), eventHandler) == mEventHandlers.end()) + { + mEventHandlers.push_back(eventHandler); + } + + return CHIP_NO_ERROR; + } + + void _RemoveEventHandler(EventHandlerFunct handler, intptr_t arg = 0) + { + EventHandler eventHandler = { .Handler = handler, .Arg = arg }; + mEventHandlers.remove(eventHandler); + } + void _HandleServerStarted() {} void _HandleServerShuttingDown() {} @@ -108,8 +133,26 @@ class PlatformManagerImpl final : public PlatformManager event->CallWorkFunct.WorkFunct(event->CallWorkFunct.Arg); break; - default: - break; + default: { +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + BLEMgr().OnPlatformEvent(event); +#endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + ThreadStackMgr().OnPlatformEvent(event); +#endif + ConnectivityMgr().OnPlatformEvent(event); + + if (!event->IsInternal()) + { + // iterate over local copy in case handler unregisters itself + auto handlers = mEventHandlers; + for (auto & handler : handlers) + { + handler.Handler(event, handler.Arg); + } + } + } + break; } } @@ -135,6 +178,7 @@ class PlatformManagerImpl final : public PlatformManager bool mShouldRunEventLoop = true; std::queue mQueue; + std::list mEventHandlers; }; /** diff --git a/src/test_driver/nrfconnect/prj.conf b/src/test_driver/nrfconnect/prj.conf index 97b7787fe9..fea8eee552 100644 --- a/src/test_driver/nrfconnect/prj.conf +++ b/src/test_driver/nrfconnect/prj.conf @@ -82,3 +82,7 @@ CONFIG_CHIP_ENABLE_READ_CLIENT=y CONFIG_CHIP_DEVICE_VENDOR_ID=65521 CONFIG_CHIP_DEVICE_PRODUCT_ID=32768 CONFIG_CHIP_PROJECT_CONFIG="main/include/CHIPProjectConfig.h" + +# Don't erase all settings as it deinitializes NVS/ZMS and causes issues with +# testing Server::ScheduleFactoryReset +CONFIG_CHIP_FACTORY_RESET_ERASE_SETTINGS=n