普通文本  |  249行  |  8.64 KB

//
// Copyright (C) 2015 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 <stdint.h>

#include <memory>
#include <vector>

#include <base/bind.h>
#include <base/memory/ref_counted.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "shill/daemon_task.h"
#include "shill/dhcp/mock_dhcp_provider.h"
#include "shill/logging.h"
#include "shill/mock_control.h"
#include "shill/mock_manager.h"
#include "shill/mock_metrics.h"
#include "shill/mock_process_manager.h"
#include "shill/mock_routing_table.h"
#include "shill/net/io_handler.h"
#include "shill/net/mock_rtnl_handler.h"
#include "shill/net/ndisc.h"
#include "shill/shill_test_config.h"
#include "shill/test_event_dispatcher.h"

#if !defined(DISABLE_WIFI)
#include "shill/net/mock_netlink_manager.h"
#include "shill/net/nl80211_message.h"
#include "shill/wifi/callback80211_metrics.h"
#endif  // DISABLE_WIFI

using base::Bind;
using base::Callback;
using base::Unretained;
using std::string;
using std::vector;

using ::testing::Expectation;
using ::testing::Mock;
using ::testing::Return;
using ::testing::Test;
using ::testing::_;

namespace shill {

class DaemonTaskForTest : public DaemonTask {
 public:
  DaemonTaskForTest(const Settings& setttings, Config* config)
      : DaemonTask(Settings(), config) {}
  virtual ~DaemonTaskForTest() {}

  bool quit_result() { return quit_result_; }

  void RunMessageLoop() { dispatcher_->DispatchForever(); }

  bool Quit(const base::Closure& completion_callback) override {
    quit_result_ = DaemonTask::Quit(completion_callback);
    dispatcher_->PostTask(base::MessageLoop::QuitWhenIdleClosure());
    return quit_result_;
  }

 private:
  bool quit_result_;
};

class DaemonTaskTest : public Test {
 public:
  DaemonTaskTest()
      : daemon_(DaemonTask::Settings(), &config_),
        dispatcher_(new EventDispatcherForTest()),
        control_(new MockControl()),
        metrics_(new MockMetrics(dispatcher_)),
        manager_(new MockManager(control_, dispatcher_, metrics_)),
#if !defined(DISABLE_WIFI)
        callback_metrics_(new Callback80211Metrics(metrics_)),
#endif  // DISABLE_WIFI
        device_info_(control_, dispatcher_, metrics_, manager_) {
  }
  virtual ~DaemonTaskTest() {}
  virtual void SetUp() {
    // Tests initialization done by the daemon's constructor
    daemon_.rtnl_handler_ = &rtnl_handler_;
    daemon_.routing_table_ = &routing_table_;
    daemon_.dhcp_provider_ = &dhcp_provider_;
    daemon_.process_manager_ = &process_manager_;
    daemon_.metrics_.reset(metrics_);        // Passes ownership
    daemon_.manager_.reset(manager_);        // Passes ownership
    daemon_.control_.reset(control_);        // Passes ownership
    daemon_.dispatcher_.reset(dispatcher_);  // Passes ownership

#if !defined(DISABLE_WIFI)
    daemon_.netlink_manager_ = &netlink_manager_;
    // Passes ownership
    daemon_.callback80211_metrics_.reset(callback_metrics_);
#endif  // DISABLE_WIFI
  }
  void StartDaemon() { daemon_.Start(); }

  void StopDaemon() { daemon_.Stop(); }

  void RunDaemon() { daemon_.RunMessageLoop(); }

  void ApplySettings(const DaemonTask::Settings& settings) {
    daemon_.settings_ = settings;
    daemon_.ApplySettings();
  }

  MOCK_METHOD0(TerminationAction, void());
  MOCK_METHOD0(BreakTerminationLoop, void());

