blob: 6c081e27428a9448780490b4688b95bac75e8bf8 [file] [log] [blame]
Boris Zbarskyffee2a92021-12-01 14:34:57 -05001/*
2 *
3 * Copyright (c) 2021 Project CHIP Authors
4 * All rights reserved.
5 *
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 */
18
19#include <app/InteractionModelEngine.h>
20#include <app/MessageDef/TimedRequestMessage.h>
21#include <app/StatusResponse.h>
22#include <app/tests/AppTestContext.h>
23#include <lib/core/CHIPCore.h>
24#include <lib/core/CHIPTLV.h>
Andrei Litvindacfe1b2022-06-27 11:40:37 -040025#include <lib/support/UnitTestContext.h>
Boris Zbarskyffee2a92021-12-01 14:34:57 -050026#include <lib/support/UnitTestRegistration.h>
27#include <lib/support/UnitTestUtils.h>
28#include <protocols/interaction_model/Constants.h>
29#include <system/TLVPacketBufferBackingStore.h>
30#include <transport/SessionManager.h>
31
32#include <nlunit-test.h>
33
34using TestContext = chip::Test::AppContext;
35
36namespace chip {
37namespace app {
38
39using namespace Messaging;
40using namespace Protocols::InteractionModel;
41
42class TestTimedHandler
43{
44public:
45 static void TestInvokeFastEnough(nlTestSuite * aSuite, void * aContext);
Boris Zbarsky653502d2021-12-02 04:01:47 -050046 static void TestWriteFastEnough(nlTestSuite * aSuite, void * aContext);
47
Boris Zbarskyffee2a92021-12-01 14:34:57 -050048 static void TestInvokeTooSlow(nlTestSuite * aSuite, void * aContext);
Boris Zbarsky653502d2021-12-02 04:01:47 -050049 static void TestWriteTooSlow(nlTestSuite * aSuite, void * aContext);
Boris Zbarskyffee2a92021-12-01 14:34:57 -050050
51 static void TestInvokeNeverComes(nlTestSuite * aSuite, void * aContext);
52
53private:
Boris Zbarsky653502d2021-12-02 04:01:47 -050054 static void TestFollowingMessageFastEnough(nlTestSuite * aSuite, void * aContext, MsgType aMsgType);
55 static void TestFollowingMessageTooSlow(nlTestSuite * aSuite, void * aContext, MsgType aMsgType);
56
Boris Zbarskyffee2a92021-12-01 14:34:57 -050057 static void GenerateTimedRequest(nlTestSuite * aSuite, uint16_t aTimeoutValue, System::PacketBufferHandle & aPayload);
58};
59
60namespace {
61
62class TestExchangeDelegate : public Messaging::ExchangeDelegate
63{
64 CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * aExchangeContext, const PayloadHeader & aPayloadHeader,
65 System::PacketBufferHandle && aPayload) override
66 {
67 mNewMessageReceived = true;
68 mLastMessageWasStatus = aPayloadHeader.HasMessageType(MsgType::StatusResponse);
69 if (mLastMessageWasStatus)
70 {
yunhanw-google73d0fae2022-07-28 07:28:14 -070071 CHIP_ERROR statusError = CHIP_NO_ERROR;
72 mError = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError);
73 if (mError == CHIP_NO_ERROR)
74 {
75 mError = statusError;
76 }
Boris Zbarskyffee2a92021-12-01 14:34:57 -050077 }
78 if (mKeepExchangeOpen)
79 {
80 aExchangeContext->WillSendMessage();
81 }
82 return CHIP_NO_ERROR;
83 }
84
85 void OnResponseTimeout(Messaging::ExchangeContext *) override {}
86
87public:
88 bool mKeepExchangeOpen = false;
89 bool mNewMessageReceived = false;
90 bool mLastMessageWasStatus = false;
Boris Zbarsky8bc51292022-01-25 12:11:04 -050091 CHIP_ERROR mError = CHIP_NO_ERROR;
Boris Zbarskyffee2a92021-12-01 14:34:57 -050092};
93
94} // anonymous namespace
95
96void TestTimedHandler::GenerateTimedRequest(nlTestSuite * aSuite, uint16_t aTimeoutValue, System::PacketBufferHandle & aPayload)
97{
98 aPayload = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
99 NL_TEST_ASSERT(aSuite, !aPayload.IsNull());
100
101 System::PacketBufferTLVWriter writer;
102 writer.Init(std::move(aPayload));
103
104 TimedRequestMessage::Builder builder;
105 CHIP_ERROR err = builder.Init(&writer);
106 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
107
108 builder.TimeoutMs(aTimeoutValue);
109 NL_TEST_ASSERT(aSuite, builder.GetError() == CHIP_NO_ERROR);
110
111 err = writer.Finalize(&aPayload);
112 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
113}
114
Boris Zbarsky653502d2021-12-02 04:01:47 -0500115void TestTimedHandler::TestFollowingMessageFastEnough(nlTestSuite * aSuite, void * aContext, MsgType aMsgType)
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500116{
117 TestContext & ctx = *static_cast<TestContext *>(aContext);
118
119 System::PacketBufferHandle payload;
Song GUO8da5d032022-03-29 22:54:57 +0800120 GenerateTimedRequest(aSuite, 500, payload);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500121
122 TestExchangeDelegate delegate;
123 ExchangeContext * exchange = ctx.NewExchangeToAlice(&delegate);
124 NL_TEST_ASSERT(aSuite, exchange != nullptr);
125
126 NL_TEST_ASSERT(aSuite, !delegate.mNewMessageReceived);
127
128 delegate.mKeepExchangeOpen = true;
129
130 CHIP_ERROR err = exchange->SendMessage(MsgType::TimedRequest, std::move(payload), SendMessageFlags::kExpectResponse);
131 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
Boris Zbarskydc10c822021-12-02 06:55:34 -0500132
133 ctx.DrainAndServiceIO();
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500134 NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived);
135 NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus);
Boris Zbarsky8bc51292022-01-25 12:11:04 -0500136 NL_TEST_ASSERT(aSuite, delegate.mError == CHIP_NO_ERROR);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500137
138 // Send an empty payload, which will error out but not with the
139 // UNSUPPORTED_ACCESS status we expect if we miss our timeout.
140 payload = MessagePacketBuffer::New(0);
141 NL_TEST_ASSERT(aSuite, !payload.IsNull());
142
143 delegate.mKeepExchangeOpen = false;
144 delegate.mNewMessageReceived = false;
145
Boris Zbarskydc10c822021-12-02 06:55:34 -0500146 err = exchange->SendMessage(aMsgType, std::move(payload), SendMessageFlags::kExpectResponse);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500147 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
Boris Zbarskydc10c822021-12-02 06:55:34 -0500148
149 ctx.DrainAndServiceIO();
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500150 NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived);
151 NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus);
Boris Zbarsky8bc51292022-01-25 12:11:04 -0500152 NL_TEST_ASSERT(aSuite, StatusIB(delegate.mError).mStatus != Status::UnsupportedAccess);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500153}
154
Boris Zbarsky653502d2021-12-02 04:01:47 -0500155void TestTimedHandler::TestInvokeFastEnough(nlTestSuite * aSuite, void * aContext)
156{
157 TestFollowingMessageFastEnough(aSuite, aContext, MsgType::InvokeCommandRequest);
158}
159
160void TestTimedHandler::TestWriteFastEnough(nlTestSuite * aSuite, void * aContext)
161{
162 TestFollowingMessageFastEnough(aSuite, aContext, MsgType::WriteRequest);
163}
164
165void TestTimedHandler::TestFollowingMessageTooSlow(nlTestSuite * aSuite, void * aContext, MsgType aMsgType)
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500166{
167 TestContext & ctx = *static_cast<TestContext *>(aContext);
168
169 System::PacketBufferHandle payload;
170 GenerateTimedRequest(aSuite, 50, payload);
171
172 TestExchangeDelegate delegate;
173 ExchangeContext * exchange = ctx.NewExchangeToAlice(&delegate);
174 NL_TEST_ASSERT(aSuite, exchange != nullptr);
175
176 NL_TEST_ASSERT(aSuite, !delegate.mNewMessageReceived);
177
178 delegate.mKeepExchangeOpen = true;
179
180 CHIP_ERROR err = exchange->SendMessage(MsgType::TimedRequest, std::move(payload), SendMessageFlags::kExpectResponse);
181 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
Boris Zbarskydc10c822021-12-02 06:55:34 -0500182
183 ctx.DrainAndServiceIO();
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500184 NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived);
185 NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus);
Boris Zbarsky8bc51292022-01-25 12:11:04 -0500186 NL_TEST_ASSERT(aSuite, delegate.mError == CHIP_NO_ERROR);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500187
188 // Sleep for > 50ms so we miss our time window.
189 chip::test_utils::SleepMillis(75);
190
191 // Send an empty payload, which will error out but not with the
192 // UNSUPPORTED_ACCESS status we expect if we miss our timeout.
193 payload = MessagePacketBuffer::New(0);
194 NL_TEST_ASSERT(aSuite, !payload.IsNull());
195
196 delegate.mKeepExchangeOpen = false;
197 delegate.mNewMessageReceived = false;
198
Boris Zbarskydc10c822021-12-02 06:55:34 -0500199 err = exchange->SendMessage(aMsgType, std::move(payload), SendMessageFlags::kExpectResponse);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500200 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
Boris Zbarskydc10c822021-12-02 06:55:34 -0500201
202 ctx.DrainAndServiceIO();
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500203 NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived);
204 NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus);
Boris Zbarsky8bc51292022-01-25 12:11:04 -0500205 NL_TEST_ASSERT(aSuite, StatusIB(delegate.mError).mStatus == Status::UnsupportedAccess);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500206}
207
Boris Zbarsky653502d2021-12-02 04:01:47 -0500208void TestTimedHandler::TestInvokeTooSlow(nlTestSuite * aSuite, void * aContext)
209{
210 TestFollowingMessageTooSlow(aSuite, aContext, MsgType::InvokeCommandRequest);
211}
212
213void TestTimedHandler::TestWriteTooSlow(nlTestSuite * aSuite, void * aContext)
214{
215 TestFollowingMessageTooSlow(aSuite, aContext, MsgType::WriteRequest);
216}
217
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500218void TestTimedHandler::TestInvokeNeverComes(nlTestSuite * aSuite, void * aContext)
219{
220 TestContext & ctx = *static_cast<TestContext *>(aContext);
221
222 System::PacketBufferHandle payload;
223 GenerateTimedRequest(aSuite, 50, payload);
224
225 TestExchangeDelegate delegate;
226 ExchangeContext * exchange = ctx.NewExchangeToAlice(&delegate);
227 NL_TEST_ASSERT(aSuite, exchange != nullptr);
228
229 NL_TEST_ASSERT(aSuite, !delegate.mNewMessageReceived);
230
231 CHIP_ERROR err = exchange->SendMessage(MsgType::TimedRequest, std::move(payload), SendMessageFlags::kExpectResponse);
232 NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR);
Boris Zbarskydc10c822021-12-02 06:55:34 -0500233
234 ctx.DrainAndServiceIO();
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500235 NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived);
236 NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus);
Boris Zbarsky8bc51292022-01-25 12:11:04 -0500237 NL_TEST_ASSERT(aSuite, delegate.mError == CHIP_NO_ERROR);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500238
239 // Do nothing else; exchange on the server remains open. We are testing to
240 // see whether shutdown cleans it up properly.
241}
242
243} // namespace app
244} // namespace chip
245
246namespace {
247
248/**
249 * Test Suite. It lists all the test functions.
250 */
251
252// clang-format off
253const nlTest sTests[] =
254{
255 NL_TEST_DEF("TimedHandlerTestInvokeFastEnough", chip::app::TestTimedHandler::TestInvokeFastEnough),
256 NL_TEST_DEF("TimedHandlerTestInvokeTooSlow", chip::app::TestTimedHandler::TestInvokeTooSlow),
257 NL_TEST_DEF("TimedHandlerTestInvokeNeverComes", chip::app::TestTimedHandler::TestInvokeNeverComes),
258 NL_TEST_SENTINEL()
259};
260// clang-format on
261
262// clang-format off
263nlTestSuite sSuite =
264{
265 "TestTimedHandler",
266 &sTests[0],
Zang MingJie4aa0d5f2022-04-22 21:22:42 +0800267 TestContext::Initialize,
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500268 TestContext::Finalize
269};
270// clang-format on
271
272} // namespace
273
274int TestTimedHandler()
275{
Andrei Litvindacfe1b2022-06-27 11:40:37 -0400276 return chip::ExecuteTestsWithContext<TestContext>(&sSuite);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500277}
278
279CHIP_REGISTER_TEST_SUITE(TestTimedHandler)