普通文本  |  265行  |  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 "shill/passive_link_monitor.h"

#include <net/if_arp.h>

#include <string>

#include <gtest/gtest.h>

#include "shill/arp_client_test_helper.h"
#include "shill/arp_packet.h"
#include "shill/logging.h"
#include "shill/mock_arp_client.h"
#include "shill/mock_connection.h"
#include "shill/mock_control.h"
#include "shill/mock_device_info.h"
#include "shill/mock_event_dispatcher.h"
#include "shill/mock_log.h"
#include "shill/net/byte_string.h"
#include "shill/net/ip_address.h"

using base::Bind;
using base::Unretained;
using std::string;
using testing::_;
using testing::AnyNumber;
using testing::HasSubstr;
using testing::Mock;
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;
using testing::StrictMock;
using testing::Test;

namespace shill {

namespace {
const char kInterfaceName[] = "test-interface";
const char kLocalIPAddress[] = "10.0.1.1";
const uint8_t kLocalMACAddress[] = { 0, 1, 2, 3, 4, 5 };
const char kRemoteIPAddress[] = "10.0.1.2";
const uint8_t kRemoteMACAddress[] = { 6, 7, 8, 9, 10, 11 };
}  // namespace

class ResultCallbackObserver {
 public:
  ResultCallbackObserver()
      : result_callback_(
          Bind(&ResultCallbackObserver::OnResultCallback,
               Unretained(this))) {}
  virtual ~ResultCallbackObserver() {}

  MOCK_METHOD1(OnResultCallback, void(bool status));

  const PassiveLinkMonitor::ResultCallback result_callback() {
    return result_callback_;
  }

 private:
  PassiveLinkMonitor::ResultCallback result_callback_;

  DISALLOW_COPY_AND_ASSIGN(ResultCallbackObserver);
};

class PassiveLinkMonitorTest : public Test {
 public:
  PassiveLinkMonitorTest()
      : device_info_(&control_, nullptr, nullptr, nullptr),
        connection_(new StrictMock<MockConnection>(&device_info_)),
        client_(new MockArpClient()),
        client_test_helper_(client_),
        link_monitor_(connection_, &dispatcher_, observer_.result_callback()),
        interface_name_(kInterfaceName) {}
  virtual ~PassiveLinkMonitorTest() {}

  virtual void SetUp() {
    ScopeLogger::GetInstance()->EnableScopesByName("link");
    ScopeLogger::GetInstance()->set_verbose_level(4);
    link_monitor_.arp_client_.reset(client_);

    EXPECT_CALL(*connection_, interface_name())
        .WillRepeatedly(ReturnRef(interface_name_));
  }

  virtual void TearDown() {
    ScopeLogger::GetInstance()->EnableScopesByName("-link");
    ScopeLogger::GetInstance()->set_verbose_level(0);
  }

  void ReceiveArpPacket(uint16_t operation) {
    client_test_helper_.GeneratePacket(
        operation,
        IPAddress(kLocalIPAddress),
        ByteString(kLocalMACAddress, arraysize(kLocalMACAddress)),
        IPAddress(kRemoteIPAddress),
        ByteString(kRemoteMACAddress, arraysize(kRemoteMACAddress)));
    link_monitor_.ReceiveRequest(0);
  }

  void MonitorCompleted(bool status) {
    link_monitor_.MonitorCompleted(status);
  }

  void InvokeCycleTimeoutHandler() {
    link_monitor_.CycleTimeoutHandler();
  }

  void SetCurrentCycleStats(int num_requests_received, int num_cycles_passed) {
    link_monitor_.num_requests_received_ = num_requests_received;
    link_monitor_.num_cycles_passed_ = num_cycles_passed;
  }

  void VerifyCurrentCycleStats(int num_requests_received,
                               int num_cycles_passed) {
    EXPECT_EQ(num_requests_received, link_monitor_.num_requests_received_);
    EXPECT_EQ(num_cycles_passed, link_monitor_.num_cycles_passed_);
  }

