blob: 4f9b994aa9d0a8b84ac389376f9c3f08e99a45cc [file] [log] [blame]
// Copyright (c) 2012 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.
// This file provides tests for individual messages. It tests
// NetlinkMessageFactory's ability to create specific message types and it
// tests the various NetlinkMessage types' ability to parse those
// messages.
// This file tests the public interface to NetlinkManager.
#include "shill/netlink_manager.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "shill/mock_netlink_socket.h"
#include "shill/nl80211_message.h"
using base::Bind;
using base::Unretained;
using testing::_;
using testing::Invoke;
using testing::Return;
using testing::Test;
namespace shill {
namespace {
// These data blocks have been collected by shill using NetlinkManager while,
// simultaneously (and manually) comparing shill output with that of the 'iw'
// code from which it was derived. The test strings represent the raw packet
// data coming from the kernel. The comments above each of these strings is
// the markup that "iw" outputs for ech of these packets.
// These constants are consistent throughout the packets, below.
const uint16_t kNl80211FamilyId = 0x13;
// wlan0 (phy #0): disconnected (by AP) reason: 2: Previous authentication no
// longer valid
const unsigned char kNL80211_CMD_DISCONNECT[] = {
0x30, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x36, 0x00,
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x47, 0x00,
};
const char kGetFamilyCommandString[] = "CTRL_CMD_GETFAMILY";
} // namespace
bool MockNetlinkSocket::SendMessage(const ByteString &out_string) {
return true;
}
class NetlinkManagerTest : public Test {
public:
NetlinkManagerTest() : netlink_manager_(NetlinkManager::GetInstance()) {
netlink_manager_->message_types_[Nl80211Message::kMessageTypeString]
.family_id = kNl80211FamilyId;
netlink_manager_->message_factory_.AddFactoryMethod(
kNl80211FamilyId, Bind(&Nl80211Message::CreateMessage));
Nl80211Message::SetMessageType(
netlink_manager_->GetMessageType(Nl80211Message::kMessageTypeString));
}
~NetlinkManagerTest() {
// NetlinkManager is a singleton, the sock_ field *MUST* be cleared
// before "NetlinkManagerTest::socket_" gets invalidated, otherwise
// later tests will refer to a corrupted memory.
netlink_manager_->sock_ = NULL;
}
void SetupNetlinkManagerObject() {
EXPECT_NE(reinterpret_cast<NetlinkManager *>(NULL), netlink_manager_);
netlink_manager_->sock_ = &socket_;
EXPECT_TRUE(netlink_manager_->Init());
}
protected:
class MockHandler80211 {
public:
MockHandler80211() :
on_netlink_message_(base::Bind(&MockHandler80211::OnNetlinkMessage,
base::Unretained(this))) {}
MOCK_METHOD1(OnNetlinkMessage, void(const NetlinkMessage &msg));
const NetlinkManager::NetlinkMessageHandler &on_netlink_message() const {
return on_netlink_message_;
}
private:
NetlinkManager::NetlinkMessageHandler on_netlink_message_;
DISALLOW_COPY_AND_ASSIGN(MockHandler80211);
};
NetlinkManager *netlink_manager_;
MockNetlinkSocket socket_;
};
// TODO(wdg): Add a test for multi-part messages. crbug.com/224652
// TODO(wdg): Add a test for GetFaimily. crbug.com/224649
// TODO(wdg): Add a test for OnNewFamilyMessage. crbug.com/222486
// TODO(wdg): Add a test for GetMessageType
// TODO(wdg): Add a test for SubscribeToEvents (verify that it handles bad input
// appropriately, and that it calls NetlinkSocket::SubscribeToEvents if input
// is good.)
TEST_F(NetlinkManagerTest, BroadcastHandlerTest) {
SetupNetlinkManagerObject();
nlmsghdr *message = const_cast<nlmsghdr *>(
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISCONNECT));
MockHandler80211 handler1;
MockHandler80211 handler2;
// Simple, 1 handler, case.
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(1);
EXPECT_FALSE(
netlink_manager_->FindBroadcastHandler(handler1.on_netlink_message()));
netlink_manager_->AddBroadcastHandler(handler1.on_netlink_message());
EXPECT_TRUE(
netlink_manager_->FindBroadcastHandler(handler1.on_netlink_message()));
netlink_manager_->OnNlMessageReceived(message);
// Add a second handler.
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(1);
EXPECT_CALL(handler2, OnNetlinkMessage(_)).Times(1);
netlink_manager_->AddBroadcastHandler(handler2.on_netlink_message());
netlink_manager_->OnNlMessageReceived(message);
// Verify that a handler can't be added twice.
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(1);
EXPECT_CALL(handler2, OnNetlinkMessage(_)).Times(1);
netlink_manager_->AddBroadcastHandler(handler1.on_netlink_message());
netlink_manager_->OnNlMessageReceived(message);
// Check that we can remove a handler.
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(0);
EXPECT_CALL(handler2, OnNetlinkMessage(_)).Times(1);
EXPECT_TRUE(netlink_manager_->RemoveBroadcastHandler(
handler1.on_netlink_message()));
netlink_manager_->OnNlMessageReceived(message);
// Check that re-adding the handler goes smoothly.
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(1);
EXPECT_CALL(handler2, OnNetlinkMessage(_)).Times(1);
netlink_manager_->AddBroadcastHandler(handler1.on_netlink_message());
netlink_manager_->OnNlMessageReceived(message);
// Check that ClearBroadcastHandlers works.
netlink_manager_->ClearBroadcastHandlers();
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(0);
EXPECT_CALL(handler2, OnNetlinkMessage(_)).Times(0);
netlink_manager_->OnNlMessageReceived(message);
}
TEST_F(NetlinkManagerTest, MessageHandlerTest) {
// Setup.
SetupNetlinkManagerObject();
MockHandler80211 handler_broadcast;
EXPECT_TRUE(netlink_manager_->AddBroadcastHandler(
handler_broadcast.on_netlink_message()));
Nl80211Message sent_message_1(CTRL_CMD_GETFAMILY, kGetFamilyCommandString);
MockHandler80211 handler_sent_1;
Nl80211Message sent_message_2(CTRL_CMD_GETFAMILY, kGetFamilyCommandString);
MockHandler80211 handler_sent_2;
// Set up the received message as a response to sent_message_1.
scoped_array<unsigned char> message_memory(
new unsigned char[sizeof(kNL80211_CMD_DISCONNECT)]);
memcpy(message_memory.get(), kNL80211_CMD_DISCONNECT,
sizeof(kNL80211_CMD_DISCONNECT));
nlmsghdr *received_message =
reinterpret_cast<nlmsghdr *>(message_memory.get());
// Now, we can start the actual test...
// Verify that generic handler gets called for a message when no
// message-specific handler has been installed.
EXPECT_CALL(handler_broadcast, OnNetlinkMessage(_)).Times(1);
netlink_manager_->OnNlMessageReceived(received_message);
// Send the message and give our handler. Verify that we get called back.
EXPECT_TRUE(netlink_manager_->SendMessage(
&sent_message_1, handler_sent_1.on_netlink_message()));
// Make it appear that this message is in response to our sent message.
received_message->nlmsg_seq = socket_.GetLastSequenceNumber();
EXPECT_CALL(handler_sent_1, OnNetlinkMessage(_)).Times(1);
netlink_manager_->OnNlMessageReceived(received_message);
// Verify that broadcast handler is called for the message after the
// message-specific handler is called once.
EXPECT_CALL(handler_broadcast, OnNetlinkMessage(_)).Times(1);
netlink_manager_->OnNlMessageReceived(received_message);
// Install and then uninstall message-specific handler; verify broadcast
// handler is called on message receipt.
EXPECT_TRUE(netlink_manager_->SendMessage(
&sent_message_1, handler_sent_1.on_netlink_message()));
received_message->nlmsg_seq = socket_.GetLastSequenceNumber();
EXPECT_TRUE(netlink_manager_->RemoveMessageHandler(sent_message_1));
EXPECT_CALL(handler_broadcast, OnNetlinkMessage(_)).Times(1);
netlink_manager_->OnNlMessageReceived(received_message);
// Install handler for different message; verify that broadcast handler is
// called for _this_ message.
EXPECT_TRUE(netlink_manager_->SendMessage(
&sent_message_2, handler_sent_2.on_netlink_message()));
EXPECT_CALL(handler_broadcast, OnNetlinkMessage(_)).Times(1);
netlink_manager_->OnNlMessageReceived(received_message);
// Change the ID for the message to that of the second handler; verify that
// the appropriate handler is called for _that_ message.
received_message->nlmsg_seq = socket_.GetLastSequenceNumber();
EXPECT_CALL(handler_sent_2, OnNetlinkMessage(_)).Times(1);
netlink_manager_->OnNlMessageReceived(received_message);
}
} // namespace shill