 protected:
  TestConfig config_;
  DaemonTaskForTest daemon_;
  MockRTNLHandler rtnl_handler_;
  MockRoutingTable routing_table_;
  MockDHCPProvider dhcp_provider_;
  MockProcessManager process_manager_;
  EventDispatcherForTest* dispatcher_;
  MockControl* control_;
  MockMetrics* metrics_;
  MockManager* manager_;
#if !defined(DISABLE_WIFI)
  MockNetlinkManager netlink_manager_;
  Callback80211Metrics* callback_metrics_;
#endif  // DISABLE_WIFI
  DeviceInfo device_info_;
};

TEST_F(DaemonTaskTest, StartStop) {
  // To ensure we do not have any stale routes, we flush a device's routes
  // when it is started.  This requires that the routing table is fully
  // populated before we create and start devices.  So test to make sure that
  // the RoutingTable starts before the Manager (which in turn starts
  // DeviceInfo who is responsible for creating and starting devices).
  // The result is that we request the dump of the routing table and when that
  // completes, we request the dump of the links.  For each link found, we
  // create and start the device.
  EXPECT_CALL(*metrics_, Start());
  EXPECT_CALL(rtnl_handler_, Start(RTMGRP_LINK | RTMGRP_IPV4_IFADDR |
                                   RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_IFADDR |
                                   RTMGRP_IPV6_ROUTE | RTMGRP_ND_USEROPT));
  Expectation routing_table_started = EXPECT_CALL(routing_table_, Start());
  EXPECT_CALL(dhcp_provider_, Init(_, _, _));
  EXPECT_CALL(process_manager_, Init(_));
#if !defined(DISABLE_WIFI)
  EXPECT_CALL(netlink_manager_, Init());
  const uint16_t kNl80211MessageType = 42;  // Arbitrary.
  EXPECT_CALL(netlink_manager_,
              GetFamily(Nl80211Message::kMessageTypeString, _))
      .WillOnce(Return(kNl80211MessageType));
  EXPECT_CALL(netlink_manager_, Start());
#endif  // DISABLE_WIFI
  EXPECT_CALL(*manager_, Start()).After(routing_table_started);
  StartDaemon();
  Mock::VerifyAndClearExpectations(metrics_);
  Mock::VerifyAndClearExpectations(manager_);

  EXPECT_CALL(*manager_, Stop());
  EXPECT_CALL(*metrics_, Stop());
  EXPECT_CALL(process_manager_, Stop());
  StopDaemon();
}

ACTION_P2(CompleteAction, manager, name) {
  manager->TerminationActionComplete(name);
}

TEST_F(DaemonTaskTest, QuitWithTerminationAction) {
  // This expectation verifies that the termination actions are invoked.
  EXPECT_CALL(*this, TerminationAction())
      .WillOnce(CompleteAction(manager_, "daemon test"));
  EXPECT_CALL(*this, BreakTerminationLoop()).Times(1);

  manager_->AddTerminationAction(
      "daemon test",
      Bind(&DaemonTaskTest::TerminationAction, Unretained(this)));

  // Run Daemon::Quit() after the daemon starts running.
  dispatcher_->PostTask(
      Bind(IgnoreResult(&DaemonTask::Quit), Unretained(&daemon_),
           Bind(&DaemonTaskTest::BreakTerminationLoop, Unretained(this))));

  RunDaemon();
  EXPECT_FALSE(daemon_.quit_result());
}

TEST_F(DaemonTaskTest, QuitWithoutTerminationActions) {
  EXPECT_CALL(*this, BreakTerminationLoop()).Times(0);
  EXPECT_TRUE(daemon_.Quit(
      Bind(&DaemonTaskTest::BreakTerminationLoop, Unretained(this))));
}

TEST_F(DaemonTaskTest, ApplySettings) {
  DaemonTask::Settings settings;
  vector<string> kEmptyStringList;
  EXPECT_CALL(*manager_, SetBlacklistedDevices(kEmptyStringList));
  EXPECT_CALL(*manager_, SetDHCPv6EnabledDevices(kEmptyStringList));
  EXPECT_CALL(*manager_, SetTechnologyOrder("", _));
  EXPECT_CALL(*manager_, SetIgnoreUnknownEthernet(false));
  EXPECT_CALL(*manager_, SetStartupPortalList(_)).Times(0);
  EXPECT_CALL(*manager_, SetPassiveMode()).Times(0);
  EXPECT_CALL(*manager_, SetPrependDNSServers(""));
  EXPECT_CALL(*manager_, SetMinimumMTU(_)).Times(0);
  EXPECT_CALL(*manager_, SetAcceptHostnameFrom(""));
  ApplySettings(settings);
  Mock::VerifyAndClearExpectations(manager_);

  vector<string> kBlacklistedDevices = {"eth0", "eth1"};
  settings.device_blacklist = kBlacklistedDevices;
  settings.default_technology_order = "wifi,ethernet";
  vector<string> kDHCPv6EnabledDevices{"eth2", "eth3"};
  settings.dhcpv6_enabled_devices = kDHCPv6EnabledDevices;
  settings.ignore_unknown_ethernet = false;
  settings.portal_list = "wimax";
  settings.use_portal_list = true;
  settings.passive_mode = true;
  settings.prepend_dns_servers = "8.8.8.8,8.8.4.4";
  settings.minimum_mtu = 256;
  settings.accept_hostname_from = "eth*";
  EXPECT_CALL(*manager_, SetBlacklistedDevices(kBlacklistedDevices));
  EXPECT_CALL(*manager_, SetDHCPv6EnabledDevices(kDHCPv6EnabledDevices));
  EXPECT_CALL(*manager_, SetTechnologyOrder("wifi,ethernet", _));
  EXPECT_CALL(*manager_, SetIgnoreUnknownEthernet(false));
  EXPECT_CALL(*manager_, SetStartupPortalList("wimax"));
  EXPECT_CALL(*manager_, SetPassiveMode());
  EXPECT_CALL(*manager_, SetPrependDNSServers("8.8.8.8,8.8.4.4"));
  EXPECT_CALL(*manager_, SetMinimumMTU(256));
  EXPECT_CALL(*manager_, SetAcceptHostnameFrom("eth*"));
  ApplySettings(settings);
  Mock::VerifyAndClearExpectations(manager_);
}

}  // namespace shill