普通文本  |  287行  |  8.96 KB

//
// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "shill/cellular/modem_manager.h"

#include <base/stl_util.h>
#include <ModemManager/ModemManager.h>

#include "shill/cellular/mock_dbus_objectmanager_proxy.h"
#include "shill/cellular/mock_modem.h"
#include "shill/cellular/mock_modem_info.h"
#include "shill/cellular/mock_modem_manager_proxy.h"
#include "shill/manager.h"
#include "shill/mock_control.h"
#include "shill/mock_manager.h"
#include "shill/test_event_dispatcher.h"
#include "shill/testing.h"

using std::string;
using std::shared_ptr;
using std::vector;
using testing::_;
using testing::Invoke;
using testing::Pointee;
using testing::Return;
using testing::SaveArg;
using testing::StrEq;
using testing::Test;

namespace shill {

class ModemManagerTest : public Test {
 public:
  ModemManagerTest()
      : manager_(&control_, &dispatcher_, nullptr),
        modem_info_(&control_, &dispatcher_, nullptr, &manager_) {}

  virtual void SetUp() {
    modem_.reset(
        new StrictModem(kService, kModemPath, &modem_info_, &control_));
  }

 protected:
  static const char kService[];
  static const char kPath[];
  static const char kModemPath[];

  shared_ptr<StrictModem> modem_;

  EventDispatcherForTest dispatcher_;
  MockControl control_;
  MockManager manager_;
  MockModemInfo modem_info_;
};

const char ModemManagerTest::kService[] = "org.chromium.ModemManager";
const char ModemManagerTest::kPath[] = "/org/chromium/ModemManager";
const char ModemManagerTest::kModemPath[] = "/org/blah/Modem/blah/0";

class ModemManagerForTest : public ModemManager {
 public:
  ModemManagerForTest(ControlInterface* control_interface,
                      const string& service,
                      const string& path,
                      ModemInfo* modem_info)
    : ModemManager(control_interface, service, path, modem_info) {}

  MOCK_METHOD0(Start, void());
  MOCK_METHOD0(Stop, void());
};

class ModemManagerCoreTest : public ModemManagerTest {
 public:
  ModemManagerCoreTest()
      : ModemManagerTest(),
        modem_manager_(&control_, kService, kPath, &modem_info_) {}

 protected:
  ModemManagerForTest modem_manager_;
};

TEST_F(ModemManagerCoreTest, ConnectDisconnect) {
  EXPECT_FALSE(modem_manager_.service_connected_);
  modem_manager_.Connect();
  EXPECT_TRUE(modem_manager_.service_connected_);

  modem_manager_.RecordAddedModem(modem_);
  EXPECT_EQ(1, modem_manager_.modems_.size());

  modem_manager_.ModemManager::Disconnect();
  EXPECT_EQ(0, modem_manager_.modems_.size());
  EXPECT_FALSE(modem_manager_.service_connected_);
}

TEST_F(ModemManagerCoreTest, AddRemoveModem) {
  modem_manager_.Connect();
  EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));

  // Remove non-existent modem path.
  modem_manager_.RemoveModem(kModemPath);
  EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));

  modem_manager_.RecordAddedModem(modem_);
  EXPECT_TRUE(modem_manager_.ModemExists(kModemPath));

  // Add an already added modem.
  modem_manager_.RecordAddedModem(modem_);
  EXPECT_TRUE(modem_manager_.ModemExists(kModemPath));

  modem_manager_.RemoveModem(kModemPath);
  EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));

  // Remove an already removed modem path.
  modem_manager_.RemoveModem(kModemPath);
  EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));
}

class ModemManagerClassicMockInit : public ModemManagerClassic {
 public:
  ModemManagerClassicMockInit(ControlInterface* control_interface,
                              const string& service,
                              const string& path,
                              ModemInfo* modem_info_) :
      ModemManagerClassic(control_interface, service, path, modem_info_) {}

  MOCK_METHOD1(InitModemClassic, void(shared_ptr<ModemClassic>));
};

class ModemManagerClassicTest : public ModemManagerTest {
 public:
  ModemManagerClassicTest()
      : ModemManagerTest(),
        modem_manager_(&control_, kService, kPath, &modem_info_),
        proxy_(new MockModemManagerProxy()) {}

 protected:
  ModemManagerClassicMockInit modem_manager_;
  MockModemManagerProxy* proxy_;
};

TEST_F(ModemManagerClassicTest, StartStop) {
  EXPECT_EQ(nullptr, modem_manager_.proxy_.get());

  EXPECT_CALL(control_, CreateModemManagerProxy(_, kPath, kService, _, _))
      .WillOnce(Return(proxy_));
  modem_manager_.Start();
  EXPECT_NE(nullptr, modem_manager_.proxy_.get());

  modem_manager_.Stop();
  EXPECT_EQ(nullptr, modem_manager_.proxy_.get());
}

