| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/net/rtnl_handler.h" |
| |
| #include <limits> |
| #include <string> |
| #include <utility> |
| |
| #include <gtest/gtest.h> |
| #include <net/if.h> |
| #include <sys/socket.h> |
| #include <linux/netlink.h> // Needs typedefs from sys/socket.h. |
| #include <linux/rtnetlink.h> |
| #include <sys/ioctl.h> |
| |
| #include <base/bind.h> |
| #include <base/message_loop/message_loop.h> |
| #include <base/run_loop.h> |
| |
| #include "shill/mock_log.h" |
| #include "shill/net/mock_io_handler_factory.h" |
| #include "shill/net/mock_sockets.h" |
| #include "shill/net/rtnl_message.h" |
| |
| using base::Bind; |
| using base::Callback; |
| using base::Unretained; |
| using std::string; |
| using testing::_; |
| using testing::A; |
| using testing::DoAll; |
| using testing::ElementsAre; |
| using testing::HasSubstr; |
| using testing::Return; |
| using testing::ReturnArg; |
| using testing::StrictMock; |
| using testing::Test; |
| using testing::AtLeast; |
| |
| namespace shill { |
| |
| namespace { |
| |
| const int kTestInterfaceIndex = 4; |
| |
| ACTION(SetInterfaceIndex) { |
| if (arg2) { |
| reinterpret_cast<struct ifreq*>(arg2)->ifr_ifindex = kTestInterfaceIndex; |
| } |
| } |
| |
| MATCHER_P(MessageType, message_type, "") { |
| return std::get<0>(arg).type() == message_type; |
| } |
| |
| std::unique_ptr<RTNLMessage> CreateDummyMessage() { |
| return std::make_unique<RTNLMessage>(RTNLMessage::kTypeLink, |
| RTNLMessage::kModeGet, 0, 0, 0, 0, |
| IPAddress::kFamilyUnknown); |
| } |
| |
| } // namespace |
| |
| class RTNLHandlerTest : public Test { |
| public: |
| RTNLHandlerTest() |
| : sockets_(new StrictMock<MockSockets>()), |
| callback_(Bind(&RTNLHandlerTest::HandlerCallback, Unretained(this))) {} |
| |
| void SetUp() override { |
| RTNLHandler::GetInstance()->io_handler_factory_ = &io_handler_factory_; |
| RTNLHandler::GetInstance()->sockets_.reset(sockets_); |
| } |
| |
| void TearDown() override { RTNLHandler::GetInstance()->Stop(); } |
| |
| uint32_t GetRequestSequence() { |
| return RTNLHandler::GetInstance()->request_sequence_; |
| } |
| |
| void SetRequestSequence(uint32_t sequence) { |
| RTNLHandler::GetInstance()->request_sequence_ = sequence; |
| } |
| |
| bool SendMessageWithErrorMask(std::unique_ptr<RTNLMessage> message, |
| const RTNLHandler::ErrorMask& error_mask, |
| uint32_t* msg_seq) { |
| return RTNLHandler::GetInstance()->SendMessageWithErrorMask( |
| std::move(message), error_mask, msg_seq); |
| } |
| |
| bool IsSequenceInErrorMaskWindow(uint32_t sequence) { |
| return RTNLHandler::GetInstance()->IsSequenceInErrorMaskWindow(sequence); |
| } |
| |
| void SetErrorMask(uint32_t sequence, |
| const RTNLHandler::ErrorMask& error_mask) { |
| return RTNLHandler::GetInstance()->SetErrorMask(sequence, error_mask); |
| } |
| |
| RTNLHandler::ErrorMask GetAndClearErrorMask(uint32_t sequence) { |
| return RTNLHandler::GetInstance()->GetAndClearErrorMask(sequence); |
| } |
| |
| int GetErrorWindowSize() { return RTNLHandler::kErrorWindowSize; } |
| |
| void StoreRequest(std::unique_ptr<RTNLMessage> request) { |
| RTNLHandler::GetInstance()->StoreRequest(std::move(request)); |
| } |
| |
| std::unique_ptr<RTNLMessage> PopStoredRequest(uint32_t seq) { |
| return RTNLHandler::GetInstance()->PopStoredRequest(seq); |
| } |
| |
| uint32_t CalculateStoredRequestWindowSize() { |
| return RTNLHandler::GetInstance()->CalculateStoredRequestWindowSize(); |
| } |
| |
| uint32_t stored_request_window_size() { |
| return RTNLHandler::GetInstance()->kStoredRequestWindowSize; |
| } |
| |
| uint32_t oldest_request_sequence() { |
| return RTNLHandler::GetInstance()->oldest_request_sequence_; |
| } |
| |
| MOCK_METHOD(void, HandlerCallback, (const RTNLMessage&)); |
| |
| protected: |
| static const int kTestSocket; |
| static const int kTestDeviceIndex; |
| static const char kTestDeviceName[]; |
| |
| void AddLink(); |
| void AddNeighbor(); |
| void StartRTNLHandler(); |
| void StopRTNLHandler(); |
| void ReturnError(uint32_t sequence, int error_number); |
| |
| MockSockets* sockets_; |
| StrictMock<MockIOHandlerFactory> io_handler_factory_; |
| Callback<void(const RTNLMessage&)> callback_; |
| |
| private: |
| base::MessageLoop message_loop_; |
| }; |
| |
| const int RTNLHandlerTest::kTestSocket = 123; |
| const int RTNLHandlerTest::kTestDeviceIndex = 123456; |
| const char RTNLHandlerTest::kTestDeviceName[] = "test-device"; |
| |
| void RTNLHandlerTest::StartRTNLHandler() { |
| EXPECT_CALL(*sockets_, |
| Socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE)) |
| .WillOnce(Return(kTestSocket)); |
| EXPECT_CALL(*sockets_, Bind(kTestSocket, _, sizeof(sockaddr_nl))) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(*sockets_, SetReceiveBuffer(kTestSocket, _)) |
| .Times(AtLeast(1)) |
| .WillRepeatedly(Return(0)); |
| EXPECT_CALL(io_handler_factory_, CreateIOInputHandler(kTestSocket, _, _)); |
| RTNLHandler::GetInstance()->Start(0); |
| } |
| |
| void RTNLHandlerTest::StopRTNLHandler() { |
| EXPECT_CALL(*sockets_, Close(kTestSocket)).WillOnce(Return(0)); |
| RTNLHandler::GetInstance()->Stop(); |
| } |
| |
| void RTNLHandlerTest::AddLink() { |
| RTNLMessage message(RTNLMessage::kTypeLink, RTNLMessage::kModeAdd, 0, 0, 0, |
| kTestDeviceIndex, IPAddress::kFamilyIPv4); |
| message.SetAttribute(static_cast<uint16_t>(IFLA_IFNAME), |
| ByteString(string(kTestDeviceName), true)); |
| ByteString b(message.Encode()); |
| InputData data(b.GetData(), b.GetLength()); |
| RTNLHandler::GetInstance()->ParseRTNL(&data); |
| } |
| |
| void RTNLHandlerTest::AddNeighbor() { |
| RTNLMessage message(RTNLMessage::kTypeNeighbor, RTNLMessage::kModeAdd, 0, 0, |
| 0, kTestDeviceIndex, IPAddress::kFamilyIPv4); |
| ByteString encoded(message.Encode()); |
| InputData data(encoded.GetData(), encoded.GetLength()); |
| RTNLHandler::GetInstance()->ParseRTNL(&data); |
| } |
| |
| void RTNLHandlerTest::ReturnError(uint32_t sequence, int error_number) { |
| struct { |
| struct nlmsghdr hdr; |
| struct nlmsgerr err; |
| } errmsg; |
| |
| memset(&errmsg, 0, sizeof(errmsg)); |
| errmsg.hdr.nlmsg_type = NLMSG_ERROR; |
| errmsg.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(errmsg.err)); |
| errmsg.hdr.nlmsg_seq = sequence; |
| errmsg.err.error = -error_number; |
| |
| InputData data(reinterpret_cast<unsigned char*>(&errmsg), sizeof(errmsg)); |
| RTNLHandler::GetInstance()->ParseRTNL(&data); |
| } |
| |
| TEST_F(RTNLHandlerTest, ListenersInvoked) { |
| StartRTNLHandler(); |
| |
| std::unique_ptr<RTNLListener> link_listener( |
| new RTNLListener(RTNLHandler::kRequestLink, callback_)); |
| std::unique_ptr<RTNLListener> neighbor_listener( |
| new RTNLListener(RTNLHandler::kRequestNeighbor, callback_)); |
| |
| EXPECT_CALL(*this, HandlerCallback(A<const RTNLMessage&>())) |
| .With(MessageType(RTNLMessage::kTypeLink)); |
| EXPECT_CALL(*this, HandlerCallback(A<const RTNLMessage&>())) |
| .With(MessageType(RTNLMessage::kTypeNeighbor)); |
| |
| AddLink(); |
| AddNeighbor(); |
| |
| StopRTNLHandler(); |
| } |
| |
| TEST_F(RTNLHandlerTest, GetInterfaceName) { |
| EXPECT_EQ(-1, RTNLHandler::GetInstance()->GetInterfaceIndex("")); |
| { |
| struct ifreq ifr; |
| string name(sizeof(ifr.ifr_name), 'x'); |
| EXPECT_EQ(-1, RTNLHandler::GetInstance()->GetInterfaceIndex(name)); |
| } |
| |
| const int kTestSocket = 123; |
| EXPECT_CALL(*sockets_, Socket(PF_INET, _, 0)) |
| .Times(3) |
| .WillOnce(Return(-1)) |
| .WillRepeatedly(Return(kTestSocket)); |
| EXPECT_CALL(*sockets_, Ioctl(kTestSocket, SIOCGIFINDEX, _)) |
| .WillOnce(Return(-1)) |
| .WillOnce(DoAll(SetInterfaceIndex(), Return(0))); |
| EXPECT_CALL(*sockets_, Close(kTestSocket)).Times(2).WillRepeatedly(Return(0)); |
| EXPECT_EQ(-1, RTNLHandler::GetInstance()->GetInterfaceIndex("eth0")); |
| EXPECT_EQ(-1, RTNLHandler::GetInstance()->GetInterfaceIndex("wlan0")); |
| EXPECT_EQ(kTestInterfaceIndex, |
| RTNLHandler::GetInstance()->GetInterfaceIndex("usb0")); |
| } |
| |
| TEST_F(RTNLHandlerTest, IsSequenceInErrorMaskWindow) { |
| const uint32_t kRequestSequence = 1234; |
| SetRequestSequence(kRequestSequence); |
| EXPECT_FALSE(IsSequenceInErrorMaskWindow(kRequestSequence + 1)); |
| EXPECT_TRUE(IsSequenceInErrorMaskWindow(kRequestSequence)); |
| EXPECT_TRUE(IsSequenceInErrorMaskWindow(kRequestSequence - 1)); |
| EXPECT_TRUE( |
| IsSequenceInErrorMaskWindow(kRequestSequence - GetErrorWindowSize() + 1)); |
| EXPECT_FALSE( |
| IsSequenceInErrorMaskWindow(kRequestSequence - GetErrorWindowSize())); |
| EXPECT_FALSE( |
| IsSequenceInErrorMaskWindow(kRequestSequence - GetErrorWindowSize() - 1)); |
| } |
| |
| TEST_F(RTNLHandlerTest, SendMessageReturnsErrorAndAdvancesSequenceNumber) { |
| StartRTNLHandler(); |
| const uint32_t kSequenceNumber = 123; |
| SetRequestSequence(kSequenceNumber); |
| EXPECT_CALL(*sockets_, Send(kTestSocket, _, _, 0)).WillOnce(Return(-1)); |
| uint32_t seq = 0; |
| EXPECT_FALSE( |
| RTNLHandler::GetInstance()->SendMessage(CreateDummyMessage(), &seq)); |
| |
| // |seq| should not be set if there was a failure. |
| EXPECT_EQ(seq, 0); |
| // Sequence number should still increment even if there was a failure. |
| EXPECT_EQ(kSequenceNumber + 1, GetRequestSequence()); |
| StopRTNLHandler(); |
| } |
| |
| TEST_F(RTNLHandlerTest, SendMessageWithEmptyMask) { |
| StartRTNLHandler(); |
| const uint32_t kSequenceNumber = 123; |
| SetRequestSequence(kSequenceNumber); |
| SetErrorMask(kSequenceNumber, {1, 2, 3}); |
| EXPECT_CALL(*sockets_, Send(kTestSocket, _, _, 0)).WillOnce(ReturnArg<2>()); |
| uint32_t seq; |
| EXPECT_TRUE(SendMessageWithErrorMask(CreateDummyMessage(), {}, &seq)); |
| EXPECT_EQ(seq, kSequenceNumber); |
| EXPECT_EQ(kSequenceNumber + 1, GetRequestSequence()); |
| EXPECT_TRUE(GetAndClearErrorMask(kSequenceNumber).empty()); |
| StopRTNLHandler(); |
| } |
| |
| TEST_F(RTNLHandlerTest, SendMessageWithErrorMask) { |
| StartRTNLHandler(); |
| const uint32_t kSequenceNumber = 123; |
| SetRequestSequence(kSequenceNumber); |
| EXPECT_CALL(*sockets_, Send(kTestSocket, _, _, 0)).WillOnce(ReturnArg<2>()); |
| uint32_t seq; |
| EXPECT_TRUE(SendMessageWithErrorMask(CreateDummyMessage(), {1, 2, 3}, &seq)); |
| EXPECT_EQ(seq, kSequenceNumber); |
| EXPECT_EQ(kSequenceNumber + 1, GetRequestSequence()); |
| EXPECT_TRUE(GetAndClearErrorMask(kSequenceNumber + 1).empty()); |
| EXPECT_THAT(GetAndClearErrorMask(kSequenceNumber), ElementsAre(1, 2, 3)); |
| |
| // A second call to GetAndClearErrorMask() returns an empty vector. |
| EXPECT_TRUE(GetAndClearErrorMask(kSequenceNumber).empty()); |
| StopRTNLHandler(); |
| } |
| |
| TEST_F(RTNLHandlerTest, SendMessageInferredErrorMasks) { |
| struct { |
| RTNLMessage::Type type; |
| RTNLMessage::Mode mode; |
| RTNLHandler::ErrorMask mask; |
| } expectations[] = { |
| {RTNLMessage::kTypeLink, RTNLMessage::kModeGet, {}}, |
| {RTNLMessage::kTypeLink, RTNLMessage::kModeAdd, {EEXIST}}, |
| {RTNLMessage::kTypeLink, RTNLMessage::kModeDelete, {ESRCH, ENODEV}}, |
| {RTNLMessage::kTypeAddress, |
| RTNLMessage::kModeDelete, |
| {ESRCH, ENODEV, EADDRNOTAVAIL}}}; |
| const uint32_t kSequenceNumber = 123; |
| EXPECT_CALL(*sockets_, Send(_, _, _, 0)).WillRepeatedly(ReturnArg<2>()); |
| for (const auto& expectation : expectations) { |
| SetRequestSequence(kSequenceNumber); |
| auto message = |
| std::make_unique<RTNLMessage>(expectation.type, expectation.mode, 0, 0, |
| 0, 0, IPAddress::kFamilyUnknown); |
| EXPECT_TRUE( |
| RTNLHandler::GetInstance()->SendMessage(std::move(message), nullptr)); |
| EXPECT_EQ(expectation.mask, GetAndClearErrorMask(kSequenceNumber)); |
| } |
| } |
| |
| TEST_F(RTNLHandlerTest, MaskedError) { |
| StartRTNLHandler(); |
| const uint32_t kSequenceNumber = 123; |
| SetRequestSequence(kSequenceNumber); |
| EXPECT_CALL(*sockets_, Send(kTestSocket, _, _, 0)).WillOnce(ReturnArg<2>()); |
| uint32_t seq; |
| EXPECT_TRUE(SendMessageWithErrorMask(CreateDummyMessage(), {1, 2, 3}, &seq)); |
| EXPECT_EQ(seq, kSequenceNumber); |
| ScopedMockLog log; |
| |
| // This error will be not be masked since this sequence number has no mask. |
| EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr("error 1"))).Times(1); |
| ReturnError(kSequenceNumber - 1, 1); |
| |
| // This error will be masked. |
| EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr("error 2"))).Times(0); |
| ReturnError(kSequenceNumber, 2); |
| |
| // This second error will be not be masked since the error mask was removed. |
| EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr("error 3"))).Times(1); |
| ReturnError(kSequenceNumber, 3); |
| |
| StopRTNLHandler(); |
| } |
| |
| TEST_F(RTNLHandlerTest, BasicStoreRequest) { |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| |
| const uint32_t kSequenceNumber1 = 123; |
| auto request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber1); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber2 = 124; |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber2); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 2); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber3 = |
| kSequenceNumber1 + stored_request_window_size() - 1; |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber3); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), stored_request_window_size()); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber1), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber1), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), |
| stored_request_window_size() - 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber2); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber2), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber2), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber3); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| } |
| |
| TEST_F(RTNLHandlerTest, StoreRequestLargerThanWindow) { |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| |
| const uint32_t kSequenceNumber1 = 123; |
| auto request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber1); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber2 = 124; |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber2); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 2); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber3 = |
| kSequenceNumber1 + stored_request_window_size(); |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber3); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), stored_request_window_size()); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber2); |
| |
| const uint32_t kSequenceNumber4 = |
| kSequenceNumber2 + stored_request_window_size(); |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber4); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 2); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber3); |
| |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber1), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber2), nullptr); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber4), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber4), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| } |
| |
| TEST_F(RTNLHandlerTest, OverflowStoreRequest) { |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| |
| const uint32_t kSequenceNumber1 = std::numeric_limits<uint32_t>::max(); |
| auto request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber1); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber2 = kSequenceNumber1 + 1; |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber2); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 2); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber3 = |
| kSequenceNumber1 + stored_request_window_size() - 1; |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber3); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), stored_request_window_size()); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber1), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber1), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), |
| stored_request_window_size() - 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber2); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber2), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber2), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber3); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| } |
| |
| TEST_F(RTNLHandlerTest, OverflowStoreRequestLargerThanWindow) { |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| |
| const uint32_t kSequenceNumber1 = std::numeric_limits<uint32_t>::max(); |
| auto request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber1); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber2 = kSequenceNumber1 + 1; |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber2); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 2); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber1); |
| |
| const uint32_t kSequenceNumber3 = |
| kSequenceNumber1 + stored_request_window_size(); |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber3); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), stored_request_window_size()); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber2); |
| |
| const uint32_t kSequenceNumber4 = |
| kSequenceNumber2 + stored_request_window_size(); |
| request = std::make_unique<RTNLMessage>(); |
| request->set_seq(kSequenceNumber4); |
| StoreRequest(std::move(request)); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 2); |
| EXPECT_EQ(oldest_request_sequence(), kSequenceNumber3); |
| |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber1), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber2), nullptr); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber3), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 1); |
| |
| EXPECT_NE(PopStoredRequest(kSequenceNumber4), nullptr); |
| EXPECT_EQ(PopStoredRequest(kSequenceNumber4), nullptr); |
| EXPECT_EQ(CalculateStoredRequestWindowSize(), 0); |
| } |
| |
| TEST_F(RTNLHandlerTest, SetInterfaceMac) { |
| StartRTNLHandler(); |
| constexpr uint32_t kSequenceNumber = 123456; |
| constexpr int32_t kErrorNumber = 115; |
| SetRequestSequence(kSequenceNumber); |
| EXPECT_CALL(*sockets_, Send(kTestSocket, _, _, 0)).WillOnce(ReturnArg<2>()); |
| |
| base::RunLoop run_loop; |
| |
| RTNLHandler::GetInstance()->SetInterfaceMac( |
| 3, ByteString::CreateFromHexString("abcdef123456"), |
| base::BindOnce( |
| [](base::Closure callback, int32_t expected_error, int32_t error) { |
| EXPECT_EQ(expected_error, error); |
| callback.Run(); |
| }, |
| run_loop.QuitClosure(), kErrorNumber)); |
| |
| ReturnError(kSequenceNumber, kErrorNumber); |
| |
| run_loop.Run(); |
| |
| StopRTNLHandler(); |
| } |
| |
| } // namespace shill |