• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/l2cap/low_energy_command_handler.h"
16 
17 #include <pw_async/fake_dispatcher_fixture.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_signaling_channel.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
21 
22 namespace bt::l2cap::internal {
23 
24 class LowEnergyCommandHandlerTest
25     : public pw::async::test::FakeDispatcherFixture {
26  public:
27   LowEnergyCommandHandlerTest() = default;
28   ~LowEnergyCommandHandlerTest() override = default;
29   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyCommandHandlerTest);
30 
31  protected:
32   // TestLoopFixture overrides
SetUp()33   void SetUp() override {
34     signaling_channel_ =
35         std::make_unique<testing::FakeSignalingChannel>(dispatcher());
36     command_handler_ = std::make_unique<LowEnergyCommandHandler>(
37         fake_sig(),
38         fit::bind_member<&LowEnergyCommandHandlerTest::OnRequestFail>(this));
39     request_fail_callback_ = nullptr;
40     failed_requests_ = 0;
41   }
42 
TearDown()43   void TearDown() override {
44     request_fail_callback_ = nullptr;
45     signaling_channel_ = nullptr;
46     command_handler_ = nullptr;
47   }
48 
fake_sig() const49   testing::FakeSignalingChannel* fake_sig() const {
50     return signaling_channel_.get();
51   }
cmd_handler() const52   LowEnergyCommandHandler* cmd_handler() const {
53     return command_handler_.get();
54   }
failed_requests() const55   size_t failed_requests() const { return failed_requests_; }
56 
set_request_fail_callback(fit::closure request_fail_callback)57   void set_request_fail_callback(fit::closure request_fail_callback) {
58     BT_ASSERT(!request_fail_callback_);
59     request_fail_callback_ = std::move(request_fail_callback);
60   }
61 
62  private:
OnRequestFail()63   void OnRequestFail() {
64     failed_requests_++;
65     if (request_fail_callback_) {
66       request_fail_callback_();
67     }
68   }
69 
70   std::unique_ptr<testing::FakeSignalingChannel> signaling_channel_;
71   std::unique_ptr<LowEnergyCommandHandler> command_handler_;
72   fit::closure request_fail_callback_;
73   size_t failed_requests_;
74 };
75 
TEST_F(LowEnergyCommandHandlerTest,OutboundConnParamUpdateReqRspOk)76 TEST_F(LowEnergyCommandHandlerTest, OutboundConnParamUpdateReqRspOk) {
77   constexpr uint16_t kIntervalMin = 0;
78   constexpr uint16_t kIntervalMax = 1;
79   constexpr uint16_t kPeripheralLatency = 2;
80   constexpr uint16_t kTimeoutMult = 3;
81   StaticByteBuffer param_update_req(
82       // Interval Min
83       LowerBits(kIntervalMin),
84       UpperBits(kIntervalMin),
85       // Interval Max
86       LowerBits(kIntervalMax),
87       UpperBits(kIntervalMax),
88       // Peripheral Latency
89       LowerBits(kPeripheralLatency),
90       UpperBits(kPeripheralLatency),
91       // Timeout Multiplier
92       LowerBits(kTimeoutMult),
93       UpperBits(kTimeoutMult));
94 
95   StaticByteBuffer param_update_rsp(
96       LowerBits(
97           static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)),
98       UpperBits(
99           static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)));
100 
101   bool cb_called = false;
102   LowEnergyCommandHandler::ConnectionParameterUpdateResponseCallback rsp_cb =
103       [&](const LowEnergyCommandHandler::ConnectionParameterUpdateResponse&
104               rsp) {
105         cb_called = true;
106         EXPECT_EQ(SignalingChannel::Status::kSuccess, rsp.status());
107         EXPECT_EQ(ConnectionParameterUpdateResult::kRejected, rsp.result());
108       };
109 
110   EXPECT_OUTBOUND_REQ(
111       *fake_sig(),
112       kConnectionParameterUpdateRequest,
113       param_update_req.view(),
114       {SignalingChannel::Status::kSuccess, param_update_rsp.view()});
115 
116   EXPECT_TRUE(
117       cmd_handler()->SendConnectionParameterUpdateRequest(kIntervalMin,
118                                                           kIntervalMax,
119                                                           kPeripheralLatency,
120                                                           kTimeoutMult,
121                                                           std::move(rsp_cb)));
122   RunUntilIdle();
123   EXPECT_TRUE(cb_called);
124 }
125 
TEST_F(LowEnergyCommandHandlerTest,InboundConnParamsUpdateReqRspOk)126 TEST_F(LowEnergyCommandHandlerTest, InboundConnParamsUpdateReqRspOk) {
127   constexpr uint16_t kIntervalMin = 0;
128   constexpr uint16_t kIntervalMax = 1;
129   constexpr uint16_t kPeripheralLatency = 2;
130   constexpr uint16_t kTimeoutMult = 3;
131   StaticByteBuffer param_update_req(
132       // Interval Min
133       LowerBits(kIntervalMin),
134       UpperBits(kIntervalMin),
135       // Interval Max
136       LowerBits(kIntervalMax),
137       UpperBits(kIntervalMax),
138       // Peripheral Latency
139       LowerBits(kPeripheralLatency),
140       UpperBits(kPeripheralLatency),
141       // Timeout Multiplier
142       LowerBits(kTimeoutMult),
143       UpperBits(kTimeoutMult));
144 
145   auto param_update_rsp = StaticByteBuffer(
146       LowerBits(
147           static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)),
148       UpperBits(
149           static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)));
150 
151   LowEnergyCommandHandler::ConnectionParameterUpdateRequestCallback cb =
152       [&](uint16_t interval_min,
153           uint16_t interval_max,
154           uint16_t peripheral_latency,
155           uint16_t timeout_multiplier,
156           LowEnergyCommandHandler::ConnectionParameterUpdateResponder*
157               responder) {
158         EXPECT_EQ(kIntervalMin, interval_min);
159         EXPECT_EQ(kIntervalMax, interval_max);
160         EXPECT_EQ(kPeripheralLatency, peripheral_latency);
161         EXPECT_EQ(kTimeoutMult, timeout_multiplier);
162         responder->Send(ConnectionParameterUpdateResult::kRejected);
163       };
164 
165   cmd_handler()->ServeConnectionParameterUpdateRequest(std::move(cb));
166 
167   RETURN_IF_FATAL(fake_sig()->ReceiveExpect(
168       kConnectionParameterUpdateRequest, param_update_req, param_update_rsp));
169 }
170 
TEST_F(LowEnergyCommandHandlerTest,InboundConnParamsUpdateReqNotEnoughBytes)171 TEST_F(LowEnergyCommandHandlerTest, InboundConnParamsUpdateReqNotEnoughBytes) {
172   constexpr uint16_t kIntervalMin = 0;
173 
174   // Request is missing interval max, peripheral latency, and timeout multiplier
175   // fields.
176   auto param_update_req = StaticByteBuffer(
177       // Interval Min
178       LowerBits(kIntervalMin),
179       UpperBits(kIntervalMin));
180 
181   bool cb_called = false;
182   auto cb = [&](uint16_t interval_min,
183                 uint16_t interval_max,
184                 uint16_t peripheral_latency,
185                 uint16_t timeout_multiplier,
186                 auto responder) { cb_called = true; };
187 
188   cmd_handler()->ServeConnectionParameterUpdateRequest(std::move(cb));
189 
190   RETURN_IF_FATAL(fake_sig()->ReceiveExpectRejectNotUnderstood(
191       kConnectionParameterUpdateRequest, param_update_req));
192   EXPECT_FALSE(cb_called);
193 }
194 
195 }  // namespace bt::l2cap::internal
196