 protected:
  MockEventDispatcher dispatcher_;
  MockControl control_;
  NiceMock<MockDeviceInfo> device_info_;
  ResultCallbackObserver observer_;
  scoped_refptr<MockConnection> connection_;
  MockArpClient* client_;
  ArpClientTestHelper client_test_helper_;
  PassiveLinkMonitor link_monitor_;
  const string interface_name_;
};

TEST_F(PassiveLinkMonitorTest, StartFailedArpClient) {
  EXPECT_CALL(*client_, StartRequestListener()).WillOnce(Return(false));
  EXPECT_FALSE(link_monitor_.Start(PassiveLinkMonitor::kDefaultMonitorCycles));
}

TEST_F(PassiveLinkMonitorTest, StartSuccess) {
  EXPECT_CALL(*client_, StartRequestListener()).WillOnce(Return(true));
  EXPECT_CALL(dispatcher_, CreateReadyHandler(_, IOHandler::kModeInput, _))
      .Times(1);
  EXPECT_CALL(dispatcher_, PostDelayedTask(_, _)).Times(1);
  EXPECT_TRUE(link_monitor_.Start(PassiveLinkMonitor::kDefaultMonitorCycles));
}

TEST_F(PassiveLinkMonitorTest, Stop) {
  EXPECT_CALL(*client_, Stop()).Times(1);
  link_monitor_.Stop();
  Mock::VerifyAndClearExpectations(client_);
}

TEST_F(PassiveLinkMonitorTest, MonitorCompleted) {
  // Monitor failed.
  EXPECT_CALL(*client_, Stop()).Times(1);
  EXPECT_CALL(observer_, OnResultCallback(false)).Times(1);
  MonitorCompleted(false);
  Mock::VerifyAndClearExpectations(client_);
  Mock::VerifyAndClearExpectations(&observer_);

  // Monitor succeed.
  EXPECT_CALL(*client_, Stop()).Times(1);
  EXPECT_CALL(observer_, OnResultCallback(true)).Times(1);
  MonitorCompleted(true);
  Mock::VerifyAndClearExpectations(client_);
  Mock::VerifyAndClearExpectations(&observer_);
}

TEST_F(PassiveLinkMonitorTest, ReceiveArpReply) {
  // Setup initial stats.
  const int kRequestReceived = 0;
  const int kCurrentCycle = 0;
  SetCurrentCycleStats(kRequestReceived, kCurrentCycle);
  ScopedMockLog log;
  EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
  EXPECT_CALL(log, Log(_, _, HasSubstr("This is not a request packet")))
      .Times(1);
  ReceiveArpPacket(ARPOP_REPLY);
  // Verify no change in receive count.
  VerifyCurrentCycleStats(kRequestReceived, kCurrentCycle);
  Mock::VerifyAndClearExpectations(&log);
}

TEST_F(PassiveLinkMonitorTest, ReceiveArpRequest) {
  // Setup initial stats.
  const int kRequestReceived = 0;
  const int kCurrentCycle = 0;
  SetCurrentCycleStats(kRequestReceived, kCurrentCycle);

  EXPECT_CALL(*client_, Stop()).Times(0);
  ReceiveArpPacket(ARPOP_REQUEST);
  ReceiveArpPacket(ARPOP_REQUEST);
  VerifyCurrentCycleStats(kRequestReceived + 2, kCurrentCycle);
  Mock::VerifyAndClearExpectations(client_);
}

TEST_F(PassiveLinkMonitorTest, ReceiveAllRequestsForCycle) {
  // 4 ARP requests received in the current cycle so far.
  const int kRequestReceived = 4;
  const int kCurrentCycle = 0;
  SetCurrentCycleStats(kRequestReceived, kCurrentCycle);

  // Received all required requests for a cycle, stop the ARP client.
  EXPECT_CALL(*client_, Stop()).Times(1);
  ReceiveArpPacket(ARPOP_REQUEST);
  Mock::VerifyAndClearExpectations(client_);
}

TEST_F(PassiveLinkMonitorTest, CycleFailed) {
  // 3 ARP requests received in the current cycle so far.
  const int kRequestReceived = 3;
  const int kCurrentCycle = 0;
  SetCurrentCycleStats(kRequestReceived, kCurrentCycle);

  // Monitor failed for the current cycle, post a task to perform cleanup and
  // invoke result callback.
  EXPECT_CALL(*client_, StartRequestListener()).Times(0);
  EXPECT_CALL(dispatcher_, PostDelayedTask(_, _)).Times(0);
  EXPECT_CALL(dispatcher_, PostTask(_)).Times(1);
  InvokeCycleTimeoutHandler();
}

TEST_F(PassiveLinkMonitorTest, CycleSucceed) {
  // 5 ARP requests received in the current cycle so far.
  const int kRequestReceived = 5;
  const int kCurrentCycle = 0;
  SetCurrentCycleStats(kRequestReceived, kCurrentCycle);

  // Monitor succeed for the current cycle, post a task to trigger a new cycle.
  EXPECT_CALL(*client_, StartRequestListener()).WillOnce(Return(true));
  EXPECT_CALL(dispatcher_, PostDelayedTask(_, _)).Times(1);
  EXPECT_CALL(dispatcher_, PostTask(_)).Times(0);
  InvokeCycleTimeoutHandler();
  // ARP request received count should be resetted.
  VerifyCurrentCycleStats(0, kCurrentCycle + 1);
}

TEST_F(PassiveLinkMonitorTest, AllCyclesCompleted) {
  // 5 ARP requests received in the current cycle so far.
  const int kRequestReceived = 5;
  const int kCurrentCycle = PassiveLinkMonitor::kDefaultMonitorCycles - 1;
  SetCurrentCycleStats(kRequestReceived, kCurrentCycle);

  // Monitor completed all the cycles, post a task to perform cleanup and
  // invoke result callback.
  EXPECT_CALL(dispatcher_, PostDelayedTask(_, _)).Times(0);
  EXPECT_CALL(dispatcher_, PostTask(_)).Times(1);
  InvokeCycleTimeoutHandler();
  VerifyCurrentCycleStats(0, PassiveLinkMonitor::kDefaultMonitorCycles);
}

}  // namespace shill