Skip to content

Commit 1069664

Browse files
mkardous-silabsbzbarsky-appleDamian-Nordic
authored andcommitted
[IC-Device] Initial implementation of Client Monitoring Registration table (#24096)
* Client Monitoring table implementation * CM table tests * Add sub-struct to add a validation function Add unit test for invalid values * Address PR comments * Apply suggestions from code review Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Increase max unit test limit * Apply suggestions from code review Co-authored-by: Damian Królik <66667989+Damian-Nordic@users.noreply.github.com> * Move comments to headeR * update test assert * Add provisional comment * restyle Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> Co-authored-by: Damian Królik <66667989+Damian-Nordic@users.noreply.github.com>
1 parent 4ff0e05 commit 1069664

7 files changed

+237
-48
lines changed

src/app/tests/BUILD.gn

+14
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ source_set("binding-test-srcs") {
5454
]
5555
}
5656

57+
source_set("client-monitoring-test-srcs") {
58+
sources = [
59+
"${chip_root}/src/app/util/ClientMonitoringRegistrationTable.cpp",
60+
"${chip_root}/src/app/util/ClientMonitoringRegistrationTable.h",
61+
]
62+
63+
public_deps = [
64+
"${chip_root}/src/app/common:cluster-objects",
65+
"${chip_root}/src/lib/core",
66+
]
67+
}
68+
5769
source_set("ota-requestor-test-srcs") {
5870
sources = [
5971
"${chip_root}/src/app/clusters/ota-requestor/DefaultOTARequestorStorage.cpp",
@@ -77,6 +89,7 @@ chip_test_suite("tests") {
7789
"TestAttributeValueEncoder.cpp",
7890
"TestBindingTable.cpp",
7991
"TestBuilderParser.cpp",
92+
"TestClientMonitoringRegistrationTable.cpp",
8093
"TestClusterInfo.cpp",
8194
"TestCommandInteraction.cpp",
8295
"TestCommandPathParams.cpp",
@@ -117,6 +130,7 @@ chip_test_suite("tests") {
117130

118131
public_deps = [
119132
":binding-test-srcs",
133+
":client-monitoring-test-srcs",
120134
":ota-requestor-test-srcs",
121135
"${chip_root}/src/app",
122136
"${chip_root}/src/app/common:cluster-objects",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
*
3+
* Copyright (c) 2022 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <app/util/ClientMonitoringRegistrationTable.h>
19+
#include <lib/core/CHIPError.h>
20+
#include <lib/support/DefaultStorageKeyAllocator.h>
21+
#include <lib/support/TestPersistentStorageDelegate.h>
22+
#include <lib/support/UnitTestRegistration.h>
23+
#include <nlunit-test.h>
24+
25+
using chip::ClientMonitoringRegistrationTable;
26+
using chip::NullOptional;
27+
28+
namespace {
29+
30+
constexpr chip::FabricIndex kTestFabricIndex = 1;
31+
constexpr uint64_t kTestICid = 10;
32+
constexpr chip::NodeId kTestClientNodeId = 11;
33+
34+
constexpr chip::FabricIndex kTestFabricIndex_2 = 2;
35+
constexpr uint64_t kTestICid_2 = 20;
36+
constexpr chip::NodeId kTestClientNodeId_2 = 21;
37+
38+
void TestDefaultClientValues(nlTestSuite * aSuite, void * aContext)
39+
{
40+
chip::TestPersistentStorageDelegate testStorage;
41+
ClientMonitoringRegistrationTable registration(testStorage);
42+
43+
NL_TEST_ASSERT(aSuite, !registration.GetClientRegistrationEntry().IsValid());
44+
NL_TEST_ASSERT(aSuite, registration.GetClientRegistrationEntry().clientNodeId == chip::kUndefinedFabricIndex);
45+
NL_TEST_ASSERT(aSuite, registration.GetClientRegistrationEntry().ICid == chip::kUndefinedNodeId);
46+
NL_TEST_ASSERT(aSuite, registration.GetClientRegistrationEntry().fabricIndex == chip::kInvalidIcId);
47+
}
48+
49+
void TestLoadFromStorageEmptyValue(nlTestSuite * aSuite, void * aContext)
50+
{
51+
chip::TestPersistentStorageDelegate testStorage;
52+
ClientMonitoringRegistrationTable registration(testStorage);
53+
54+
CHIP_ERROR err = registration.LoadFromStorage(kTestFabricIndex);
55+
NL_TEST_ASSERT(aSuite, err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
56+
}
57+
58+
void TestSaveAndLoadRegistrationValue(nlTestSuite * aSuite, void * aContext)
59+
{
60+
chip::TestPersistentStorageDelegate testStorage;
61+
ClientMonitoringRegistrationTable savedRegistration(testStorage);
62+
ClientMonitoringRegistrationTable loadedRegistration(testStorage);
63+
64+
savedRegistration.GetClientRegistrationEntry().clientNodeId = kTestClientNodeId;
65+
savedRegistration.GetClientRegistrationEntry().ICid = kTestICid;
66+
savedRegistration.GetClientRegistrationEntry().fabricIndex = kTestFabricIndex;
67+
68+
CHIP_ERROR err = savedRegistration.SaveToStorage();
69+
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
70+
71+
err = loadedRegistration.LoadFromStorage(kTestFabricIndex);
72+
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
73+
74+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().clientNodeId == kTestClientNodeId);
75+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().ICid == kTestICid);
76+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().fabricIndex == kTestFabricIndex);
77+
}
78+
79+
void TestSaveLoadRegistrationValueForMultipleFabrics(nlTestSuite * aSuite, void * aContexT)
80+
{
81+
chip::TestPersistentStorageDelegate testStorage;
82+
ClientMonitoringRegistrationTable savedRegistration(testStorage);
83+
ClientMonitoringRegistrationTable loadedRegistration(testStorage);
84+
85+
savedRegistration.GetClientRegistrationEntry().clientNodeId = kTestClientNodeId;
86+
savedRegistration.GetClientRegistrationEntry().ICid = kTestICid;
87+
savedRegistration.GetClientRegistrationEntry().fabricIndex = kTestFabricIndex;
88+
89+
CHIP_ERROR err = savedRegistration.SaveToStorage();
90+
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
91+
92+
savedRegistration.GetClientRegistrationEntry().clientNodeId = kTestClientNodeId_2;
93+
savedRegistration.GetClientRegistrationEntry().ICid = kTestICid_2;
94+
savedRegistration.GetClientRegistrationEntry().fabricIndex = kTestFabricIndex_2;
95+
96+
err = savedRegistration.SaveToStorage();
97+
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
98+
99+
err = loadedRegistration.LoadFromStorage(kTestFabricIndex);
100+
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
101+
102+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().clientNodeId == kTestClientNodeId);
103+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().ICid == kTestICid);
104+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().fabricIndex == kTestFabricIndex);
105+
106+
err = loadedRegistration.LoadFromStorage(kTestFabricIndex_2);
107+
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
108+
109+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().clientNodeId == kTestClientNodeId_2);
110+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().ICid == kTestICid_2);
111+
NL_TEST_ASSERT(aSuite, loadedRegistration.GetClientRegistrationEntry().fabricIndex == kTestFabricIndex_2);
112+
}
113+
114+
void TestSaveAllInvalidRegistrationValues(nlTestSuite * aSuite, void * context)
115+
{
116+
chip::TestPersistentStorageDelegate testStorage;
117+
ClientMonitoringRegistrationTable registration(testStorage);
118+
119+
CHIP_ERROR err = registration.SaveToStorage();
120+
NL_TEST_ASSERT(aSuite, err == CHIP_ERROR_INCORRECT_STATE);
121+
}
122+
123+
} // namespace
124+
125+
int TestClientMonitoringRegistrationTable()
126+
{
127+
static nlTest sTests[] = { NL_TEST_DEF("TestDefaultClientValues", TestDefaultClientValues),
128+
NL_TEST_DEF("TestLoadFromStorageEmptyValue", TestLoadFromStorageEmptyValue),
129+
NL_TEST_DEF("TestSaveAndLoadRegistrationValue", TestSaveAndLoadRegistrationValue),
130+
NL_TEST_DEF("TestSaveAllInvalidRegistrationValues", TestSaveAllInvalidRegistrationValues),
131+
NL_TEST_DEF("TestSaveLoadRegistrationValueForMultipleFabrics",
132+
TestSaveLoadRegistrationValueForMultipleFabrics),
133+
NL_TEST_SENTINEL() };
134+
135+
nlTestSuite cmSuite = { "TestClientMonitoringRegistrationTable", &sTests[0], nullptr, nullptr };
136+
137+
nlTestRunner(&cmSuite, nullptr);
138+
return (nlTestRunnerStats(&cmSuite));
139+
}
140+
141+
CHIP_REGISTER_TEST_SUITE(TestClientMonitoringRegistrationTable)

