Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 1 | /* |
| 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 Litvin | dacfe1b | 2022-06-27 11:40:37 -0400 | [diff] [blame] | 25 | #include <lib/support/UnitTestContext.h> |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 26 | #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 | |
| 34 | using TestContext = chip::Test::AppContext; |
| 35 | |
| 36 | namespace chip { |
| 37 | namespace app { |
| 38 | |
| 39 | using namespace Messaging; |
| 40 | using namespace Protocols::InteractionModel; |
| 41 | |
| 42 | class TestTimedHandler |
| 43 | { |
| 44 | public: |
| 45 | static void TestInvokeFastEnough(nlTestSuite * aSuite, void * aContext); |
Boris Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 46 | static void TestWriteFastEnough(nlTestSuite * aSuite, void * aContext); |
| 47 | |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 48 | static void TestInvokeTooSlow(nlTestSuite * aSuite, void * aContext); |
Boris Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 49 | static void TestWriteTooSlow(nlTestSuite * aSuite, void * aContext); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 50 | |
| 51 | static void TestInvokeNeverComes(nlTestSuite * aSuite, void * aContext); |
| 52 | |
| 53 | private: |
Boris Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 54 | static void TestFollowingMessageFastEnough(nlTestSuite * aSuite, void * aContext, MsgType aMsgType); |
| 55 | static void TestFollowingMessageTooSlow(nlTestSuite * aSuite, void * aContext, MsgType aMsgType); |
| 56 | |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 57 | static void GenerateTimedRequest(nlTestSuite * aSuite, uint16_t aTimeoutValue, System::PacketBufferHandle & aPayload); |
| 58 | }; |
| 59 | |
| 60 | namespace { |
| 61 | |
| 62 | class 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-google | 73d0fae | 2022-07-28 07:28:14 -0700 | [diff] [blame] | 71 | 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 Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 77 | } |
| 78 | if (mKeepExchangeOpen) |
| 79 | { |
| 80 | aExchangeContext->WillSendMessage(); |
| 81 | } |
| 82 | return CHIP_NO_ERROR; |
| 83 | } |
| 84 | |
| 85 | void OnResponseTimeout(Messaging::ExchangeContext *) override {} |
| 86 | |
| 87 | public: |
| 88 | bool mKeepExchangeOpen = false; |
| 89 | bool mNewMessageReceived = false; |
| 90 | bool mLastMessageWasStatus = false; |
Boris Zbarsky | 8bc5129 | 2022-01-25 12:11:04 -0500 | [diff] [blame] | 91 | CHIP_ERROR mError = CHIP_NO_ERROR; |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 92 | }; |
| 93 | |
| 94 | } // anonymous namespace |
| 95 | |
| 96 | void 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 Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 115 | void TestTimedHandler::TestFollowingMessageFastEnough(nlTestSuite * aSuite, void * aContext, MsgType aMsgType) |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 116 | { |
| 117 | TestContext & ctx = *static_cast<TestContext *>(aContext); |
| 118 | |
| 119 | System::PacketBufferHandle payload; |
Song GUO | 8da5d03 | 2022-03-29 22:54:57 +0800 | [diff] [blame] | 120 | GenerateTimedRequest(aSuite, 500, payload); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 121 | |
| 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 Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 132 | |
| 133 | ctx.DrainAndServiceIO(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 134 | NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived); |
| 135 | NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus); |
Boris Zbarsky | 8bc5129 | 2022-01-25 12:11:04 -0500 | [diff] [blame] | 136 | NL_TEST_ASSERT(aSuite, delegate.mError == CHIP_NO_ERROR); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 137 | |
| 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 Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 146 | err = exchange->SendMessage(aMsgType, std::move(payload), SendMessageFlags::kExpectResponse); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 147 | NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR); |
Boris Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 148 | |
| 149 | ctx.DrainAndServiceIO(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 150 | NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived); |
| 151 | NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus); |
Boris Zbarsky | 8bc5129 | 2022-01-25 12:11:04 -0500 | [diff] [blame] | 152 | NL_TEST_ASSERT(aSuite, StatusIB(delegate.mError).mStatus != Status::UnsupportedAccess); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 153 | } |
| 154 | |
Boris Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 155 | void TestTimedHandler::TestInvokeFastEnough(nlTestSuite * aSuite, void * aContext) |
| 156 | { |
| 157 | TestFollowingMessageFastEnough(aSuite, aContext, MsgType::InvokeCommandRequest); |
| 158 | } |
| 159 | |
| 160 | void TestTimedHandler::TestWriteFastEnough(nlTestSuite * aSuite, void * aContext) |
| 161 | { |
| 162 | TestFollowingMessageFastEnough(aSuite, aContext, MsgType::WriteRequest); |
| 163 | } |
| 164 | |
| 165 | void TestTimedHandler::TestFollowingMessageTooSlow(nlTestSuite * aSuite, void * aContext, MsgType aMsgType) |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 166 | { |
| 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 Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 182 | |
| 183 | ctx.DrainAndServiceIO(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 184 | NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived); |
| 185 | NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus); |
Boris Zbarsky | 8bc5129 | 2022-01-25 12:11:04 -0500 | [diff] [blame] | 186 | NL_TEST_ASSERT(aSuite, delegate.mError == CHIP_NO_ERROR); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 187 | |
| 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 Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 199 | err = exchange->SendMessage(aMsgType, std::move(payload), SendMessageFlags::kExpectResponse); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 200 | NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR); |
Boris Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 201 | |
| 202 | ctx.DrainAndServiceIO(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 203 | NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived); |
| 204 | NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus); |
Boris Zbarsky | 8bc5129 | 2022-01-25 12:11:04 -0500 | [diff] [blame] | 205 | NL_TEST_ASSERT(aSuite, StatusIB(delegate.mError).mStatus == Status::UnsupportedAccess); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 206 | } |
| 207 | |
Boris Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 208 | void TestTimedHandler::TestInvokeTooSlow(nlTestSuite * aSuite, void * aContext) |
| 209 | { |
| 210 | TestFollowingMessageTooSlow(aSuite, aContext, MsgType::InvokeCommandRequest); |
| 211 | } |
| 212 | |
| 213 | void TestTimedHandler::TestWriteTooSlow(nlTestSuite * aSuite, void * aContext) |
| 214 | { |
| 215 | TestFollowingMessageTooSlow(aSuite, aContext, MsgType::WriteRequest); |
| 216 | } |
| 217 | |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 218 | void 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 Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 233 | |
| 234 | ctx.DrainAndServiceIO(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 235 | NL_TEST_ASSERT(aSuite, delegate.mNewMessageReceived); |
| 236 | NL_TEST_ASSERT(aSuite, delegate.mLastMessageWasStatus); |
Boris Zbarsky | 8bc5129 | 2022-01-25 12:11:04 -0500 | [diff] [blame] | 237 | NL_TEST_ASSERT(aSuite, delegate.mError == CHIP_NO_ERROR); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 238 | |
| 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 | |
| 246 | namespace { |
| 247 | |
| 248 | /** |
| 249 | * Test Suite. It lists all the test functions. |
| 250 | */ |
| 251 | |
| 252 | // clang-format off |
| 253 | const 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 |
| 263 | nlTestSuite sSuite = |
| 264 | { |
| 265 | "TestTimedHandler", |
| 266 | &sTests[0], |
Zang MingJie | 4aa0d5f | 2022-04-22 21:22:42 +0800 | [diff] [blame] | 267 | TestContext::Initialize, |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 268 | TestContext::Finalize |
| 269 | }; |
| 270 | // clang-format on |
| 271 | |
| 272 | } // namespace |
| 273 | |
| 274 | int TestTimedHandler() |
| 275 | { |
Andrei Litvin | dacfe1b | 2022-06-27 11:40:37 -0400 | [diff] [blame] | 276 | return chip::ExecuteTestsWithContext<TestContext>(&sSuite); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 277 | } |
| 278 | |
| 279 | CHIP_REGISTER_TEST_SUITE(TestTimedHandler) |