Newer
Older
mbed-os / connectivity / netsocket / tests / UNITTESTS / netsocket / EthernetInterface / test_EthernetInterface.cpp
@Paul Szczepanek Paul Szczepanek on 26 Jan 2021 8 KB upgrade gtest to 1.10
/*
 * Copyright (c) 2018, Arm Limited and affiliates
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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 "gtest/gtest.h"
#include "gmock/gmock.h"

#include "OnboardNetworkStack_mock.h"

#include "netsocket/EthernetInterface.h"
#include <iostream>
#include "EMAC_mock.h"

OnboardNetworkStack &OnboardNetworkStack::get_default_instance()
{
    return OnboardNetworkStackMock::get_instance();
}

// Implementaion in in NetworkInterfaceDefaults.cpp
MBED_WEAK EthInterface *EthInterface::get_default_instance()
{
    return get_target_default_instance();
}

using ::testing::_;
using ::testing::Return;
using ::testing::ReturnArg;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
using ::testing::SetArrayArgument;
using ::testing::SetArgPointee;
using ::testing::SetArgReferee;
using ::testing::DoAll;

class TestEthernetInterface: public testing::Test {
protected:
    EthernetInterface *iface;
    OnboardNetworkStackMock *stackMock;
    MockEMAC *emacMock;
    OnboardNetworkStackMock::InterfaceMock *netStackIface;
    virtual void SetUp()
    {
        stackMock = &OnboardNetworkStackMock::get_instance();
        emacMock = &MockEMAC::get_instance();
        netStackIface = &OnboardNetworkStackMock::InterfaceMock::get_instance();
        iface = new EthernetInterface(MockEMAC::get_instance(), OnboardNetworkStackMock::get_instance());
    }

    virtual void TearDown()
    {
        // Do not delete the mocks pointers, as they point to statically allocated singletons.
        delete iface;
    }

    /* Enclose the heavily-used connection procedure to improve code redability */
    void doConnect(bool dhcp = true, bool blocking = true)
    {
        EXPECT_CALL(*stackMock, add_ethernet_interface(testing::Ref(*emacMock), true, _))
        .Times(1)
        .WillOnce(DoAll(SetArgPointee<2>(netStackIface), Return(NSAPI_ERROR_OK)));
        EXPECT_CALL(*netStackIface, attach(_))
        .Times(1)
        .RetiresOnSaturation();;
        EXPECT_CALL(*netStackIface, bringup(dhcp, NULL, NULL, NULL, DEFAULT_STACK, blocking))
        .Times(1)
        .WillOnce(Return(NSAPI_ERROR_OK));
        EXPECT_EQ(NSAPI_ERROR_OK, iface->connect());
    }

    static void cb(nsapi_event_t ev, intptr_t ptr)
    {

    }
};

TEST_F(TestEthernetInterface, constructor_default)
{
    EXPECT_TRUE(iface);

    // Test that this clas presents itself correctly
    EXPECT_NE(nullptr, iface->ethInterface());
    EXPECT_NE(nullptr, iface->emacInterface());

    EXPECT_EQ(nullptr, iface->wifiInterface());
    EXPECT_EQ(nullptr, iface->cellularInterface());
    EXPECT_EQ(nullptr, iface->meshInterface());
}

TEST_F(TestEthernetInterface, constructor_getter)
{
    EthInterface *eth = EthInterface::get_default_instance();
}



TEST_F(TestEthernetInterface, connect)
{
    doConnect();
}

TEST_F(TestEthernetInterface, connect_failure)
{
    EXPECT_CALL(*stackMock, add_ethernet_interface(testing::Ref(*emacMock), true, _))
    .Times(1)
    .WillOnce(DoAll(SetArgPointee<2>(netStackIface), Return(NSAPI_ERROR_NO_MEMORY)));
    EXPECT_EQ(NSAPI_ERROR_NO_MEMORY, iface->connect());
}

TEST_F(TestEthernetInterface, disconnect_without_connecting)
{
    EXPECT_EQ(NSAPI_ERROR_NO_CONNECTION, iface->disconnect());
}

TEST_F(TestEthernetInterface, disconnect)
{
    doConnect();

    EXPECT_CALL(*netStackIface, bringdown())
    .Times(1)
    .WillOnce(Return(NSAPI_ERROR_OK));
    EXPECT_EQ(NSAPI_ERROR_OK, iface->disconnect());
}

