Skip to content

Commit

Permalink
address comments and add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
yunhanw-google committed Oct 12, 2024
1 parent 512f5c8 commit 7334a09
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 9 deletions.
4 changes: 4 additions & 0 deletions src/app/icd/client/CheckInHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ CHIP_ERROR CheckInHandler::Init(Messaging::ExchangeManager * exchangeManager, IC
{
VerifyOrReturnError(exchangeManager != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(clientStorage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(mpExchangeManager == nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mpICDClientStorage == nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mpCheckInDelegate == nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mpImEngine == nullptr, CHIP_ERROR_INCORRECT_STATE);

mpExchangeManager = exchangeManager;
mpICDClientStorage = clientStorage;
Expand Down
8 changes: 4 additions & 4 deletions src/app/icd/client/DefaultICDClientStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ CHIP_ERROR DefaultICDClientStorage::SerializeToTlv(TLV::TLVWriter & writer, cons
return writer.EndContainer(arrayType);
}

bool DefaultICDClientStorage::CheckFabricExistence(FabricIndex fabricIndex)
bool DefaultICDClientStorage::FabricExists(FabricIndex fabricIndex)
{
for (auto & fabric_idx : mFabricList)
{
Expand All @@ -364,7 +364,7 @@ bool DefaultICDClientStorage::CheckFabricExistence(FabricIndex fabricIndex)

CHIP_ERROR DefaultICDClientStorage::StoreEntry(const ICDClientInfo & clientInfo)
{
VerifyOrReturnError(CheckFabricExistence(clientInfo.peer_node.GetFabricIndex()), CHIP_ERROR_INVALID_FABRIC_INDEX);
VerifyOrReturnError(FabricExists(clientInfo.peer_node.GetFabricIndex()), CHIP_ERROR_INVALID_FABRIC_INDEX);
std::vector<ICDClientInfo> clientInfoVector;
size_t clientInfoSize = MaxICDClientInfoSize();
ReturnErrorOnFailure(Load(clientInfo.peer_node.GetFabricIndex(), clientInfoVector, clientInfoSize));
Expand Down Expand Up @@ -442,7 +442,7 @@ CHIP_ERROR DefaultICDClientStorage::UpdateEntryCountForFabric(FabricIndex fabric

CHIP_ERROR DefaultICDClientStorage::DeleteEntry(const ScopedNodeId & peerNode)
{
VerifyOrReturnError(CheckFabricExistence(peerNode.GetFabricIndex()), CHIP_NO_ERROR);
VerifyOrReturnError(FabricExists(peerNode.GetFabricIndex()), CHIP_NO_ERROR);
size_t clientInfoSize = 0;
std::vector<ICDClientInfo> clientInfoVector;
ReturnErrorOnFailure(Load(peerNode.GetFabricIndex(), clientInfoVector, clientInfoSize));
Expand Down Expand Up @@ -480,7 +480,7 @@ CHIP_ERROR DefaultICDClientStorage::DeleteEntry(const ScopedNodeId & peerNode)

CHIP_ERROR DefaultICDClientStorage::DeleteAllEntries(FabricIndex fabricIndex)
{
VerifyOrReturnError(CheckFabricExistence(fabricIndex), CHIP_NO_ERROR);
VerifyOrReturnError(FabricExists(fabricIndex), CHIP_NO_ERROR);

size_t clientInfoSize = 0;
std::vector<ICDClientInfo> clientInfoVector;
Expand Down
2 changes: 1 addition & 1 deletion src/app/icd/client/DefaultICDClientStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class DefaultICDClientStorage : public ICDClientStorage
CHIP_ERROR LoadFabricList();
CHIP_ERROR LoadCounter(FabricIndex fabricIndex, size_t & count, size_t & clientInfoSize);

bool CheckFabricExistence(FabricIndex fabricIndex);
bool FabricExists(FabricIndex fabricIndex);

CHIP_ERROR IncreaseEntryCountForFabric(FabricIndex fabricIndex);
CHIP_ERROR DecreaseEntryCountForFabric(FabricIndex fabricIndex);
Expand Down
2 changes: 2 additions & 0 deletions src/app/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ chip_test_suite("tests") {
"TestBasicCommandPathRegistry.cpp",
"TestBindingTable.cpp",
"TestBuilderParser.cpp",
"TestCheckInHandler.cpp",
"TestCommandHandlerInterfaceRegistry.cpp",
"TestCommandInteraction.cpp",
"TestCommandPathParams.cpp",
Expand Down Expand Up @@ -251,6 +252,7 @@ chip_test_suite("tests") {
"${chip_root}/src/app/codegen-data-model-provider:instance-header",
"${chip_root}/src/app/common:cluster-objects",
"${chip_root}/src/app/data-model-provider/tests:encode-decode",
"${chip_root}/src/app/icd/client:handler",
"${chip_root}/src/app/icd/client:manager",
"${chip_root}/src/app/tests:helpers",
"${chip_root}/src/app/util/mock:mock_codegen_data_model",
Expand Down
274 changes: 274 additions & 0 deletions src/app/tests/TestCheckInHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
/*
* Copyright (c) 2024 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 <app/InteractionModelEngine.h>
#include <app/icd/client/CheckInHandler.h>
#include <app/icd/client/DefaultCheckInDelegate.h>
#include <app/icd/client/DefaultICDClientStorage.h>
#include <app/reporting/tests/MockReportScheduler.h>
#include <app/tests/AppTestContext.h>
#include <crypto/DefaultSessionKeystore.h>
#include <lib/core/StringBuilderAdapters.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/Span.h>
#include <lib/support/TestPersistentStorageDelegate.h>
#include <protocols/secure_channel/CheckinMessage.h>
#include <pw_unit_test/framework.h>
#include <system/SystemPacketBuffer.h>
#include <transport/SessionManager.h>

using namespace chip;
using namespace app;
using namespace System;
using TestSessionKeystoreImpl = Crypto::DefaultSessionKeystore;

constexpr uint8_t kKeyBuffer1[] = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};

constexpr uint8_t kKeyBuffer2[] = {
0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81, 0x71, 0x61, 0x51, 0x14, 0x31, 0x21, 0x11, 0x01
};

class TestCheckInHandler : public chip::Test::AppContext
{
};

class CheckInHandlerWrapper : public chip::app::CheckInHandler
{
public:
CHIP_ERROR ValidateOnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
System::PacketBufferHandle && payload)
{
return OnMessageReceived(ec, payloadHeader, std::move(payload));
}
};

TEST_F(TestCheckInHandler, TestOnMessageReceived)
{
InteractionModelEngine * engine = InteractionModelEngine::GetInstance();
EXPECT_EQ(engine->Init(&GetExchangeManager(), &GetFabricTable(), app::reporting::GetDefaultReportScheduler()), CHIP_NO_ERROR);
TestPersistentStorageDelegate clientInfoStorage;
TestSessionKeystoreImpl keystore;

DefaultICDClientStorage manager;
EXPECT_EQ(manager.Init(&clientInfoStorage, &keystore), CHIP_NO_ERROR);

DefaultCheckInDelegate checkInDelegate;
EXPECT_EQ(checkInDelegate.Init(&manager, engine), CHIP_NO_ERROR);

CheckInHandlerWrapper checkInHandler;
EXPECT_EQ(checkInHandler.Init(&GetExchangeManager(), &manager, &checkInDelegate, engine), CHIP_NO_ERROR);

FabricIndex fabricIdA = 1;
NodeId nodeIdA = 6666;

ICDClientInfo clientInfoA;
clientInfoA.peer_node = ScopedNodeId(nodeIdA, fabricIdA);
clientInfoA.start_icd_counter = 0;
clientInfoA.offset = 0;
EXPECT_EQ(manager.UpdateFabricList(fabricIdA), CHIP_NO_ERROR);
EXPECT_EQ(manager.SetKey(clientInfoA, ByteSpan(kKeyBuffer1)), CHIP_NO_ERROR);
EXPECT_EQ(manager.StoreEntry(clientInfoA), CHIP_NO_ERROR);

FabricIndex fabricIdB = 2;
NodeId nodeIdB = 6667;

ICDClientInfo clientInfoB;
clientInfoB.peer_node = ScopedNodeId(nodeIdB, fabricIdB);
clientInfoB.offset = 0;
EXPECT_EQ(manager.UpdateFabricList(fabricIdB), CHIP_NO_ERROR);
EXPECT_EQ(manager.SetKey(clientInfoB, ByteSpan(kKeyBuffer2)), CHIP_NO_ERROR);
EXPECT_EQ(manager.StoreEntry(clientInfoB), CHIP_NO_ERROR);

PayloadHeader payloadHeader;
payloadHeader.SetExchangeID(0);
payloadHeader.SetMessageType(chip::Protocols::SecureChannel::MsgType::ICD_CheckIn);

uint32_t counter = 1;
System::PacketBufferHandle buffer1 = MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output1{ buffer1->Start(), buffer1->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoA.aes_key_handle, clientInfoA.hmac_key_handle, counter, ByteSpan(), output1),
CHIP_NO_ERROR);

buffer1->SetDataLength(static_cast<uint16_t>(output1.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer1)), CHIP_NO_ERROR);

ICDClientInfo clientInfo1;
auto * iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
while (iterator->Next(clientInfo1))
{
if (clientInfo1.peer_node.GetNodeId() == nodeIdA && clientInfo1.peer_node.GetFabricIndex() == fabricIdA)
{
break;
}
}
iterator->Release();

EXPECT_EQ(clientInfo1.offset, counter - clientInfoA.start_icd_counter);

// Validate duplicate check-in message handling
chip::System::PacketBufferHandle buffer2 =
MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output2{ buffer2->Start(), buffer2->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoA.aes_key_handle, clientInfoA.hmac_key_handle, counter, ByteSpan(), output2),
CHIP_NO_ERROR);

buffer2->SetDataLength(static_cast<uint16_t>(output2.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer2)), CHIP_NO_ERROR);

ICDClientInfo clientInfo2;
iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
while (iterator->Next(clientInfo2))
{
if (clientInfo2.peer_node.GetNodeId() == nodeIdA && clientInfo2.peer_node.GetFabricIndex() == fabricIdA)
{
break;
}
}
iterator->Release();
EXPECT_EQ(clientInfo2.offset, counter - clientInfoA.start_icd_counter);

// Validate second check-in message with increased counter
counter++;
System::PacketBufferHandle buffer3 = MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output3{ buffer3->Start(), buffer3->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoA.aes_key_handle, clientInfoA.hmac_key_handle, counter, ByteSpan(), output3),
CHIP_NO_ERROR);
buffer3->SetDataLength(static_cast<uint16_t>(output3.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer3)), CHIP_NO_ERROR);
ICDClientInfo clientInfo3;
iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
while (iterator->Next(clientInfo3))
{
if (clientInfo3.peer_node.GetNodeId() == nodeIdA && clientInfo3.peer_node.GetFabricIndex() == fabricIdA)
{
break;
}
}
iterator->Release();
EXPECT_EQ(clientInfo3.offset, counter - clientInfoA.start_icd_counter);

// Validate check-in message from fabricB
counter++;
System::PacketBufferHandle buffer4 = MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output4{ buffer4->Start(), buffer4->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoB.aes_key_handle, clientInfoB.hmac_key_handle, counter, ByteSpan(), output4),
CHIP_NO_ERROR);
buffer4->SetDataLength(static_cast<uint16_t>(output4.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer4)), CHIP_NO_ERROR);
ICDClientInfo clientInfo4;
iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
while (iterator->Next(clientInfo4))
{
if (clientInfo4.peer_node.GetNodeId() == nodeIdB && clientInfo4.peer_node.GetFabricIndex() == fabricIdB)
{
break;
}
}
iterator->Release();
EXPECT_EQ(clientInfo4.offset, counter - clientInfoB.start_icd_counter);

// Validate check-in message from removed fabricB
counter++;
System::PacketBufferHandle buffer5 = MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output5{ buffer5->Start(), buffer5->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoB.aes_key_handle, clientInfoB.hmac_key_handle, counter, ByteSpan(), output5),
CHIP_NO_ERROR);

EXPECT_EQ(manager.DeleteAllEntries(fabricIdB), CHIP_NO_ERROR);
buffer5->SetDataLength(static_cast<uint16_t>(output5.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer5)), CHIP_NO_ERROR);
ICDClientInfo clientInfo5;
iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
bool located = false;
while (iterator->Next(clientInfo5))
{
if (clientInfo5.peer_node.GetFabricIndex() == fabricIdB)
{
located = true;
break;
}
}
iterator->Release();
EXPECT_FALSE(located);

// Add back fabricB and validate check-in message again
EXPECT_EQ(manager.UpdateFabricList(fabricIdB), CHIP_NO_ERROR);
EXPECT_EQ(manager.SetKey(clientInfoB, ByteSpan(kKeyBuffer2)), CHIP_NO_ERROR);
EXPECT_EQ(manager.StoreEntry(clientInfoB), CHIP_NO_ERROR);
counter++;
System::PacketBufferHandle buffer6 = MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output6{ buffer6->Start(), buffer6->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoB.aes_key_handle, clientInfoB.hmac_key_handle, counter, ByteSpan(), output6),
CHIP_NO_ERROR);
buffer6->SetDataLength(static_cast<uint16_t>(output4.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer6)), CHIP_NO_ERROR);
ICDClientInfo clientInfo6;
iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
while (iterator->Next(clientInfo6))
{
if (clientInfo6.peer_node.GetNodeId() == nodeIdB && clientInfo6.peer_node.GetFabricIndex() == fabricIdB)
{
break;
}
}
iterator->Release();
EXPECT_EQ(clientInfo6.offset, counter - clientInfoB.start_icd_counter);

// Clear fabric table
EXPECT_EQ(manager.DeleteAllEntries(fabricIdA), CHIP_NO_ERROR);
EXPECT_EQ(manager.DeleteAllEntries(fabricIdB), CHIP_NO_ERROR);
// Add back fabricA and validate check-in message again
EXPECT_EQ(manager.UpdateFabricList(fabricIdA), CHIP_NO_ERROR);
EXPECT_EQ(manager.SetKey(clientInfoA, ByteSpan(kKeyBuffer1)), CHIP_NO_ERROR);
EXPECT_EQ(manager.StoreEntry(clientInfoA), CHIP_NO_ERROR);
counter++;
System::PacketBufferHandle buffer7 = MessagePacketBuffer::New(chip::Protocols::SecureChannel::CheckinMessage::kMinPayloadSize);
MutableByteSpan output7{ buffer7->Start(), buffer7->MaxDataLength() };
EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
clientInfoA.aes_key_handle, clientInfoA.hmac_key_handle, counter, ByteSpan(), output7),
CHIP_NO_ERROR);
buffer7->SetDataLength(static_cast<uint16_t>(output7.size()));
EXPECT_EQ(checkInHandler.ValidateOnMessageReceived(nullptr, payloadHeader, std::move(buffer7)), CHIP_NO_ERROR);
ICDClientInfo clientInfo7;
iterator = manager.IterateICDClientInfo();
ASSERT_NE(iterator, nullptr);
while (iterator->Next(clientInfo7))
{
if (clientInfo7.peer_node.GetNodeId() == nodeIdA && clientInfo7.peer_node.GetFabricIndex() == fabricIdA)
{
break;
}
}
iterator->Release();
EXPECT_EQ(clientInfo7.offset, counter - clientInfoA.start_icd_counter);

checkInHandler.Shutdown();
}
8 changes: 4 additions & 4 deletions src/app/tests/TestDefaultICDClientStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ TEST_F(TestDefaultICDClientStorage, TestProcessCheckInPayload)
uint32_t checkInCounter = 0;
ByteSpan payload{ buffer->Start(), buffer->DataLength() };
EXPECT_EQ(manager.ProcessCheckInPayload(payload, decodeClientInfo, checkInCounter), CHIP_NO_ERROR);
EXPECT_EQ(checkInCounter, 1u);
EXPECT_EQ(checkInCounter, counter);

// Validate second check-in message with increased counter
counter++;
Expand All @@ -300,7 +300,7 @@ TEST_F(TestDefaultICDClientStorage, TestProcessCheckInPayload)
buffer->SetDataLength(static_cast<uint16_t>(output.size()));
ByteSpan payload1{ buffer->Start(), buffer->DataLength() };
EXPECT_EQ(manager.ProcessCheckInPayload(payload1, decodeClientInfo, checkInCounter), CHIP_NO_ERROR);
EXPECT_EQ(checkInCounter, 2u);
EXPECT_EQ(checkInCounter, counter);

// Use a key not available in the storage for encoding
EXPECT_EQ(manager.SetKey(clientInfo, ByteSpan(kKeyBuffer2)), CHIP_NO_ERROR);
Expand Down Expand Up @@ -342,7 +342,7 @@ TEST_F(TestDefaultICDClientStorage, TestProcessCheckInPayloadWithRemovedKey)
uint32_t checkInCounter = 0;
ByteSpan payload{ buffer->Start(), buffer->DataLength() };
EXPECT_EQ(manager.ProcessCheckInPayload(payload, decodeClientInfo, checkInCounter), CHIP_NO_ERROR);
EXPECT_EQ(checkInCounter, 1u);
EXPECT_EQ(checkInCounter, counter);

// Use a removed key in the storage for encoding
manager.RemoveKey(clientInfo), CHIP_NO_ERROR;
Expand Down Expand Up @@ -384,7 +384,7 @@ TEST_F(TestDefaultICDClientStorage, TestProcessCheckInPayloadWithEmptyIcdStorage
uint32_t checkInCounter = 0;
ByteSpan payload{ buffer->Start(), buffer->DataLength() };
EXPECT_EQ(manager.ProcessCheckInPayload(payload, decodeClientInfo, checkInCounter), CHIP_NO_ERROR);
EXPECT_EQ(checkInCounter, 1u);
EXPECT_EQ(checkInCounter, counter);
manager.DeleteAllEntries(fabricId);

EXPECT_EQ(chip::Protocols::SecureChannel::CheckinMessage::GenerateCheckinMessagePayload(
Expand Down

0 comments on commit 7334a09

Please sign in to comment.