Home | History | Annotate | Download | only in cellular
      1 //
      2 // Copyright (C) 2012 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/cellular/modem.h"
     18 
     19 #include <vector>
     20 
     21 #include <base/strings/stringprintf.h>
     22 #include <gmock/gmock.h>
     23 #include <gtest/gtest.h>
     24 #include <mm/mm-modem.h>
     25 #include <net/if.h>
     26 #include <sys/ioctl.h>
     27 
     28 #include "shill/cellular/cellular.h"
     29 #include "shill/cellular/cellular_capability_gsm.h"
     30 #include "shill/cellular/mock_cellular.h"
     31 #include "shill/cellular/mock_modem.h"
     32 #include "shill/cellular/mock_modem_info.h"
     33 #include "shill/manager.h"
     34 #include "shill/mock_device_info.h"
     35 #include "shill/net/mock_rtnl_handler.h"
     36 #include "shill/net/rtnl_handler.h"
     37 #include "shill/test_event_dispatcher.h"
     38 
     39 using std::string;
     40 using std::vector;
     41 using testing::_;
     42 using testing::AnyNumber;
     43 using testing::DoAll;
     44 using testing::Return;
     45 using testing::SetArgumentPointee;
     46 using testing::StrEq;
     47 using testing::StrictMock;
     48 using testing::Test;
     49 
     50 namespace shill {
     51 
     52 namespace {
     53 
     54 const int kTestInterfaceIndex = 5;
     55 const char kLinkName[] = "usb0";
     56 const char kService[] = "org.chromium.ModemManager";
     57 const char kPath[] = "/org/chromium/ModemManager/Gobi/0";
     58 const unsigned char kAddress[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
     59 const char kAddressAsString[] = "000102030405";
     60 
     61 }  // namespace
     62 
     63 class ModemTest : public Test {
     64  public:
     65   ModemTest()
     66       : modem_info_(nullptr, &dispatcher_, nullptr, nullptr),
     67         device_info_(modem_info_.control_interface(), modem_info_.dispatcher(),
     68                      modem_info_.metrics(), modem_info_.manager()),
     69         modem_(
     70             new StrictModem(
     71                 kService,
     72                 kPath,
     73                 &modem_info_,
     74                 nullptr)) {}
     75   virtual void SetUp();
     76   virtual void TearDown();
     77 
     78   void ReplaceSingletons() {
     79     modem_->rtnl_handler_ = &rtnl_handler_;
     80   }
     81 
     82  protected:
     83   EventDispatcherForTest dispatcher_;
     84   MockModemInfo modem_info_;
     85   MockDeviceInfo device_info_;
     86   std::unique_ptr<StrictModem> modem_;
     87   MockRTNLHandler rtnl_handler_;
     88   ByteString expected_address_;
     89 };
     90 
     91 void ModemTest::SetUp() {
     92   EXPECT_EQ(kService, modem_->service_);
     93   EXPECT_EQ(kPath, modem_->path_);
     94   ReplaceSingletons();
     95   expected_address_ = ByteString(kAddress, arraysize(kAddress));
     96 
     97   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(kLinkName)).
     98       WillRepeatedly(Return(kTestInterfaceIndex));
     99 
    100   EXPECT_CALL(*modem_info_.mock_manager(), device_info())
    101       .WillRepeatedly(Return(&device_info_));
    102 }
    103 
    104 void ModemTest::TearDown() {
    105   modem_.reset();
    106 }
    107 
    108 MATCHER_P2(HasPropertyWithValueU32, key, value, "") {
    109   return arg.ContainsUint(key) && value == arg.GetUint(key);
    110 }
    111 
    112 TEST_F(ModemTest, PendingDevicePropertiesAndCreate) {
    113   static const char kSentinel[] = "sentinel";
    114   static const uint32_t kSentinelValue = 17;
    115 
    116   InterfaceToProperties properties;
    117   properties[MM_MODEM_INTERFACE].SetUint(kSentinel, kSentinelValue);
    118 
    119   EXPECT_CALL(*modem_, GetLinkName(_, _)).WillRepeatedly(DoAll(
    120       SetArgumentPointee<1>(string(kLinkName)),
    121       Return(true)));
    122   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(StrEq(kLinkName))).
    123       WillRepeatedly(Return(kTestInterfaceIndex));
    124 
    125   // The first time we call CreateDeviceFromModemProperties,
    126   // GetMACAddress will fail.
    127   EXPECT_CALL(device_info_, GetMACAddress(kTestInterfaceIndex, _)).
    128       WillOnce(Return(false));
    129   EXPECT_CALL(*modem_, GetModemInterface()).
    130       WillRepeatedly(Return(MM_MODEM_INTERFACE));
    131   modem_->CreateDeviceFromModemProperties(properties);
    132   EXPECT_FALSE(modem_->device_.get());
    133 
    134   // On the second time, we allow GetMACAddress to succeed.  Now we
    135   // expect a device to be built
    136   EXPECT_CALL(device_info_, GetMACAddress(kTestInterfaceIndex, _)).
    137       WillOnce(DoAll(SetArgumentPointee<1>(expected_address_),
    138                      Return(true)));
    139 
    140   // modem will take ownership
    141   MockCellular* cellular = new MockCellular(
    142       &modem_info_,
    143       kLinkName,
    144       kAddressAsString,
    145       kTestInterfaceIndex,
    146       Cellular::kTypeCDMA,
    147       kService,
    148       kPath);
    149 
    150   EXPECT_CALL(*modem_,
    151               ConstructCellular(StrEq(kLinkName),
    152                                 StrEq(kAddressAsString),
    153                                 kTestInterfaceIndex)).
    154       WillOnce(Return(cellular));
    155 
    156   EXPECT_CALL(*cellular, OnPropertiesChanged(
    157       _,
    158       HasPropertyWithValueU32(kSentinel, kSentinelValue),
    159       _));
    160   EXPECT_CALL(device_info_, RegisterDevice(_));
    161   modem_->OnDeviceInfoAvailable(kLinkName);
    162 
    163   EXPECT_TRUE(modem_->device_.get());
    164 
    165   // Add expectations for the eventual |modem_| destruction.
    166   EXPECT_CALL(*cellular, DestroyService());
    167   EXPECT_CALL(device_info_, DeregisterDevice(_));
    168 }
    169 
    170 TEST_F(ModemTest, EarlyDeviceProperties) {
    171   // OnDeviceInfoAvailable called before
    172   // CreateDeviceFromModemProperties: Do nothing
    173   modem_->OnDeviceInfoAvailable(kLinkName);
    174   EXPECT_FALSE(modem_->device_.get());
    175 }
    176 
    177 TEST_F(ModemTest, CreateDeviceEarlyFailures) {
    178   InterfaceToProperties properties;
    179 
    180   EXPECT_CALL(*modem_, ConstructCellular(_, _, _)).Times(0);
    181   EXPECT_CALL(*modem_, GetModemInterface()).
    182       WillRepeatedly(Return(MM_MODEM_INTERFACE));
    183 
    184   // No modem interface properties:  no device created
    185   modem_->CreateDeviceFromModemProperties(properties);
    186   EXPECT_FALSE(modem_->device_.get());
    187 
    188   properties[MM_MODEM_INTERFACE] = KeyValueStore();
    189 
    190   // Link name, but no ifindex: no device created
    191   EXPECT_CALL(*modem_, GetLinkName(_, _)).WillOnce(DoAll(
    192       SetArgumentPointee<1>(string(kLinkName)),
    193       Return(true)));
    194   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(StrEq(kLinkName))).WillOnce(
    195       Return(-1));
    196   modem_->CreateDeviceFromModemProperties(properties);
    197   EXPECT_FALSE(modem_->device_.get());
    198 
    199   // The params are good, but the device is blacklisted.
    200   EXPECT_CALL(*modem_, GetLinkName(_, _)).WillOnce(DoAll(
    201       SetArgumentPointee<1>(string(kLinkName)),
    202       Return(true)));
    203   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(StrEq(kLinkName)))
    204       .WillOnce(Return(kTestInterfaceIndex));
    205   EXPECT_CALL(device_info_, GetMACAddress(kTestInterfaceIndex, _))
    206       .WillOnce(DoAll(SetArgumentPointee<1>(expected_address_),
    207                       Return(true)));
    208   EXPECT_CALL(device_info_, IsDeviceBlackListed(kLinkName))
    209       .WillRepeatedly(Return(true));
    210   modem_->CreateDeviceFromModemProperties(properties);
    211   EXPECT_FALSE(modem_->device_.get());
    212 
    213   // No link name: see CreateDevicePPP.
    214 }
    215 
    216 TEST_F(ModemTest, CreateDevicePPP) {
    217   InterfaceToProperties properties;
    218   properties[MM_MODEM_INTERFACE] = KeyValueStore();
    219 
    220   string dev_name(
    221       base::StringPrintf(Modem::kFakeDevNameFormat, Modem::fake_dev_serial_));
    222 
    223   // |modem_| will take ownership.
    224   MockCellular* cellular = new MockCellular(
    225       &modem_info_,
    226       dev_name,
    227       Modem::kFakeDevAddress,
    228       Modem::kFakeDevInterfaceIndex,
    229       Cellular::kTypeUniversal,
    230       kService,
    231       kPath);
    232 
    233   EXPECT_CALL(*modem_, GetModemInterface()).
    234       WillRepeatedly(Return(MM_MODEM_INTERFACE));
    235   // No link name: assumed to be a PPP dongle.
    236   EXPECT_CALL(*modem_, GetLinkName(_, _)).WillOnce(Return(false));
    237   EXPECT_CALL(*modem_,
    238               ConstructCellular(dev_name,
    239                                 StrEq(Modem::kFakeDevAddress),
    240                                 Modem::kFakeDevInterfaceIndex)).
    241       WillOnce(Return(cellular));
    242   EXPECT_CALL(device_info_, RegisterDevice(_));
    243 
    244   modem_->CreateDeviceFromModemProperties(properties);
    245   EXPECT_TRUE(modem_->device_.get());
    246 
    247   // Add expectations for the eventual |modem_| destruction.
    248   EXPECT_CALL(*cellular, DestroyService());
    249   EXPECT_CALL(device_info_, DeregisterDevice(_));
    250 }
    251 
    252 TEST_F(ModemTest, GetDeviceParams) {
    253   string mac_address;
    254   int interface_index = 2;
    255   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(_)).WillOnce(Return(-1));
    256   EXPECT_CALL(device_info_, GetMACAddress(_, _)).Times(AnyNumber())
    257       .WillRepeatedly(Return(false));
    258   EXPECT_FALSE(modem_->GetDeviceParams(&mac_address, &interface_index));
    259   EXPECT_EQ(-1, interface_index);
    260 
    261   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(_)).WillOnce(Return(-2));
    262   EXPECT_CALL(device_info_, GetMACAddress(_, _)).Times(AnyNumber())
    263       .WillRepeatedly(Return(false));
    264   EXPECT_FALSE(modem_->GetDeviceParams(&mac_address, &interface_index));
    265   EXPECT_EQ(-2, interface_index);
    266 
    267   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(_)).WillOnce(Return(1));
    268   EXPECT_CALL(device_info_, GetMACAddress(_, _)).WillOnce(Return(false));
    269   EXPECT_FALSE(modem_->GetDeviceParams(&mac_address, &interface_index));
    270   EXPECT_EQ(1, interface_index);
    271 
    272   EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(_)).WillOnce(Return(2));
    273   EXPECT_CALL(device_info_, GetMACAddress(2, _)).
    274       WillOnce(DoAll(SetArgumentPointee<1>(expected_address_),
    275                      Return(true)));
    276   EXPECT_TRUE(modem_->GetDeviceParams(&mac_address, &interface_index));
    277   EXPECT_EQ(2, interface_index);
    278   EXPECT_EQ(kAddressAsString, mac_address);
    279 }
    280 
    281 TEST_F(ModemTest, RejectPPPModem) {
    282   // TODO(rochberg):  Port this to ModemClassic
    283 }
    284 
    285 }  // namespace shill
    286