TEST_F(TestEthernetInterface, set_network)
{
    SocketAddress ipAddress("127.0.0.1");
    SocketAddress netmask("255.255.0.0");
    SocketAddress gateway("127.0.0.2");
    char macAddress[NSAPI_MAC_SIZE];
    memset(macAddress, '\0', NSAPI_MAC_SIZE);

    SocketAddress ipAddressArg;
    SocketAddress netmaskArg;
    SocketAddress gatewayArg;

    // Before connecting return NULL
    EXPECT_EQ(NULL, iface->get_mac_address());

    SocketAddress tmp;
    EXPECT_EQ(NSAPI_ERROR_NO_CONNECTION, iface->get_ip_address(&tmp));
    EXPECT_EQ(NSAPI_ERROR_NO_CONNECTION, iface->get_netmask(&tmp));
    EXPECT_EQ(NSAPI_ERROR_NO_CONNECTION, iface->get_gateway(&tmp));

    // Set the network data
    EXPECT_EQ(NSAPI_ERROR_OK, iface->set_network(ipAddress, netmask, gateway));

    // Now the bringup should have different arguments. We can't use doConnect method.
    EXPECT_CALL(*stackMock, add_ethernet_interface(testing::Ref(*emacMock), true, _))
    .Times(1)
    .WillOnce(DoAll(SetArgPointee<2>(netStackIface), Return(NSAPI_ERROR_OK)));
    EXPECT_CALL(*netStackIface, attach(_))
    .Times(1)
    .RetiresOnSaturation();
    // Do not put the expected char * arguments, as they are pointers and would not match
    EXPECT_CALL(*netStackIface, bringup(false, _, _, _, DEFAULT_STACK, true))
    .Times(1)
    .WillOnce(DoAll(SaveArg<1>(&ipAddressArg),
                    SaveArg<2>(&netmaskArg),
                    SaveArg<3>(&gatewayArg),
                    Return(NSAPI_ERROR_OK)));
    EXPECT_EQ(NSAPI_ERROR_OK, iface->connect());
    // Check the contents of the stored pointer arguments.
    EXPECT_EQ(ipAddress, ipAddressArg);
    EXPECT_EQ(netmask, netmaskArg);
    EXPECT_EQ(gateway, gatewayArg);

    // Testing the getters makes sense now.
    EXPECT_CALL(*netStackIface, get_mac_address(_, _))
    .Times(1)
    .WillOnce(DoAll(SetArrayArgument<0>(macAddress, macAddress + NSAPI_MAC_SIZE), Return(macAddress)));
    EXPECT_EQ(std::string(macAddress), std::string(iface->get_mac_address()));

    EXPECT_CALL(*netStackIface, get_ip_address(_))
    .Times(1)
    .WillOnce(DoAll(SetArgPointee<0>(ipAddress), Return(NSAPI_ERROR_OK)));
    EXPECT_EQ(NSAPI_ERROR_OK, iface->get_ip_address(&ipAddressArg));

    EXPECT_CALL(*netStackIface, get_netmask(_))
    .Times(1)
    .WillOnce(DoAll(SetArgPointee<0>(netmask), Return(NSAPI_ERROR_OK)));
    EXPECT_EQ(NSAPI_ERROR_OK, iface->get_netmask(&netmaskArg));

    EXPECT_CALL(*netStackIface, get_gateway(_))
    .Times(1)
    .WillOnce(DoAll(SetArgPointee<0>(gateway), Return(NSAPI_ERROR_OK)));
    EXPECT_EQ(NSAPI_ERROR_OK, iface->get_gateway(&gatewayArg));
}

TEST_F(TestEthernetInterface, get_connection_status)
{
    EXPECT_EQ(NSAPI_STATUS_DISCONNECTED, iface->get_connection_status());

    doConnect();

    EXPECT_CALL(*netStackIface, get_connection_status())
    .Times(1)
    .WillOnce(Return(NSAPI_STATUS_LOCAL_UP));
    EXPECT_EQ(NSAPI_STATUS_LOCAL_UP, iface->get_connection_status());
}

TEST_F(TestEthernetInterface, attach)
{
    doConnect();
    EXPECT_CALL(*netStackIface, attach(_)) // TODO: check that the correct function is passed.
    .Times(1);
    iface->attach(cb);
}


TEST_F(TestEthernetInterface, get_interface_name)
{
    char name[100] = "eth0";
    EXPECT_EQ(NULL, iface->get_interface_name(name));

    doConnect();

    // The parameter will be an internal variable.
    EXPECT_CALL(*netStackIface, get_interface_name(_))
    .Times(1)
    .WillOnce(Return(name));
    EXPECT_EQ(std::string(name), std::string(iface->get_interface_name(name)));
}

TEST_F(TestEthernetInterface, get_ipv6_link_local_address)
{
    SocketAddress addr("4.3.2.1");
    EXPECT_EQ(NSAPI_ERROR_NO_CONNECTION, iface->get_ipv6_link_local_address(&addr));
    EXPECT_EQ(std::string(addr.get_ip_address()), std::string("4.3.2.1"));
    doConnect();

    // The parameter will be an internal variable.
    EXPECT_CALL(*netStackIface, get_ipv6_link_local_address(&addr))
    .Times(1)
    .WillOnce(Return(NSAPI_ERROR_OK));
    EXPECT_EQ(NSAPI_ERROR_OK, iface->get_ipv6_link_local_address(&addr));
}

TEST_F(TestEthernetInterface, set_as_default)
{
    doConnect();

    EXPECT_CALL(*stackMock, set_default_interface(netStackIface))
    .Times(1);
    iface->set_as_default();
}


TEST_F(TestEthernetInterface, set_dhcp)
{
    EXPECT_EQ(NSAPI_ERROR_OK, iface->set_dhcp(false));
    doConnect(false, true);
}

TEST_F(TestEthernetInterface, set_blocking)
{
    EXPECT_EQ(NSAPI_ERROR_OK, iface->set_blocking(false));
    doConnect(true, false);
}