blob: 1dc2699852d549e4e3aff5c09ba36cc25e668a91 [file] [log] [blame]
/*
* Copyright (C) 2016, 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 <array>
#include <memory>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <wifi_system_test/mock_interface_tool.h>
#include "wificond/client_interface_impl.h"
#include "wificond/tests/mock_i_send_mgmt_frame_event.h"
#include "wificond/tests/mock_netlink_manager.h"
#include "wificond/tests/mock_netlink_utils.h"
#include "wificond/tests/mock_scan_utils.h"
using android::wifi_system::MockInterfaceTool;
using std::unique_ptr;
using std::vector;
using testing::Mock;
using testing::NiceMock;
using testing::Return;
using testing::StrictMock;
using testing::_;
namespace android {
namespace wificond {
namespace {
const uint32_t kTestWiphyIndex = 2;
const char kTestInterfaceName[] = "testwifi0";
const uint32_t kTestInterfaceIndex = 42;
const uint64_t kCookie = 42;
const int32_t kAutoMcs = -1;
const int32_t kMcs = 5;
const uint8_t kTestFrame[] = {0x00, 0x01, 0x02, 0x03};
class ClientInterfaceImplTest : public ::testing::Test {
protected:
void SetUp() override {
SetUp(WiphyFeatures());
}
/**
* call SetUp(WiphyFeatures wiphy_features) in your test function if
* you would like to change WiphyFeatures.
*/
void SetUp(WiphyFeatures wiphy_features) {
EXPECT_CALL(*netlink_utils_,
SubscribeMlmeEvent(kTestInterfaceIndex, _));
EXPECT_CALL(*netlink_utils_,
GetWiphyInfo(kTestWiphyIndex, _, _, _))
.WillOnce([wiphy_features](uint32_t wiphy_index, BandInfo* out_band_info,
ScanCapabilities* out_scan_capabilities,
WiphyFeatures* out_wiphy_features) {
*out_wiphy_features = wiphy_features;
return true;
});
EXPECT_CALL(*netlink_utils_,
SubscribeFrameTxStatusEvent(kTestInterfaceIndex, _))
.WillOnce([this](uint32_t interface_index,
OnFrameTxStatusEventHandler handler) {
frame_tx_status_event_handler_ = handler;
});
EXPECT_CALL(*netlink_utils_,
SubscribeChannelSwitchEvent(kTestInterfaceIndex, _));
client_interface_.reset(new ClientInterfaceImpl{
kTestWiphyIndex,
kTestInterfaceName,
kTestInterfaceIndex,
std::array<uint8_t, ETH_ALEN>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
if_tool_.get(),
netlink_utils_.get(),
scan_utils_.get()});
}
void TearDown() override {
EXPECT_CALL(*netlink_utils_,
UnsubscribeMlmeEvent(kTestInterfaceIndex));
EXPECT_CALL(*netlink_utils_,
UnsubscribeFrameTxStatusEvent(kTestInterfaceIndex));
EXPECT_CALL(*netlink_utils_,
UnsubscribeChannelSwitchEvent(kTestInterfaceIndex));
}
unique_ptr<NiceMock<MockInterfaceTool>> if_tool_{
new NiceMock<MockInterfaceTool>};
unique_ptr<NiceMock<MockNetlinkManager>> netlink_manager_{
new NiceMock<MockNetlinkManager>()};
unique_ptr<NiceMock<MockNetlinkUtils>> netlink_utils_{
new NiceMock<MockNetlinkUtils>(netlink_manager_.get())};
unique_ptr<NiceMock<MockScanUtils>> scan_utils_{
new NiceMock<MockScanUtils>(netlink_manager_.get())};
unique_ptr<ClientInterfaceImpl> client_interface_;
OnFrameTxStatusEventHandler frame_tx_status_event_handler_;
sp<StrictMock<MockISendMgmtFrameEvent>> send_mgmt_frame_event_{
new StrictMock<MockISendMgmtFrameEvent>()};
}; // class ClientInterfaceImplTest
} // namespace
/**
* If the device does not support sending mgmt frame at specified MCS rate,
* and the caller specifies a MCS < 0, the call should still succeed (and the
* driver will determine the MCS rate automatically).
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameMcsUnsupportedAutoSelectMcs) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
});
EXPECT_CALL(*send_mgmt_frame_event_, OnAck(_));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
frame_tx_status_event_handler_(kCookie, true);
}
/**
* If the device does not support sending mgmt frame at specified MCS rate,
* and the caller specifies a MCS >= 0, the call should fail.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameMcsUnsupportedCallerSpecifiedMcs) {
EXPECT_CALL(*send_mgmt_frame_event_,
OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kMcs);
}
/**
* If the device does support sending mgmt frame at specified MCS rate and the
* user specifies a valid MCS rate, the call should succeed.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameMcsSupported) {
WiphyFeatures wiphy_features;
wiphy_features.supports_tx_mgmt_frame_mcs = true;
SetUp(wiphy_features);
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
});
EXPECT_CALL(*send_mgmt_frame_event_, OnAck(_));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kMcs);
frame_tx_status_event_handler_(kCookie, true);
}
/**
* Transmitted frame was not ACKed.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameNotAcked) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
});
EXPECT_CALL(*send_mgmt_frame_event_,
OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
frame_tx_status_event_handler_(kCookie, false);
}
/**
* Transmission failed due to unknown NL80211 error.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameUnknownError) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)), kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
return false;
});
EXPECT_CALL(*send_mgmt_frame_event_,
OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_UNKNOWN));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
}
/**
* Received cookie was different than expected; No callback should be triggered.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameWrongCookie) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
});
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
frame_tx_status_event_handler_(
kCookie + 1, // wrong cookie
false);
// StrictMock<MockISendMgmtFrameEvent> will fail if any unexpected method is
// called, guaranteeing no interaction with the callback.
}
/**
* frame_tx_status_event_handler_ triggered even though no transmission is in
* progress. No callback should be triggered.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameNoTxCallbackTriggered) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
});
EXPECT_CALL(*send_mgmt_frame_event_,
OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
frame_tx_status_event_handler_(kCookie, false);
// transmission has finished here.
// Now send another Tx status event.
frame_tx_status_event_handler_(kCookie + 1, false);
// StrictMock<MockISendMgmtFrameEvent> will fail if any unexpected method is
// called, guaranteeing no more interaction with the callback.
}
/**
* Second transmission was started even though no Tx Status event was received
* for the first transmission. Should discard first transmission, and second
* transmission should work normally.
*
* Since timeout of this SendMgmtFrame() is managed by framework, and framework
* does not notify wificond when the call times out, wificond should still work
* when a second call is made, even though it seems as though the first call is
* still incomplete.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameSecondTxWhileFirstTxIncomplete) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
})
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie + 1;
return true;
});
// first transmission; no tx status
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
sp<StrictMock<MockISendMgmtFrameEvent>> send_mgmt_frame_event2{
new StrictMock<MockISendMgmtFrameEvent>()};
EXPECT_CALL(*send_mgmt_frame_event2,
OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
// second transmission; yes tx status
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event2, kAutoMcs);
frame_tx_status_event_handler_(kCookie + 1, false);
// now trigger tx status for first call; nothing should happen (implicitly
// verified by StrictMock).
frame_tx_status_event_handler_(kCookie, false);
}
/**
* Tests that internal state is reset correctly between calls by performing
* two transmissions in sequence.
*/
TEST_F(ClientInterfaceImplTest, SendMgmtFrameInternalStateResetBetweenCalls) {
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
int32_t mcs, uint64_t* out_cookie) {
*out_cookie = kCookie;
return true;
});
EXPECT_CALL(*send_mgmt_frame_event_, OnAck(_));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
frame_tx_status_event_handler_(kCookie, true);
Mock::VerifyAndClearExpectations(netlink_utils_.get());
Mock::VerifyAndClearExpectations(send_mgmt_frame_event_.get());
uint64_t new_cookie = kCookie + 1;
EXPECT_CALL(*netlink_utils_,
SendMgmtFrame(kTestInterfaceIndex,
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
kAutoMcs, _))
.WillOnce([new_cookie](uint32_t interface_index,
const vector<uint8_t>& frame, int32_t mcs, uint64_t* out_cookie) {
*out_cookie = new_cookie;
return true;
});
EXPECT_CALL(*send_mgmt_frame_event_,
OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
client_interface_->SendMgmtFrame(
vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
send_mgmt_frame_event_, kAutoMcs);
frame_tx_status_event_handler_(new_cookie, false);
}
} // namespace wificond
} // namespace android