3 * Copyright (c) 2020 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This file implements a process to effect a functional test for
22 * the PeerConnections class within the transport layer
25 #include <support/CodeUtils.h>
26 #include <support/ErrorStr.h>
27 #include <support/UnitTestRegistration.h>
28 #include <transport/PeerConnections.h>
30 #include <nlunit-test.h>
35 using namespace chip::Transport;
37 PeerAddress AddressFromString(const char * str)
41 VerifyOrDie(Inet::IPAddress::FromString(str, addr));
43 return PeerAddress::UDP(addr);
46 const PeerAddress kPeer1Addr = AddressFromString("10.1.2.3");
47 const PeerAddress kPeer2Addr = AddressFromString("10.0.0.32");
48 const PeerAddress kPeer3Addr = AddressFromString("100.200.0.1");
50 const NodeId kPeer1NodeId = 123;
51 const NodeId kPeer2NodeId = 6;
52 const NodeId kPeer3NodeId = 81;
54 void TestBasicFunctionality(nlTestSuite * inSuite, void * inContext)
57 PeerConnectionState * statePtr;
58 PeerConnections<2, Time::Source::kTest> connections;
59 connections.GetTimeSource().SetCurrentMonotonicTimeMs(100);
61 err = connections.CreateNewPeerConnectionState(kPeer1Addr, nullptr);
62 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
64 err = connections.CreateNewPeerConnectionState(kPeer2Addr, &statePtr);
65 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
66 NL_TEST_ASSERT(inSuite, statePtr != nullptr);
67 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
68 NL_TEST_ASSERT(inSuite, statePtr->GetLastActivityTimeMs() == 100);
70 // Insufficient space for new connections. Object is max size 2
71 err = connections.CreateNewPeerConnectionState(kPeer3Addr, &statePtr);
72 NL_TEST_ASSERT(inSuite, err != CHIP_NO_ERROR);
75 void TestFindByAddress(nlTestSuite * inSuite, void * inContext)
78 PeerConnectionState * statePtr;
79 PeerConnections<3, Time::Source::kTest> connections;
81 PeerConnectionState * state1 = nullptr;
82 PeerConnectionState * state2 = nullptr;
83 PeerConnectionState * state3 = nullptr;
85 err = connections.CreateNewPeerConnectionState(kPeer1Addr, &state1);
86 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
88 err = connections.CreateNewPeerConnectionState(kPeer1Addr, &state2);
89 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
91 err = connections.CreateNewPeerConnectionState(kPeer2Addr, &state3);
92 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
94 NL_TEST_ASSERT(inSuite, state1 != state2);
95 NL_TEST_ASSERT(inSuite, state1 != state3);
96 NL_TEST_ASSERT(inSuite, state2 != state3);
98 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1Addr, nullptr));
99 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer1Addr);
101 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1Addr, statePtr));
102 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer1Addr);
104 NL_TEST_ASSERT(inSuite, (statePtr = connections.FindPeerConnectionState(kPeer1Addr, statePtr)) == nullptr);
106 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer2Addr, nullptr));
107 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
108 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
111 void TestFindByNodeId(nlTestSuite * inSuite, void * inContext)
114 PeerConnectionState * statePtr;
115 PeerConnections<3, Time::Source::kTest> connections;
117 err = connections.CreateNewPeerConnectionState(kPeer1Addr, &statePtr);
118 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
119 statePtr->SetPeerNodeId(kPeer1NodeId);
121 err = connections.CreateNewPeerConnectionState(kPeer2Addr, &statePtr);
122 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
123 statePtr->SetPeerNodeId(kPeer2NodeId);
125 err = connections.CreateNewPeerConnectionState(kPeer2Addr, &statePtr);
126 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
127 statePtr->SetPeerNodeId(kPeer1NodeId);
129 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1NodeId, nullptr));
131 statePtr->GetPeerAddress().ToString(buf);
132 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer1Addr);
133 NL_TEST_ASSERT(inSuite, statePtr->GetPeerNodeId() == kPeer1NodeId);
135 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer1NodeId, statePtr));
136 statePtr->GetPeerAddress().ToString(buf);
137 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
138 NL_TEST_ASSERT(inSuite, statePtr->GetPeerNodeId() == kPeer1NodeId);
140 NL_TEST_ASSERT(inSuite, (statePtr = connections.FindPeerConnectionState(kPeer1NodeId, statePtr)) == nullptr);
142 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer2NodeId, nullptr));
143 NL_TEST_ASSERT(inSuite, statePtr->GetPeerAddress() == kPeer2Addr);
144 NL_TEST_ASSERT(inSuite, statePtr->GetPeerNodeId() == kPeer2NodeId);
146 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3NodeId, nullptr));
149 void TestFindByKeyId(nlTestSuite * inSuite, void * inContext)
152 PeerConnectionState * statePtr;
153 PeerConnections<2, Time::Source::kTest> connections;
155 // No Node ID, peer key 1, local key 2
156 err = connections.CreateNewPeerConnectionState(Optional<NodeId>::Missing(), 1, 2, &statePtr);
157 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
159 // Lookup using no node, and peer key
160 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 1, nullptr));
161 // Lookup using no node, and local key
162 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 2, nullptr));
164 // Lookup using no node, and incorrect peer key
165 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 2, nullptr));
167 // Lookup using no node, and incorrect local key
168 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 1, nullptr));
170 // Lookup using a node ID, and peer key
171 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 1, nullptr));
173 // Lookup using a node ID, and local key
174 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 2, nullptr));
176 // Some Node ID, peer key 3, local key 4
177 err = connections.CreateNewPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 3, 4, &statePtr);
178 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
180 // Lookup using correct node (or no node), and correct keys
181 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 3, nullptr));
182 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 4, nullptr));
183 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(Optional<NodeId>::Missing(), 3, nullptr));
184 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Missing(), 4, nullptr));
186 // Lookup using incorrect keys
187 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer1NodeId), 4, nullptr));
188 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer1NodeId), 3, nullptr));
190 // Lookup using incorrect node, but correct keys
191 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(Optional<NodeId>::Value(kPeer2NodeId), 3, nullptr));
192 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionStateByLocalKey(Optional<NodeId>::Value(kPeer2NodeId), 4, nullptr));
195 struct ExpiredCallInfo
198 NodeId lastCallNodeId = 0;
199 PeerAddress lastCallPeerAddress = PeerAddress::Uninitialized();
202 void TestExpireConnections(nlTestSuite * inSuite, void * inContext)
205 ExpiredCallInfo callInfo;
206 PeerConnectionState * statePtr;
207 PeerConnections<2, Time::Source::kTest> connections;
209 connections.GetTimeSource().SetCurrentMonotonicTimeMs(100);
211 err = connections.CreateNewPeerConnectionState(kPeer1Addr, nullptr);
212 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
214 connections.GetTimeSource().SetCurrentMonotonicTimeMs(200);
215 err = connections.CreateNewPeerConnectionState(kPeer2Addr, &statePtr);
216 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
217 statePtr->SetPeerNodeId(kPeer2NodeId);
219 // cannot add before expiry
220 connections.GetTimeSource().SetCurrentMonotonicTimeMs(300);
221 err = connections.CreateNewPeerConnectionState(kPeer3Addr, &statePtr);
222 NL_TEST_ASSERT(inSuite, err != CHIP_NO_ERROR);
224 // at time 300, this expires ip addr 1
225 connections.ExpireInactiveConnections(150, [&callInfo](const PeerConnectionState & state) {
226 callInfo.callCount++;
227 callInfo.lastCallNodeId = state.GetPeerNodeId();
228 callInfo.lastCallPeerAddress = state.GetPeerAddress();
230 NL_TEST_ASSERT(inSuite, callInfo.callCount == 1);
231 NL_TEST_ASSERT(inSuite, callInfo.lastCallNodeId == kUndefinedNodeId);
232 NL_TEST_ASSERT(inSuite, callInfo.lastCallPeerAddress == kPeer1Addr);
233 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1NodeId, nullptr));
235 // now that the connections were expired, we can add peer3
236 connections.GetTimeSource().SetCurrentMonotonicTimeMs(300);
237 err = connections.CreateNewPeerConnectionState(kPeer3Addr, &statePtr);
238 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
239 statePtr->SetPeerNodeId(kPeer3NodeId);
241 connections.GetTimeSource().SetCurrentMonotonicTimeMs(400);
242 NL_TEST_ASSERT(inSuite, statePtr = connections.FindPeerConnectionState(kPeer2NodeId, nullptr));
244 connections.MarkConnectionActive(statePtr);
245 NL_TEST_ASSERT(inSuite, statePtr->GetLastActivityTimeMs() == connections.GetTimeSource().GetCurrentMonotonicTimeMs());
248 // Peer 3 active at time 300
249 // Peer 2 active at time 400
251 connections.GetTimeSource().SetCurrentMonotonicTimeMs(500);
252 callInfo.callCount = 0;
253 connections.ExpireInactiveConnections(150, [&callInfo](const PeerConnectionState & state) {
254 callInfo.callCount++;
255 callInfo.lastCallNodeId = state.GetPeerNodeId();
256 callInfo.lastCallPeerAddress = state.GetPeerAddress();
259 // peer 2 stays active
260 NL_TEST_ASSERT(inSuite, callInfo.callCount == 1);
261 NL_TEST_ASSERT(inSuite, callInfo.lastCallNodeId == kPeer3NodeId);
262 NL_TEST_ASSERT(inSuite, callInfo.lastCallPeerAddress == kPeer3Addr);
263 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1Addr, nullptr));
264 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, nullptr));
265 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
267 err = connections.CreateNewPeerConnectionState(kPeer1Addr, nullptr);
268 NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
269 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer1Addr, nullptr));
270 NL_TEST_ASSERT(inSuite, connections.FindPeerConnectionState(kPeer2Addr, nullptr));
271 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
273 // peer 1 and 2 are active
274 connections.GetTimeSource().SetCurrentMonotonicTimeMs(1000);
275 callInfo.callCount = 0;
276 connections.ExpireInactiveConnections(100, [&callInfo](const PeerConnectionState & state) {
277 callInfo.callCount++;
278 callInfo.lastCallNodeId = state.GetPeerNodeId();
279 callInfo.lastCallPeerAddress = state.GetPeerAddress();
281 NL_TEST_ASSERT(inSuite, callInfo.callCount == 2); // everything expired
282 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer1Addr, nullptr));
283 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer2Addr, nullptr));
284 NL_TEST_ASSERT(inSuite, !connections.FindPeerConnectionState(kPeer3Addr, nullptr));
290 static const nlTest sTests[] =
292 NL_TEST_DEF("BasicFunctionality", TestBasicFunctionality),
293 NL_TEST_DEF("FindByPeerAddress", TestFindByAddress),
294 NL_TEST_DEF("FindByNodeId", TestFindByNodeId),
295 NL_TEST_DEF("FindByKeyId", TestFindByKeyId),
296 NL_TEST_DEF("ExpireConnections", TestExpireConnections),
301 int TestPeerConnectionsFn(void)
303 nlTestSuite theSuite = { "Transport-PeerConnections", &sTests[0], nullptr, nullptr };
304 nlTestRunner(&theSuite, nullptr);
305 return nlTestRunnerStats(&theSuite);
308 CHIP_REGISTER_TEST_SUITE(TestPeerConnectionsFn)