TEST_F(ModemManagerClassicTest, Connect) {
  // Setup proxy.
  modem_manager_.proxy_.reset(proxy_);

  EXPECT_CALL(*proxy_, EnumerateDevices())
      .WillOnce(Return(vector<string>(1, kModemPath)));
  EXPECT_CALL(modem_manager_,
              InitModemClassic(
                  Pointee(Field(&Modem::path_, StrEq(kModemPath)))));
  modem_manager_.Connect();
  EXPECT_EQ(1, modem_manager_.modems_.size());
  ASSERT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
}

class ModemManager1MockInit : public ModemManager1 {
 public:
  ModemManager1MockInit(ControlInterface* control_interface,
                        const string& service,
                        const string& path,
                        ModemInfo* modem_info_) :
      ModemManager1(control_interface, service, path, modem_info_) {}
  MOCK_METHOD2(InitModem1, void(shared_ptr<Modem1>,
                                const InterfaceToProperties&));
};


class ModemManager1Test : public ModemManagerTest {
 public:
  ModemManager1Test()
      : ModemManagerTest(),
        modem_manager_(&control_, kService, kPath, &modem_info_),
        proxy_(new MockDBusObjectManagerProxy()) {}

 protected:
  virtual void SetUp() {
    proxy_->IgnoreSetCallbacks();
  }

  void Connect(const ObjectsWithProperties& expected_objects) {
    ManagedObjectsCallback get_managed_objects_callback;
    EXPECT_CALL(*proxy_, GetManagedObjects(_, _, _))
        .WillOnce(SaveArg<1>(&get_managed_objects_callback));
    modem_manager_.Connect();
    get_managed_objects_callback.Run(expected_objects, Error());
  }

  static ObjectsWithProperties GetModemWithProperties() {
    KeyValueStore o_fd_mm1_modem;

    InterfaceToProperties properties;
    properties[MM_DBUS_INTERFACE_MODEM] = o_fd_mm1_modem;

    ObjectsWithProperties objects_with_properties;
    objects_with_properties[kModemPath] = properties;

    return objects_with_properties;
  }

  ModemManager1MockInit modem_manager_;
  MockDBusObjectManagerProxy* proxy_;
  MockControl control_;
};

TEST_F(ModemManager1Test, StartStop) {
  EXPECT_EQ(nullptr, modem_manager_.proxy_.get());

  EXPECT_CALL(control_, CreateDBusObjectManagerProxy(kPath, kService, _, _))
      .WillOnce(Return(proxy_));
  EXPECT_CALL(*proxy_, set_interfaces_added_callback(_));
  EXPECT_CALL(*proxy_, set_interfaces_removed_callback(_));
  modem_manager_.Start();
  EXPECT_NE(nullptr, modem_manager_.proxy_.get());

  modem_manager_.Stop();
  EXPECT_EQ(nullptr, modem_manager_.proxy_.get());
}

TEST_F(ModemManager1Test, Connect) {
  // Setup proxy.
  modem_manager_.proxy_.reset(proxy_);

  Connect(GetModemWithProperties());
  EXPECT_EQ(1, modem_manager_.modems_.size());
  EXPECT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
}

TEST_F(ModemManager1Test, AddRemoveInterfaces) {
  // Setup proxy.
  modem_manager_.proxy_.reset(proxy_);

  // Have nothing come back from GetManagedObjects
  Connect(ObjectsWithProperties());
  EXPECT_EQ(0, modem_manager_.modems_.size());

  // Add an object that doesn't have a modem interface.  Nothing should be added
  EXPECT_CALL(modem_manager_, InitModem1(_, _)).Times(0);
  modem_manager_.OnInterfacesAddedSignal(kModemPath,
                                         InterfaceToProperties());
  EXPECT_EQ(0, modem_manager_.modems_.size());

  // Actually add a modem
  EXPECT_CALL(modem_manager_, InitModem1(_, _)).Times(1);
  modem_manager_.OnInterfacesAddedSignal(kModemPath,
                                         GetModemWithProperties()[kModemPath]);
  EXPECT_EQ(1, modem_manager_.modems_.size());

  // Remove an irrelevant interface
  vector<string> not_including_modem_interface;
  not_including_modem_interface.push_back("not.a.modem.interface");
  modem_manager_.OnInterfacesRemovedSignal(kModemPath,
                                           not_including_modem_interface);
  EXPECT_EQ(1, modem_manager_.modems_.size());

  // Remove the modem
  vector<string> with_modem_interface;
  with_modem_interface.push_back(MM_DBUS_INTERFACE_MODEM);
  modem_manager_.OnInterfacesRemovedSignal(kModemPath, with_modem_interface);
  EXPECT_EQ(0, modem_manager_.modems_.size());
}

}  // namespace shill