/* * * Copyright (c) 2020-2021 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. */ /** * @file * This file implements unit tests for the SessionManager implementation. */ #include #include #include #include #include #include #include namespace { using namespace chip; class TestGroupOutgoingCounters : public chip::Transport::GroupOutgoingCounters { public: TestGroupOutgoingCounters(){}; TestGroupOutgoingCounters(chip::PersistentStorageDelegate * storage_delegate) : GroupOutgoingCounters(storage_delegate){}; void SetCounter(bool isControl, uint32_t value) { uint32_t temp = 0; StorageKeyName key = StorageKeyName::Uninitialized(); if (isControl) { mGroupControlCounter = value; key = DefaultStorageKeyAllocator::GroupControlCounter(); } else { mGroupDataCounter = value; key = DefaultStorageKeyAllocator::GroupDataCounter(); } if (mStorage == nullptr) { return; } // Always Update storage for Test purposes temp = value + GROUP_MSG_COUNTER_MIN_INCREMENT; mStorage->SyncSetKeyValue(key.KeyName(), &temp, sizeof(uint32_t)); } }; class TestGroupPeerTable : public chip::Transport::GroupPeerTable { public: TestGroupPeerTable(){}; FabricIndex GetFabricIndexAt(uint8_t index) { if (index < CHIP_CONFIG_MAX_FABRICS) { return mGroupFabrics[index].mFabricIndex; } return kUndefinedFabricIndex; } NodeId GetNodeIdAt(uint8_t fabricIndex, uint8_t index, bool isControl) { if (fabricIndex < CHIP_CONFIG_MAX_FABRICS) { if (isControl && index < CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS) { return mGroupFabrics[fabricIndex].mControlGroupSenders[index].mNodeId; } if (!isControl && index < CHIP_CONFIG_MAX_GROUP_DATA_PEERS) { return mGroupFabrics[fabricIndex].mDataGroupSenders[index].mNodeId; } } return kUndefinedNodeId; } }; TEST(TestGroupMessageCounter, AddPeerTest) { NodeId peerNodeId = 1234; FabricIndex fabricIndex = 1; int i = 0; CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; chip::Transport::GroupPeerTable mGroupPeerMsgCounter; do { err = mGroupPeerMsgCounter.FindOrAddPeer(fabricIndex, peerNodeId++, false, counter); i++; } while (err != CHIP_ERROR_TOO_MANY_PEER_NODES); EXPECT_EQ(i, CHIP_CONFIG_MAX_GROUP_DATA_PEERS + 1); i = 1; do { err = mGroupPeerMsgCounter.FindOrAddPeer(++fabricIndex, peerNodeId, false, counter); i++; } while (err != CHIP_ERROR_TOO_MANY_PEER_NODES); EXPECT_EQ(i, CHIP_CONFIG_MAX_FABRICS + 1); } TEST(TestGroupMessageCounter, RemovePeerTest) { NodeId peerNodeId = 1234; FabricIndex fabricIndex = 1; CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; TestGroupPeerTable mGroupPeerMsgCounter; // Fill table up (max fabric and mac peer) for (uint32_t it = 0; it < CHIP_CONFIG_MAX_FABRICS; it++) { for (uint32_t peerId = 0; peerId < CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS; peerId++) { err = mGroupPeerMsgCounter.FindOrAddPeer(fabricIndex, peerNodeId++, true, counter); } fabricIndex++; } // Verify that table is indeed full (for control Peer) err = mGroupPeerMsgCounter.FindOrAddPeer(99, 99, true, counter); EXPECT_EQ(err, CHIP_ERROR_TOO_MANY_PEER_NODES); // Clear all Peer fabricIndex = 1; peerNodeId = 1234; for (uint32_t it = 0; it < CHIP_CONFIG_MAX_FABRICS; it++) { for (uint32_t peerId = 0; peerId < CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS; peerId++) { err = mGroupPeerMsgCounter.RemovePeer(fabricIndex, peerNodeId++, true); EXPECT_EQ(err, CHIP_NO_ERROR); } fabricIndex++; } // Try re-adding the previous peer without any error err = mGroupPeerMsgCounter.FindOrAddPeer(99, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); err = mGroupPeerMsgCounter.FindOrAddPeer(104, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); err = mGroupPeerMsgCounter.FindOrAddPeer(105, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); err = mGroupPeerMsgCounter.FindOrAddPeer(106, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); // Fabric removal test err = mGroupPeerMsgCounter.FabricRemoved(123); EXPECT_EQ(err, CHIP_ERROR_NOT_FOUND); err = mGroupPeerMsgCounter.FabricRemoved(99); EXPECT_EQ(err, CHIP_NO_ERROR); err = mGroupPeerMsgCounter.FabricRemoved(99); EXPECT_EQ(err, CHIP_ERROR_NOT_FOUND); // Verify that the Fabric List was compacted. EXPECT_EQ(106, mGroupPeerMsgCounter.GetFabricIndexAt(0)); } TEST(TestGroupMessageCounter, PeerRetrievalTest) { NodeId peerNodeId = 1234; FabricIndex fabricIndex = 1; CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; chip::Transport::PeerMessageCounter * counter2 = nullptr; chip::Transport::GroupPeerTable mGroupPeerMsgCounter; err = mGroupPeerMsgCounter.FindOrAddPeer(fabricIndex, peerNodeId, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_NE(counter, nullptr); err = mGroupPeerMsgCounter.FindOrAddPeer(99, 99, true, counter2); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_NE(counter2, nullptr); EXPECT_NE(counter2, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(fabricIndex, peerNodeId, true, counter2); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(counter2, counter); } TEST(TestGroupMessageCounter, CounterCommitRolloverTest) { CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; chip::Transport::GroupPeerTable mGroupPeerMsgCounter; err = mGroupPeerMsgCounter.FindOrAddPeer(99, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_NE(counter, nullptr); err = counter->VerifyOrTrustFirstGroup(UINT32_MAX); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(UINT32_MAX); err = counter->VerifyOrTrustFirstGroup(0); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(0); err = counter->VerifyOrTrustFirstGroup(1); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(1); } TEST(TestGroupMessageCounter, CounterTrustFirstTest) { CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; chip::Transport::GroupPeerTable mGroupPeerMsgCounter; err = mGroupPeerMsgCounter.FindOrAddPeer(99, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_NE(counter, nullptr); err = counter->VerifyOrTrustFirstGroup(5656); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(5656); err = counter->VerifyOrTrustFirstGroup(5756); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(5756); err = counter->VerifyOrTrustFirstGroup(4756); EXPECT_NE(err, CHIP_NO_ERROR); // test sequential reception err = counter->VerifyOrTrustFirstGroup(5757); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(5757); err = counter->VerifyOrTrustFirstGroup(5758); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(5758); err = counter->VerifyOrTrustFirstGroup(5756); EXPECT_NE(err, CHIP_NO_ERROR); // Test Roll over err = mGroupPeerMsgCounter.FindOrAddPeer(1, 99, true, counter); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_NE(counter, nullptr); err = counter->VerifyOrTrustFirstGroup(UINT32_MAX - 6); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(UINT32_MAX - 6); err = counter->VerifyOrTrustFirstGroup(UINT32_MAX - 1); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(UINT32_MAX - 1); err = counter->VerifyOrTrustFirstGroup(UINT32_MAX); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(0); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(1); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(2); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(3); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(4); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(5); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(6); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(7); EXPECT_EQ(err, CHIP_NO_ERROR); } TEST(TestGroupMessageCounter, ReorderPeerRemovalTest) { CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; TestGroupPeerTable mGroupPeerMsgCounter; err = mGroupPeerMsgCounter.FindOrAddPeer(1, 1, true, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(1, 2, true, counter); err = mGroupPeerMsgCounter.RemovePeer(1, 1, true); EXPECT_EQ(mGroupPeerMsgCounter.GetNodeIdAt(0, 0, true), 2u); // with other list err = mGroupPeerMsgCounter.FindOrAddPeer(2, 1, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 2, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 3, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 4, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 5, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 6, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 7, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 8, false, counter); err = mGroupPeerMsgCounter.FindOrAddPeer(2, 9, false, counter); err = mGroupPeerMsgCounter.RemovePeer(2, 7, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(mGroupPeerMsgCounter.GetNodeIdAt(1, 6, false), 9u); err = mGroupPeerMsgCounter.RemovePeer(2, 4, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(mGroupPeerMsgCounter.GetNodeIdAt(1, 3, false), 8u); err = mGroupPeerMsgCounter.RemovePeer(2, 1, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(mGroupPeerMsgCounter.GetNodeIdAt(1, 0, false), 9u); } TEST(TestGroupMessageCounter, ReorderFabricRemovalTest) { CHIP_ERROR err = CHIP_NO_ERROR; chip::Transport::PeerMessageCounter * counter = nullptr; TestGroupPeerTable mGroupPeerMsgCounter; for (uint8_t i = 0; i < CHIP_CONFIG_MAX_FABRICS; i++) { err = mGroupPeerMsgCounter.FindOrAddPeer(static_cast(i + 1), 1, false, counter); EXPECT_EQ(err, CHIP_NO_ERROR); } // Try removing last Fabric first err = counter->VerifyOrTrustFirstGroup(1234); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(1234); err = mGroupPeerMsgCounter.FabricRemoved(CHIP_CONFIG_MAX_FABRICS); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(mGroupPeerMsgCounter.GetFabricIndexAt(CHIP_CONFIG_MAX_FABRICS - 1), kUndefinedFabricIndex); err = mGroupPeerMsgCounter.FindOrAddPeer(CHIP_CONFIG_MAX_FABRICS, 1, false, counter); EXPECT_EQ(err, CHIP_NO_ERROR); // Verify that the counter was indeed cleared err = counter->VerifyOrTrustFirstGroup(1234); EXPECT_EQ(err, CHIP_NO_ERROR); // Set a counter that will be moved around err = counter->VerifyOrTrustFirstGroup(5656); EXPECT_EQ(err, CHIP_NO_ERROR); counter->CommitGroup(5656); err = counter->VerifyOrTrustFirstGroup(4756); EXPECT_NE(err, CHIP_NO_ERROR); // Per Spec CHIP_CONFIG_MAX_FABRICS can only be as low as 4 err = mGroupPeerMsgCounter.RemovePeer(3, 1, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(mGroupPeerMsgCounter.GetFabricIndexAt(2), CHIP_CONFIG_MAX_FABRICS); err = mGroupPeerMsgCounter.RemovePeer(2, 1, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(mGroupPeerMsgCounter.GetFabricIndexAt(1), CHIP_CONFIG_MAX_FABRICS - 1); // Validate that counter value were moved around correctly err = mGroupPeerMsgCounter.FindOrAddPeer(CHIP_CONFIG_MAX_FABRICS, 1, false, counter); EXPECT_EQ(err, CHIP_NO_ERROR); err = counter->VerifyOrTrustFirstGroup(4756); EXPECT_NE(err, CHIP_NO_ERROR); } TEST(TestGroupMessageCounter, GroupMessageCounterTest) { chip::TestPersistentStorageDelegate delegate; TestGroupOutgoingCounters groupCientCounter; uint32_t controlCounter = 0, dataCounter = 0; CHIP_ERROR err = groupCientCounter.Init(&delegate); EXPECT_EQ(err, CHIP_NO_ERROR); // Start Test with Control counter // Counter should be random controlCounter = groupCientCounter.GetCounter(true); dataCounter = groupCientCounter.GetCounter(false); groupCientCounter.IncrementCounter(true); EXPECT_EQ((groupCientCounter.GetCounter(true) - controlCounter), 1u); groupCientCounter.SetCounter(true, UINT32_MAX - GROUP_MSG_COUNTER_MIN_INCREMENT); EXPECT_EQ(groupCientCounter.GetCounter(true), UINT32_MAX - GROUP_MSG_COUNTER_MIN_INCREMENT); // Test Persistence TestGroupOutgoingCounters groupCientCounter2(&delegate); EXPECT_EQ(groupCientCounter2.GetCounter(true), UINT32_MAX); EXPECT_EQ((groupCientCounter2.GetCounter(false) - dataCounter), (uint32_t) GROUP_MSG_COUNTER_MIN_INCREMENT); // Test Roll over groupCientCounter2.IncrementCounter(true); EXPECT_EQ(groupCientCounter2.GetCounter(true), 0u); TestGroupOutgoingCounters groupCientCounter3(&delegate); EXPECT_EQ(groupCientCounter3.GetCounter(true), (UINT32_MAX + GROUP_MSG_COUNTER_MIN_INCREMENT)); // Redo the test with the second counter // Start Test with Control counter dataCounter = groupCientCounter.GetCounter(false); groupCientCounter.IncrementCounter(false); EXPECT_EQ((groupCientCounter.GetCounter(false) - dataCounter), 1u); groupCientCounter.SetCounter(false, UINT32_MAX - GROUP_MSG_COUNTER_MIN_INCREMENT); EXPECT_EQ(groupCientCounter.GetCounter(false), UINT32_MAX - GROUP_MSG_COUNTER_MIN_INCREMENT); // Test Persistence TestGroupOutgoingCounters groupCientCounter4(&delegate); EXPECT_EQ(groupCientCounter4.GetCounter(false), UINT32_MAX); // Test Roll over groupCientCounter4.IncrementCounter(false); EXPECT_EQ(groupCientCounter4.GetCounter(false), 0u); TestGroupOutgoingCounters groupCientCounter5(&delegate); EXPECT_EQ(groupCientCounter5.GetCounter(false), (UINT32_MAX + GROUP_MSG_COUNTER_MIN_INCREMENT)); } } // namespace