blob: 5cfdadd01ccbbc0d7a816f718c960da55d8d5be2 [file] [log] [blame]
/*
*
* Copyright (c) 2022 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 <app/icd/IcdMonitoringTable.h>
#include <lib/core/CHIPError.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/TestPersistentStorageDelegate.h>
#include <lib/support/UnitTestRegistration.h>
#include <nlunit-test.h>
using namespace chip;
namespace {
constexpr uint16_t kMaxTestClients1 = 2;
constexpr uint16_t kMaxTestClients2 = 1;
constexpr FabricIndex kTestFabricIndex1 = 1;
constexpr FabricIndex kTestFabricIndex2 = kMaxValidFabricIndex;
constexpr uint64_t kClientNodeId11 = 0x100001;
constexpr uint64_t kClientNodeId12 = 0x100002;
constexpr uint64_t kClientNodeId13 = 0x100003;
constexpr uint64_t kClientNodeId21 = 0x200001;
constexpr uint64_t kClientNodeId22 = 0x200002;
constexpr uint8_t kKeyBuffer0a[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
constexpr uint8_t kKeyBuffer0b[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
constexpr uint8_t kKeyBuffer1a[] = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};
constexpr uint8_t kKeyBuffer1b[] = {
0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81, 0x71, 0x61, 0x51, 0x14, 0x31, 0x21, 0x11, 0x01
};
constexpr uint8_t kKeyBuffer2a[] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
};
constexpr uint8_t kKeyBuffer2b[] = {
0xf2, 0xe2, 0xd2, 0xc2, 0xb2, 0xa2, 0x92, 0x82, 0x72, 0x62, 0x52, 0x42, 0x32, 0x22, 0x12, 0x02
};
constexpr uint8_t kKeyBuffer3a[] = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
};
// constexpr uint8_t kKeyBuffer3b[] = { 0xf3, 0xe3, 0xd3, 0xc3, 0xb3, 0xa3, 0x93, 0x83, 0x73, 0x63, 0x53, 0x14, 0x33, 0x23, 0x13,
// 0x03 };
void TestSaveAndLoadRegistrationValue(nlTestSuite * aSuite, void * aContext)
{
TestPersistentStorageDelegate storage;
IcdMonitoringTable saving(storage, kTestFabricIndex1, kMaxTestClients1);
IcdMonitoringTable loading(storage, kTestFabricIndex1, kMaxTestClients1);
IcdMonitoringEntry entry;
CHIP_ERROR err;
// Insert first entry
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan(kKeyBuffer1a);
err = saving.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert second entry
entry.checkInNodeID = kClientNodeId12;
entry.monitoredSubject = kClientNodeId11;
entry.key = ByteSpan(kKeyBuffer2a);
err = saving.Set(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert one too many
entry.checkInNodeID = kClientNodeId13;
entry.monitoredSubject = kClientNodeId13;
entry.key = ByteSpan(kKeyBuffer3a);
err = saving.Set(2, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
// Retrieve first entry
err = loading.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer1a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer1a, entry.key.size()));
// Retrieve second entry
err = loading.Get(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
// No more entries
err = loading.Get(2, entry);
NL_TEST_ASSERT(aSuite, 2 == loading.Limit());
NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err);
// Overwrite first entry
entry.checkInNodeID = kClientNodeId13;
entry.monitoredSubject = kClientNodeId11;
entry.key = ByteSpan(kKeyBuffer1b);
err = saving.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Retrieve first entry (modified)
err = loading.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId13 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer1b) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer1b, entry.key.size()));
// Retrieve second entry (not modified)
err = loading.Get(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
}
void TestSaveAllInvalidRegistrationValues(nlTestSuite * aSuite, void * aContext)
{
TestPersistentStorageDelegate storage;
IcdMonitoringTable table(storage, kTestFabricIndex1, kMaxTestClients1);
IcdMonitoringEntry entry;
CHIP_ERROR err;
// Invalid checkInNodeID
entry.checkInNodeID = kUndefinedNodeId;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan(kKeyBuffer1a);
err = table.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
// Invalid monitoredSubject
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kUndefinedNodeId;
entry.key = ByteSpan(kKeyBuffer1a);
err = table.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
// Invalid key (empty)
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan();
err = table.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
// Invalid key (too short)
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan(kKeyBuffer0a);
err = table.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
// Invalid key (too long)
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan(kKeyBuffer0b);
err = table.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
}
void TestSaveLoadRegistrationValueForMultipleFabrics(nlTestSuite * aSuite, void * aContext)
{
TestPersistentStorageDelegate storage;
IcdMonitoringTable table1(storage, kTestFabricIndex1, kMaxTestClients1);
IcdMonitoringTable table2(storage, kTestFabricIndex2, kMaxTestClients2);
IcdMonitoringEntry entry;
CHIP_ERROR err;
// Insert in first fabric
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan(kKeyBuffer1a);
err = table1.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert in first fabric
entry.checkInNodeID = kClientNodeId12;
entry.monitoredSubject = kClientNodeId11;
entry.key = ByteSpan(kKeyBuffer1b);
err = table1.Set(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert in second fabric
entry.checkInNodeID = kClientNodeId21;
entry.monitoredSubject = kClientNodeId22;
entry.key = ByteSpan(kKeyBuffer2a);
err = table2.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert in second fabric (one too many)
entry.checkInNodeID = kClientNodeId22;
entry.monitoredSubject = kClientNodeId21;
entry.key = ByteSpan(kKeyBuffer2b);
err = table2.Set(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err);
// Retrieve fabric1, first entry
err = table1.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer1a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer1a, entry.key.size()));
// Retrieve fabric2, second entry
err = table1.Get(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer1b) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer1b, entry.key.size()));
// Retrieve fabric2, first entry
err = table2.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex2 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId21 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId22 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
}
void TestDeleteValidEntryFromStorage(nlTestSuite * aSuite, void * context)
{
TestPersistentStorageDelegate storage;
IcdMonitoringTable table1(storage, kTestFabricIndex1, kMaxTestClients1);
IcdMonitoringTable table2(storage, kTestFabricIndex2, kMaxTestClients2);
IcdMonitoringEntry entry;
CHIP_ERROR err;
// Insert first entry
entry.checkInNodeID = kClientNodeId11;
entry.monitoredSubject = kClientNodeId12;
entry.key = ByteSpan(kKeyBuffer1a);
err = table1.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert second entry
entry.checkInNodeID = kClientNodeId12;
entry.monitoredSubject = kClientNodeId11;
entry.key = ByteSpan(kKeyBuffer2a);
err = table1.Set(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Insert in second fabric
entry.checkInNodeID = kClientNodeId21;
entry.monitoredSubject = kClientNodeId22;
entry.key = ByteSpan(kKeyBuffer2a);
err = table2.Set(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Remove (invalid)
err = table1.Remove(2);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR != err);
// Retrieve fabric1
err = table1.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer1a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer1a, entry.key.size()));
// Retrieve second entry (not modified)
err = table1.Get(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
// Remove (existing)
err = table1.Remove(0);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
// Retrieve second entry (shifted down)
err = table1.Get(1, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err);
err = table1.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
// Retrieve fabric2, first entry
err = table2.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex2 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId21 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId22 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
// Remove all (fabric 1)
err = table1.RemoveAll();
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
err = table1.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err);
// Check fabric 2
err = table2.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
NL_TEST_ASSERT(aSuite, kTestFabricIndex2 == entry.fabricIndex);
NL_TEST_ASSERT(aSuite, kClientNodeId21 == entry.checkInNodeID);
NL_TEST_ASSERT(aSuite, kClientNodeId22 == entry.monitoredSubject);
NL_TEST_ASSERT(aSuite, sizeof(kKeyBuffer2a) == entry.key.size());
NL_TEST_ASSERT(aSuite, 0 == memcmp(entry.key.data(), kKeyBuffer2a, entry.key.size()));
// Remove all (fabric 2)
err = table2.RemoveAll();
NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err);
err = table2.Get(0, entry);
NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err);
}
} // namespace
/**
* Set up the test suite.
*/
int Test_Setup(void * inContext)
{
return SUCCESS;
}
int TestClientMonitoringRegistrationTable()
{
static nlTest sTests[] = {
NL_TEST_DEF("TestSaveAndLoadRegistrationValue", TestSaveAndLoadRegistrationValue),
NL_TEST_DEF("TestSaveAllInvalidRegistrationValues", TestSaveAllInvalidRegistrationValues),
NL_TEST_DEF("TestSaveLoadRegistrationValueForMultipleFabrics", TestSaveLoadRegistrationValueForMultipleFabrics),
NL_TEST_DEF("TestDeleteValidEntryFromStorage", TestDeleteValidEntryFromStorage), NL_TEST_SENTINEL()
};
nlTestSuite cmSuite = { "TestClientMonitoringRegistrationTable", &sTests[0], &Test_Setup, nullptr };
nlTestRunner(&cmSuite, nullptr);
return (nlTestRunnerStats(&cmSuite));
}
CHIP_REGISTER_TEST_SUITE(TestClientMonitoringRegistrationTable)