src/app/util/ClientMonitoringRegistrationTable.cpp

+28-34
Original file line numberDiff line numberDiff line change
@@ -17,59 +17,53 @@
1717

1818
#include "ClientMonitoringRegistrationTable.h"
1919

20-
namespace chip {
20+
#include <lib/support/DefaultStorageKeyAllocator.h>
2121

22-
/**********************************************************
23-
* Attributes Definition
24-
*********************************************************/
22+
namespace chip {
2523

2624
/**********************************************************
2725
* ClientMonitoringRegistrationTable Implementation
2826
*********************************************************/
2927

30-
ClientMonitoringRegistrationTable::ClientMonitoringRegistrationTable(FabricIndex fabricIndex)
31-
{
32-
this->LoadFromStorage(fabricIndex);
33-
}
28+
ClientMonitoringRegistrationTable::ClientMonitoringRegistrationTable(PersistentStorageDelegate & storage) : mStorage(storage) {}
3429

35-
void ClientMonitoringRegistrationTable::LoadFromStorage(FabricIndex fabricIndex)
30+
CHIP_ERROR ClientMonitoringRegistrationTable::LoadFromStorage(FabricIndex fabricIndex)
3631
{
37-
// TODO: Implement load from NVM logic
38-
}
32+
uint8_t buffer[kRegStorageSize] = { 0 };
33+
uint16_t size = sizeof(buffer);
3934

40-
void ClientMonitoringRegistrationTable::SaveToStorage()
41-
{
42-
// Store to NVM based of class attributes
43-
}
35+
ReturnErrorOnFailure(
36+
mStorage.SyncGetKeyValue(DefaultStorageKeyAllocator::ClientMonitoringTableEntry(fabricIndex).KeyName(), buffer, size));
4437

45-
NodeId ClientMonitoringRegistrationTable::getClientNodeId()
46-
{
47-
return mRegisteredClient.clientNodeId;
48-
}
38+
TLV::TLVReader reader;
39+
reader.Init(buffer, size);
40+
ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
4941

50-
uint64_t ClientMonitoringRegistrationTable::getICid()
51-
{
52-
return mRegisteredClient.ICid;
53-
}
42+
ReturnErrorOnFailure(mRegisteredClient.Decode(reader));
5443

55-
FabricIndex ClientMonitoringRegistrationTable::getFaricIndex()
56-
{
57-
return mRegisteredClient.fabricIndex;
58-
}
44+
mRegisteredClient.fabricIndex = fabricIndex;
5945

60-
void ClientMonitoringRegistrationTable::setClientNodeId(NodeId clientNodeId)
61-
{
62-
mRegisteredClient.clientNodeId = clientNodeId;
46+
return CHIP_NO_ERROR;
6347
}
6448

65-
void ClientMonitoringRegistrationTable::setICid(uint64_t ICid)
49+
CHIP_ERROR ClientMonitoringRegistrationTable::SaveToStorage()
6650
{
67-
mRegisteredClient.ICid = ICid;
51+
VerifyOrReturnError(mRegisteredClient.IsValid(), CHIP_ERROR_INCORRECT_STATE);
52+
53+
uint8_t buffer[kRegStorageSize] = { 0 };
54+
TLV::TLVWriter writer;
55+
56+
writer.Init(buffer);
57+
ReturnErrorOnFailure(mRegisteredClient.EncodeForWrite(writer, TLV::AnonymousTag()));
58+
ReturnErrorOnFailure(writer.Finalize());
59+
60+
return mStorage.SyncSetKeyValue(DefaultStorageKeyAllocator::ClientMonitoringTableEntry(mRegisteredClient.fabricIndex).KeyName(),
61+
buffer, static_cast<uint16_t>(writer.GetLengthWritten()));
6862
}
6963

70-
void ClientMonitoringRegistrationTable::setFabricIndex(FabricIndex fabric)
64+
ClientMonitoringRegistrationTable::ClientRegistrationEntry & ClientMonitoringRegistrationTable::GetClientRegistrationEntry()
7165
{
72-
mRegisteredClient.fabricIndex = fabric;
66+
return mRegisteredClient;
7367
}
7468

7569
} // namespace chip

src/app/util/ClientMonitoringRegistrationTable.h

+42-13
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,62 @@
1919

2020
#include <app-common/zap-generated/cluster-objects.h>
2121
#include <lib/core/CHIPConfig.h>
22+
#include <lib/core/CHIPPersistentStorageDelegate.h>
23+
#include <lib/core/DataModelTypes.h>
2224
#include <lib/support/CodeUtils.h>
23-
#include <platform/CHIPDeviceConfig.h>
2425

2526
namespace chip {
27+
28+
/**
29+
* @brief ClientMonitoringRegistrationTable exists to manage the persistence of entries in the ClientMonitoring Cluster.
30+
* To access persisted data with the ClientMonitoringRegistrationTable class, instantiate an instance of this class
31+
* and call the LoadFromStorage function.
32+
*
33+
* This class can only manage one fabric at a time. The flow is load a fabric, execute necessary operations,
34+
* save it if there are any changes and load another fabric.
35+
*/
2636
class ClientMonitoringRegistrationTable
2737
{
2838
public:
2939
using MonitoringRegistrationStruct = chip::app::Clusters::ClientMonitoring::Structs::MonitoringRegistration::Type;
3040

31-
ClientMonitoringRegistrationTable(FabricIndex fabricIndex);
41+
struct ClientRegistrationEntry : MonitoringRegistrationStruct
42+
{
43+
bool IsValid() { return clientNodeId != kUndefinedNodeId && ICid != kInvalidIcId && fabricIndex != kUndefinedFabricIndex; }
44+
};
45+
46+
ClientMonitoringRegistrationTable(PersistentStorageDelegate & storage);
3247
~ClientMonitoringRegistrationTable(){};
3348

34-
void SaveToStorage();
49+
/**
50+
* @brief Function saves the mRegisteredClient attribute to persitant storage
51+
* To correctly persit an entry, the values must be stored in the structures attributes
52+
*
53+
* @return CHIP_ERROR
54+
*/
55+
CHIP_ERROR SaveToStorage();
3556

36-
// Getter
37-
NodeId getClientNodeId();
38-
uint64_t getICid();
39-
FabricIndex getFaricIndex();
57+
/**
58+
* @brief Function loads a client registration entry from persistent storage for a single fabric
59+
*
60+
* @param[in] fabricIndex fabric index to load from storage
61+
* @return CHIP_ERROR
62+
*/
63+
CHIP_ERROR LoadFromStorage(FabricIndex fabricIndex);
4064

41-
// Setter
42-
void setClientNodeId(NodeId clientNodeId);
43-
void setICid(uint64_t ICid);
44-
void setFabricIndex(FabricIndex fabric);
65+
/**
66+
* @brief Accessor function that returns the client registration entry that was loaded for a fabric from persistant storage.
67+
* @see LoadFromStorage
68+
*
69+
* @return ClientMonitoringRegistrationTable::ClientRegistrationEntry&
70+
*/
71+
ClientRegistrationEntry & GetClientRegistrationEntry();
4572

4673
private:
47-
void LoadFromStorage(FabricIndex fabricIndex);
48-
MonitoringRegistrationStruct mRegisteredClient;
74+
static constexpr uint8_t kRegStorageSize = TLV::EstimateStructOverhead(sizeof(NodeId), sizeof(uint64_t));
75+
76+
ClientRegistrationEntry mRegisteredClient;
77+
PersistentStorageDelegate & mStorage;
4978
};
5079

5180
} // namespace chip

src/lib/core/DataModelTypes.h

+4
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ constexpr EndpointId kRootEndpointId = 0;
5858
constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus 0xFFFF is a invalid list index.
5959
constexpr KeysetId kInvalidKeysetId = 0xFFFF;
6060

61+
// Invalid IC identifier is provisional. Value will most likely change when identifying token is defined
62+
// https://github.com/project-chip/connectedhomeip/issues/24251
63+
constexpr uint64_t kInvalidIcId = 0;
64+
6165
// These are MEIs, 0xFFFF is not a valid manufacturer code,
6266
// thus 0xFFFF'FFFF is not a valid MEI.
6367
static constexpr ClusterId kInvalidClusterId = 0xFFFF'FFFF;

src/lib/support/DefaultStorageKeyAllocator.h

+7
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,13 @@ class DefaultStorageKeyAllocator
175175
static StorageKeyName BindingTable() { return StorageKeyName::FromConst("g/bt"); }
176176
static StorageKeyName BindingTableEntry(uint8_t index) { return StorageKeyName::Formatted("g/bt/%x", index); }
177177

178+
// Client Monitoring
179+
180+
static StorageKeyName ClientMonitoringTableEntry(chip::FabricIndex fabric)
181+
{
182+
return StorageKeyName::Formatted("f/%x/cm", fabric);
183+
}
184+
178185
static StorageKeyName OTADefaultProviders() { return StorageKeyName::FromConst("g/o/dp"); }
179186
static StorageKeyName OTACurrentProvider() { return StorageKeyName::FromConst("g/o/cp"); }
180187
static StorageKeyName OTAUpdateToken() { return StorageKeyName::FromConst("g/o/ut"); }

src/lib/support/UnitTestRegistration.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
namespace chip {
2424

25-
const size_t kTestSuitesMax = 128;
25+
const size_t kTestSuitesMax = 256;
2626

2727
typedef struct
2828
{

0 commit comments

Comments
 (0)