blob: 1668c4dff7048e1b69b563e1adc93042d4cd3f64 [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.
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mm/mm-modem.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include "shill/cellular.h"
#include "shill/cellular_capability_gsm.h"
#include "shill/event_dispatcher.h"
#include "shill/manager.h"
#include "shill/mock_control.h"
#include "shill/mock_device_info.h"
#include "shill/mock_dbus_properties_proxy.h"
#include "shill/mock_glib.h"
#include "shill/mock_manager.h"
#include "shill/mock_sockets.h"
#include "shill/modem.h"
#include "shill/proxy_factory.h"
#include "shill/rtnl_handler.h"
using std::string;
using std::vector;
using testing::_;
using testing::DoAll;
using testing::Return;
using testing::SetArgumentPointee;
using testing::StrictMock;
using testing::Test;
namespace shill {
namespace {
const int kTestInterfaceIndex = 5;
ACTION(SetInterfaceIndex) {
if (arg2) {
reinterpret_cast<struct ifreq *>(arg2)->ifr_ifindex = kTestInterfaceIndex;
}
}
} // namespace
class ModemTest : public Test {
public:
ModemTest()
: manager_(&control_interface_, &dispatcher_, &glib_),
proxy_(new MockDBusPropertiesProxy()),
proxy_factory_(this),
modem_(kOwner,
kPath,
&control_interface_,
&dispatcher_,
&manager_,
NULL) {}
virtual void SetUp();
virtual void TearDown();
void SetSockets(Sockets *sockets) {
RTNLHandler::GetInstance()->sockets_ = sockets;
}
protected:
class TestProxyFactory : public ProxyFactory {
public:
explicit TestProxyFactory(ModemTest *test) : test_(test) {}
virtual DBusPropertiesProxyInterface *CreateDBusPropertiesProxy(
DBusPropertiesProxyDelegate */*delegate*/,
const string &/*path*/,
const string &/*service*/) {
return test_->proxy_.release();
}
private:
ModemTest *test_;
};
static const char kOwner[];
static const char kPath[];
CellularCapabilityGSM *GetCapabilityGSM() {
return dynamic_cast<CellularCapabilityGSM *>(
modem_.device_->capability_.get());
}
MockGLib glib_;
MockControl control_interface_;
EventDispatcher dispatcher_;
MockManager manager_;
scoped_ptr<MockDBusPropertiesProxy> proxy_;
TestProxyFactory proxy_factory_;
Modem modem_;
StrictMock<MockSockets> sockets_;
};
const char ModemTest::kOwner[] = ":1.18";
const char ModemTest::kPath[] = "/org/chromium/ModemManager/Gobi/0";
void ModemTest::SetUp() {
EXPECT_EQ(kOwner, modem_.owner_);
EXPECT_EQ(kPath, modem_.path_);
modem_.proxy_factory_ = &proxy_factory_;
SetSockets(&sockets_);
}
void ModemTest::TearDown() {
modem_.proxy_factory_ = NULL;
SetSockets(NULL);
}
TEST_F(ModemTest, Init) {
DBusPropertiesMap props;
props[Modem::kPropertyIPMethod].writer().append_uint32(
MM_MODEM_IP_METHOD_DHCP);
props[Modem::kPropertyLinkName].writer().append_string("usb1");
EXPECT_CALL(*proxy_, GetAll(MM_MODEM_INTERFACE)).WillOnce(Return(props));
EXPECT_TRUE(modem_.task_factory_.empty());
modem_.Init();
EXPECT_FALSE(modem_.task_factory_.empty());
EXPECT_CALL(sockets_, Socket(PF_INET, SOCK_DGRAM, 0)).WillOnce(Return(-1));
dispatcher_.DispatchPendingEvents();
}
TEST_F(ModemTest, CreateDeviceFromProperties) {
DBusPropertiesMap props;
modem_.CreateDeviceFromProperties(props);
EXPECT_FALSE(modem_.device_.get());
props[Modem::kPropertyIPMethod].writer().append_uint32(
MM_MODEM_IP_METHOD_PPP);
modem_.CreateDeviceFromProperties(props);
EXPECT_FALSE(modem_.device_.get());
props.erase(Modem::kPropertyIPMethod);
props[Modem::kPropertyIPMethod].writer().append_uint32(
MM_MODEM_IP_METHOD_DHCP);
modem_.CreateDeviceFromProperties(props);
EXPECT_FALSE(modem_.device_.get());
static const char kLinkName[] = "usb0";
static const unsigned char kAddress[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
const int kTestSocket = 10;
props[Modem::kPropertyLinkName].writer().append_string(kLinkName);
EXPECT_CALL(sockets_, Socket(PF_INET, SOCK_DGRAM, 0))
.Times(2)
.WillRepeatedly(Return(kTestSocket));
EXPECT_CALL(sockets_, Ioctl(kTestSocket, SIOCGIFINDEX, _))
.WillRepeatedly(DoAll(SetInterfaceIndex(), Return(0)));
EXPECT_CALL(sockets_, Close(kTestSocket))
.WillRepeatedly(Return(0));
ByteString expected_address(kAddress, arraysize(kAddress));
MockDeviceInfo info_(&control_interface_, &dispatcher_, &manager_);
EXPECT_CALL(info_, GetMACAddress(kTestInterfaceIndex, _))
.WillOnce(DoAll(SetArgumentPointee<1>(expected_address), Return(true)))
.WillOnce(DoAll(SetArgumentPointee<1>(expected_address), Return(true)));
EXPECT_CALL(info_, GetDevice(kTestInterfaceIndex))
.WillRepeatedly(Return(modem_.device_));
EXPECT_CALL(manager_, device_info()).WillRepeatedly(Return(&info_));
modem_.CreateDeviceFromProperties(props);
EXPECT_FALSE(modem_.device_.get());
props[Modem::kPropertyType].writer().append_uint32(MM_MODEM_TYPE_GSM);
props[Modem::kPropertyState].writer().append_uint32(
Cellular::kModemStateDisabled);
static const char kLockType[] = "sim-pin";
const int kRetries = 2;
props[CellularCapabilityGSM::kPropertyUnlockRequired].writer().append_string(
kLockType);
props[CellularCapabilityGSM::kPropertyUnlockRetries].writer().append_uint32(
kRetries);
modem_.CreateDeviceFromProperties(props);
ASSERT_TRUE(modem_.device_.get());
EXPECT_EQ(kLinkName, modem_.device_->link_name());
EXPECT_EQ(kTestInterfaceIndex, modem_.device_->interface_index());
EXPECT_EQ(Cellular::kModemStateDisabled, modem_.device_->modem_state());
EXPECT_EQ(kLockType, GetCapabilityGSM()->sim_lock_type());
EXPECT_EQ(kRetries, GetCapabilityGSM()->sim_lock_retries_left());
vector<DeviceRefPtr> devices;
manager_.FilterByTechnology(Technology::kCellular, &devices);
EXPECT_EQ(1, devices.size());
EXPECT_TRUE(devices[0].get() == modem_.device_.get());
}
} // namespace shill