Skip to content

Commit 653fd79

Browse files
andy31415bzbarsky-appleCopilot
authored
[ServerClusterIntrerfaceRegistry] Add consistent behavior on startup failures (project-chip#41924)
* Add consistent behavior on register failures in server cluster interface registry. * Fix typo and add comment. * Update src/app/server-cluster/tests/TestServerClusterInterfaceRegistry.cpp Co-authored-by: Boris Zbarsky <[email protected]> * Add some documentation on error codes from SetContext. * Update src/app/server-cluster/tests/TestServerClusterInterfaceRegistry.cpp Co-authored-by: Copilot <[email protected]> * Update src/app/server-cluster/ServerClusterInterfaceRegistry.cpp Co-authored-by: Copilot <[email protected]> * Update src/app/server-cluster/tests/TestServerClusterInterfaceRegistry.cpp Co-authored-by: Copilot <[email protected]> * Update src/app/server-cluster/ServerClusterInterfaceRegistry.cpp Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Boris Zbarsky <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent c561ace commit 653fd79

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

src/app/server-cluster/ServerClusterInterfaceRegistry.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ CHIP_ERROR ServerClusterInterfaceRegistry::Register(ServerClusterRegistration &
6262

6363
if (mContext.has_value())
6464
{
65-
ReturnErrorOnFailure(entry.serverClusterInterface->Startup(*mContext));
65+
// To preserve similarity with SetContext, do not fail the register even if Startup fails.
66+
// This will cause Shutdown to be called for both successful and failed startups.
67+
LogErrorOnFailure(entry.serverClusterInterface->Startup(*mContext));
6668
}
6769

6870
entry.next = mRegistrations;

src/app/server-cluster/ServerClusterInterfaceRegistry.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ class ServerClusterInterfaceRegistry
155155
// Set up the underlying context for all clusters that are managed by this registry.
156156
//
157157
// The values within context will be moved and used as-is.
158+
//
159+
// Returns:
160+
// - CHIP_NO_ERROR on success
161+
// - CHIP_ERROR_HAD_FAILURES if some cluster `Startup` calls had errors (Startup
162+
// will be called for all clusters).
158163
CHIP_ERROR SetContext(ServerClusterContext && context);
159164

160165
// Invalidates current context.

src/app/server-cluster/tests/TestServerClusterInterfaceRegistry.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,34 @@ class MultiPathCluster : public DefaultServerCluster
8686
Span<const ConcreteClusterPath> mActualPaths;
8787
};
8888

89+
class FailingStartupCluster : public DefaultServerCluster
90+
{
91+
public:
92+
FailingStartupCluster(const ConcreteClusterPath & path) : DefaultServerCluster(path) {}
93+
FailingStartupCluster(EndpointId endpoint, ClusterId cluster) : DefaultServerCluster({ endpoint, cluster }) {}
94+
95+
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
96+
AttributeValueEncoder & encoder) override
97+
{
98+
return CHIP_ERROR_NOT_IMPLEMENTED;
99+
}
100+
101+
CHIP_ERROR Startup(ServerClusterContext & context) override
102+
{
103+
DefaultServerCluster::Startup(context);
104+
mStartupCalls++;
105+
return CHIP_ERROR_CANCELLED;
106+
}
107+
void Shutdown() override { mShutdownCalls++; }
108+
109+
uint32_t GetStartupCallCount() const { return mStartupCalls; }
110+
uint32_t GetShutdownCallCount() const { return mShutdownCalls; }
111+
112+
private:
113+
uint32_t mStartupCalls = 0;
114+
uint32_t mShutdownCalls = 0;
115+
};
116+
89117
struct TestServerClusterInterfaceRegistry : public ::testing::Test
90118
{
91119
static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); }
@@ -322,3 +350,53 @@ TEST_F(TestServerClusterInterfaceRegistry, UnregisterErrors)
322350
// Can't unregister a null cluster.
323351
EXPECT_EQ(registry.Unregister(nullptr), CHIP_ERROR_NOT_FOUND);
324352
}
353+
354+
TEST_F(TestServerClusterInterfaceRegistry, StartupShutdownWithoutContext)
355+
{
356+
// register before the context
357+
RegisteredServerCluster<FailingStartupCluster> cluster1(kEp1, kCluster1);
358+
RegisteredServerCluster<FailingStartupCluster> cluster2(kEp1, kCluster2);
359+
RegisteredServerCluster<FailingStartupCluster> cluster3(kEp2, kCluster1);
360+
361+
{
362+
ServerClusterInterfaceRegistry registry;
363+
364+
// all registrations are ok
365+
EXPECT_EQ(registry.Register(cluster1.Registration()), CHIP_NO_ERROR);
366+
EXPECT_EQ(registry.Register(cluster2.Registration()), CHIP_NO_ERROR);
367+
368+
// startup was NOT called (no context yet)
369+
EXPECT_EQ(cluster1.Cluster().GetStartupCallCount(), 0u);
370+
EXPECT_EQ(cluster2.Cluster().GetStartupCallCount(), 0u);
371+
372+
TestServerClusterContext context;
373+
374+
// the clusters are explicitly set to fail startup, so SetContext returns an error.
375+
// TODO: is this sane? Register() with a startup failure does NOT return a failure.
376+
EXPECT_EQ(registry.SetContext(context.Create()), CHIP_ERROR_HAD_FAILURES);
377+
378+
// Startup called after registration, with failure that is NOT reported (only logged)
379+
EXPECT_EQ(cluster3.Cluster().GetStartupCallCount(), 0u);
380+
EXPECT_EQ(registry.Register(cluster3.Registration()), CHIP_NO_ERROR);
381+
382+
// all startups were called, even though there was an error
383+
EXPECT_EQ(cluster1.Cluster().GetStartupCallCount(), 1u);
384+
EXPECT_EQ(cluster2.Cluster().GetStartupCallCount(), 1u);
385+
EXPECT_EQ(cluster3.Cluster().GetStartupCallCount(), 1u);
386+
EXPECT_EQ(cluster1.Cluster().GetShutdownCallCount(), 0u);
387+
EXPECT_EQ(cluster2.Cluster().GetShutdownCallCount(), 0u);
388+
EXPECT_EQ(cluster3.Cluster().GetShutdownCallCount(), 0u);
389+
390+
// unregister will call shutdown
391+
EXPECT_EQ(registry.Unregister(&cluster2.Cluster()), CHIP_NO_ERROR);
392+
EXPECT_EQ(cluster2.Cluster().GetShutdownCallCount(), 1u);
393+
}
394+
395+
// registry deletion will call shutdown for the rest
396+
EXPECT_EQ(cluster1.Cluster().GetStartupCallCount(), 1u);
397+
EXPECT_EQ(cluster2.Cluster().GetStartupCallCount(), 1u);
398+
EXPECT_EQ(cluster3.Cluster().GetStartupCallCount(), 1u);
399+
EXPECT_EQ(cluster1.Cluster().GetShutdownCallCount(), 1u);
400+
EXPECT_EQ(cluster2.Cluster().GetShutdownCallCount(), 1u);
401+
EXPECT_EQ(cluster3.Cluster().GetShutdownCallCount(), 1u);
402+
}

0 commit comments

Comments
 (0)