diff options
author | Frank Ronneburg <fronneburg@xevo.com> | 2018-04-12 09:23:41 +0900 |
---|---|---|
committer | fronneburg <fronneburg@xevo.com> | 2018-04-11 17:25:49 -0700 |
commit | f9d0a8c9d9117b91deda42c9c9148bd5917e6dd2 (patch) | |
tree | 1d0ad97d3e1edf6f37a11cb5c320f1cfc70404e9 /src/components/transport_manager/test | |
parent | e0caccd349cd66a21508c00bcfab8f288d688d86 (diff) | |
download | sdl_core-f9d0a8c9d9117b91deda42c9c9148bd5917e6dd2.tar.gz |
Merge pull request #241 in NAR/sdl-core from feat/transport_unit_tests to feature/Ford-WiFi
* commit 'ebf724367d56d40d18dde5fb2d8af928b985d18d':
UT: add transport adapter, adapter listener, manager unit tests
Fix NetworkInterfaceListener issues detected by UT
UT: Add NetworkInterfaceListener unit tests
Append htonl() for INADDR_ANY
Fix TcpClientListener issues detected by UT
UT: Add TcpClientListener unit tests
Refactor: create NetworkInterfaceListener interface class
Diffstat (limited to 'src/components/transport_manager/test')
7 files changed, 1246 insertions, 15 deletions
diff --git a/src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h b/src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h new file mode 100644 index 0000000000..b7db7c7e64 --- /dev/null +++ b/src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_TCP_MOCK_TCP_CLIENT_LISTENER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_TCP_MOCK_TCP_CLIENT_LISTENER_H_ + +#include "gmock/gmock.h" +#include "transport_manager/tcp/tcp_client_listener.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +using namespace ::transport_manager::transport_adapter; + +class MockTcpClientListener : public TcpClientListener { + public: + MockTcpClientListener(TransportAdapterController* controller, + uint16_t port, + bool enable_keepalive, + const std::string designated_interface = "") + : TcpClientListener( + controller, port, enable_keepalive, designated_interface) {} + MOCK_METHOD0(Init, TransportAdapter::Error()); + MOCK_METHOD0(Terminate, void()); + MOCK_CONST_METHOD0(IsInitialised, bool()); + MOCK_METHOD0(StartListening, TransportAdapter::Error()); + MOCK_METHOD0(StopListening, TransportAdapter::Error()); + MOCK_METHOD2(OnIPAddressUpdated, + void(const std::string ipv4_addr, const std::string ipv6_addr)); +}; + +} // namespace transport_manager_test +} // namespace components +} // namespace test + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_TCP_MOCK_TCP_CLIENT_LISTENER_H_ diff --git a/src/components/transport_manager/test/network_interface_listener_test.cc b/src/components/transport_manager/test/network_interface_listener_test.cc new file mode 100644 index 0000000000..8198e42eb2 --- /dev/null +++ b/src/components/transport_manager/test/network_interface_listener_test.cc @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arpa/inet.h> +#include <net/if.h> +#include <time.h> + +#include "gtest/gtest.h" +#include "transport_manager/tcp/network_interface_listener_impl.h" +#include "transport_manager/tcp/mock_tcp_client_listener.h" +#include "utils/test_async_waiter.h" +#include "utils/threads/thread.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +namespace { +const long kThreadStartWaitMsec = 10; +const uint32_t kStartNotificationTimeoutMsec = 500; +} + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::SaveArg; + +class NetworkInterfaceListenerTest : public ::testing::Test { + public: + NetworkInterfaceListenerTest() + : interface_listener_impl_(NULL) + , mock_tcp_client_listener_(NULL, 0, false, "") {} + + virtual ~NetworkInterfaceListenerTest() {} + + protected: + struct InterfaceEntry { + const char* name; + const char* ipv4_address; + const char* ipv6_address; + unsigned int flags; + }; + + void Init(const std::string interface_name) { + interface_listener_impl_ = new NetworkInterfaceListenerImpl( + &mock_tcp_client_listener_, interface_name); + } + + void Deinit() { + delete interface_listener_impl_; + } + + void SetDummyInterfaceTable(struct InterfaceEntry* entries) { + InterfaceStatusTable dummy_table; + + while (entries->name != NULL) { + InterfaceStatus status; + if (entries->ipv4_address != NULL) { + struct in_addr addr; + ASSERT_EQ(1, inet_pton(AF_INET, entries->ipv4_address, &addr)); + status.SetIPv4Address(&addr); + } + if (entries->ipv6_address != NULL) { + struct in6_addr addr6; + ASSERT_EQ(1, inet_pton(AF_INET6, entries->ipv6_address, &addr6)); + status.SetIPv6Address(&addr6); + } + status.SetFlags(entries->flags); + + dummy_table.insert(std::make_pair(entries->name, status)); + entries++; + } + + interface_listener_impl_->OverwriteStatusTable(dummy_table); + } + + void SleepFor(long msec) const { + if (msec > 0) { + struct timespec ts = {0, msec * 1000 * 1000}; + nanosleep(&ts, NULL); + } + } + + NetworkInterfaceListenerImpl* interface_listener_impl_; + MockTcpClientListener mock_tcp_client_listener_; +}; + +TEST_F(NetworkInterfaceListenerTest, Init) { + Init(""); + + EXPECT_TRUE(interface_listener_impl_->Init()); + EXPECT_TRUE(0 <= interface_listener_impl_->GetSocket()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Deinit) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + interface_listener_impl_->Deinit(); + + EXPECT_EQ(-1, interface_listener_impl_->GetSocket()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Start_success) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + SetDummyInterfaceTable(entries); + + // after stated, it is expected that the listener notifies current IP address + // (if it's available) + TestAsyncWaiter waiter; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries[0].ipv4_address, "")) + .WillOnce(NotifyTestAsyncWaiter(&waiter)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + + // the "isThreadRunning_" flag of the thread will be update slightly later + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(interface_listener_impl_->GetThread()->is_running()); + + EXPECT_TRUE(waiter.WaitFor(1, kStartNotificationTimeoutMsec)); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Start_twice) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + // ignore OnIPAddressUpdated call + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .Times(AtLeast(0)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(interface_listener_impl_->Start()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Stop_success) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + // ignore OnIPAddressUpdated call + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .Times(AtLeast(0)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(interface_listener_impl_->Stop()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(interface_listener_impl_->GetThread()->is_running()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Stop_twice) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + // ignore OnIPAddressUpdated call + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .Times(AtLeast(0)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(interface_listener_impl_->Stop()); + + EXPECT_FALSE(interface_listener_impl_->Stop()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Stop_without_Start) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + EXPECT_FALSE(interface_listener_impl_->Stop()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_IPAddressChanged) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int0", "5.6.7.8", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, "")).Times(1); + + // this test case doesn't call Start() - we only check the behavior of + // NotifyIPAddresses() + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries2[0].ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_IPAddressNotChanged) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {"dummy_int1", "172.16.23.30", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + // OnIPAddressUpdated() shouldn't be notified + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(0); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_GoesUnavailable) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", "fdc2:12af:327a::1", IFF_UP | IFF_RUNNING}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int0", "1.2.3.4", "fdc2:12af:327a::1", IFF_UP}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, + entries1[0].ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated("", "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_Removed) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", "fdc2:12af:327a::1", IFF_UP | IFF_RUNNING}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, + entries1[0].ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated("", "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_Added) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries2[1].ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_SelectInterface) { + // automatically select network interface + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries); + + std::string output_ipv4_address; + std::string output_ipv6_address; + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .WillOnce(DoAll(SaveArg<0>(&output_ipv4_address), + SaveArg<1>(&output_ipv6_address))); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + std::string selected_interface = + interface_listener_impl_->GetSelectedInterfaceName(); + + // the interface listener should pick one of the interfaces + EXPECT_TRUE((selected_interface == entries[0].name && + output_ipv4_address == entries[0].ipv4_address && + output_ipv6_address == "") || + (selected_interface == entries[1].name && + output_ipv4_address == entries[1].ipv4_address && + output_ipv6_address == entries[1].ipv6_address)); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, + AutoSelectInterface_SkipUnavailableInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries); + + // dummy_int1 should not be selected + struct InterfaceEntry* expected = &entries[1]; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(expected->ipv4_address, + expected->ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(expected->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_SkipEmptyInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {"net_dummy2", NULL, NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries); + + // net_dummy2 should not be selected + struct InterfaceEntry* expected = &entries[0]; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(expected->ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(expected->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, + AutoSelectInterface_SkipLoopbackInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING | IFF_LOOPBACK}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + // dummy_int1 should not be selected + struct InterfaceEntry* expected = &entries[1]; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(expected->ipv4_address, + expected->ipv6_address)).Times(1); + + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(expected->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_DisableInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"net_dummy0", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + // make the interface "not running" + entries[0].flags &= ~IFF_RUNNING; + SetDummyInterfaceTable(entries); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated("", "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ("", interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_EnableInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"net_dummy0", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + // make the interface "not running" + entries[0].flags &= ~IFF_RUNNING; + SetDummyInterfaceTable(entries); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + // make it running again + entries[0].flags |= IFF_RUNNING; + SetDummyInterfaceTable(entries); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries[0].ipv4_address, + entries[0].ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(entries[0].name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_SwitchInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", + "10.10.10.12", + "fd53:ba79:241d:30c1::78", + IFF_UP | IFF_RUNNING}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + const std::string selected_interface = + interface_listener_impl_->GetSelectedInterfaceName(); + struct InterfaceEntry* selected = &entries[0]; + while (selected->name != NULL) { + if (selected->name == selected_interface) { + break; + } + selected++; + } + ASSERT_TRUE(selected->name != NULL); + + // make the interface "not running" + selected->flags &= ~IFF_RUNNING; + SetDummyInterfaceTable(entries); + + struct InterfaceEntry* switched; + if (selected == &entries[0]) { + switched = &entries[1]; + } else { + switched = &entries[0]; + } + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(switched->ipv4_address, + switched->ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(switched->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +} // namespace transport_manager_test +} // namespace components +} // namespace test diff --git a/src/components/transport_manager/test/tcp_client_listener_test.cc b/src/components/transport_manager/test/tcp_client_listener_test.cc index ca85b89fa9..0302225b07 100644 --- a/src/components/transport_manager/test/tcp_client_listener_test.cc +++ b/src/components/transport_manager/test/tcp_client_listener_test.cc @@ -2,6 +2,9 @@ * Copyright (c) 2015, Ford Motor Company * All rights reserved. * + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * @@ -13,7 +16,7 @@ * disclaimer in the documentation and/or other materials provided with the * distribution. * - * Neither the name of the Ford Motor Company nor the names of its contributors + * Neither the name of the copyright holders nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -30,21 +33,38 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include <time.h> + #include "gtest/gtest.h" #include "transport_manager/transport_adapter/mock_transport_adapter.h" #include "transport_manager/tcp/tcp_client_listener.h" +#include "transport_manager/tcp/network_interface_listener.h" #include "transport_manager/mock_transport_manager.h" #include "transport_manager/transport_adapter/transport_adapter_controller.h" -#include "transport_manager/transport_adapter/device.h" +#include "transport_manager/transport_adapter/mock_device.h" +#include "utils/make_shared.h" +#include "utils/test_async_waiter.h" +#include "utils/threads/thread.h" namespace test { namespace components { namespace transport_manager_test { +using ::testing::_; +using ::testing::AtLeast; using ::testing::Return; using namespace ::transport_manager; using namespace ::transport_manager::transport_adapter; +namespace { +const long kThreadStartWaitMsec = 10; +const uint32_t kConnectionCreatedTimeoutMsec = 200; +} + class MockTransportAdapterController : public TransportAdapterController { public: MOCK_METHOD1(AddDevice, DeviceSptr(DeviceSptr device)); @@ -100,36 +120,495 @@ class MockTransportAdapterController : public TransportAdapterController { new_config)); }; -class TcpClientListenerTest : public ::testing::Test { +class MockNetworkInterfaceListener : public NetworkInterfaceListener { + public: + MOCK_METHOD0(Init, bool()); + MOCK_METHOD0(Deinit, void()); + MOCK_METHOD0(Start, bool()); + MOCK_METHOD0(Stop, bool()); +}; + +class TcpClientListenerTest : public ::testing::TestWithParam<std::string> { public: TcpClientListenerTest() - : port_(0) + : port_(0) /* On Linux, binding to port 0 lets the system choose an + available port */ , enable_keep_alive_(false) - , tcp_client_listener_( - &adapter_controller_mock_, port_, enable_keep_alive_) {} + , interface_listener_mock_(NULL) + , tcp_client_listener_(NULL) {} + virtual ~TcpClientListenerTest() { + delete tcp_client_listener_; + } protected: + void SetUp() OVERRIDE { + tcp_client_listener_ = new TcpClientListener( + &adapter_controller_mock_, port_, enable_keep_alive_, GetParam()); + interface_listener_mock_ = new MockNetworkInterfaceListener(); + tcp_client_listener_->set_network_interface_listener( + interface_listener_mock_); + } + + bool InterfaceNameSpecified() const { + return "" != GetParam(); + } + + void SleepFor(long msec) const { + if (msec > 0) { + struct timespec ts = {0, msec * 1000 * 1000}; + nanosleep(&ts, NULL); + } + } + uint16_t port_; bool enable_keep_alive_; MockTransportAdapterController adapter_controller_mock_; - TcpClientListener tcp_client_listener_; + MockNetworkInterfaceListener* interface_listener_mock_; + TcpClientListener* tcp_client_listener_; }; -TEST_F(TcpClientListenerTest, Ctor_test) { - EXPECT_EQ(0, tcp_client_listener_.port()); - EXPECT_TRUE(NULL != tcp_client_listener_.thread()); - EXPECT_EQ(-1, tcp_client_listener_.get_socket()); +TEST_P(TcpClientListenerTest, Ctor_test) { + EXPECT_EQ(0, tcp_client_listener_->port()); + EXPECT_TRUE(NULL != tcp_client_listener_->thread()); + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); } -TEST_F(TcpClientListenerTest, IsInitialised) { +TEST_P(TcpClientListenerTest, IsInitialised) { // should return false until Init() is called - EXPECT_FALSE(tcp_client_listener_.IsInitialised()); + EXPECT_FALSE(tcp_client_listener_->IsInitialised()); +} + +TEST_P(TcpClientListenerTest, Init) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + + if (InterfaceNameSpecified()) { + // TcpClientListener will create socket once IP address of the network is + // notified. + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); + } else { + // Interface name is not designated. In this case, TcpClientListener will + // create socket with Init(). + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + } + + EXPECT_TRUE(tcp_client_listener_->IsInitialised()); + + // Deinit() will be called during destructor + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, Terminate) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); + + tcp_client_listener_->Terminate(); + + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); +} + +TEST_P(TcpClientListenerTest, StartListening) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + // the "isThreadRunning_" flag of the thread will be update slightly later + SleepFor(kThreadStartWaitMsec); + + if (InterfaceNameSpecified()) { + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + } else { + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + // Stop() and Deinit() will be called during destructor + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, StartListening_twice) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + // call again + EXPECT_EQ(TransportAdapter::BAD_STATE, + tcp_client_listener_->StartListening()); + + // Stop() and Deinit() will be called during destructor + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, StopListening) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StopListening()); + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, StopListening_twice) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StopListening()); + + // call again + EXPECT_EQ(TransportAdapter::BAD_STATE, tcp_client_listener_->StopListening()); + + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, ClientConnection) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + if (InterfaceNameSpecified()) { + // set up a server socket by notifying a dummy IP address + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(_)).Times(1); + tcp_client_listener_->OnIPAddressUpdated(std::string("192.168.1.1"), + std::string("")); + } + + // get the port number (assigned by system) that the socket is listening on + struct sockaddr_in server_addr; + socklen_t server_addr_len = sizeof(server_addr); + EXPECT_EQ(0, + getsockname(tcp_client_listener_->get_socket(), + reinterpret_cast<struct sockaddr*>(&server_addr), + &server_addr_len)); + + // try connecting to the socket + struct sockaddr_in client_addr; + client_addr.sin_family = AF_INET; + client_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + client_addr.sin_port = server_addr.sin_port; + socklen_t client_addr_len = sizeof(client_addr); + + int s = socket(AF_INET, SOCK_STREAM, 0); + EXPECT_TRUE(0 <= s); + + TestAsyncWaiter waiter; + + // controller should be notified of AddDevice event + DeviceSptr mock_device = utils::MakeShared<MockTCPDevice>( + htonl(INADDR_LOOPBACK), "dummy_tcp_device"); + EXPECT_CALL(adapter_controller_mock_, AddDevice(_)) + .WillOnce(Return(mock_device)); + EXPECT_CALL(adapter_controller_mock_, ConnectionCreated(_, _, _)) + .WillOnce(NotifyTestAsyncWaiter(&waiter)); + + // adapter_controller_mock_ may also receive ConnectDone() and + // ConnectionFinished() from ThreadedSocketConnection. Ignore them as hey are + // not part ly client listener's tests. + EXPECT_CALL(adapter_controller_mock_, ConnectDone(_, _)).Times(AtLeast(0)); + EXPECT_CALL(adapter_controller_mock_, ConnectionFinished(_, _)) + .Times(AtLeast(0)); + + EXPECT_EQ(0, + connect(s, + reinterpret_cast<struct sockaddr*>(&client_addr), + client_addr_len)); + + // since the connection is handled on another thread, wait for some time + EXPECT_TRUE(waiter.WaitFor(1, kConnectionCreatedTimeoutMsec)); + + close(s); + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_ValidIPv4Address) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config; + expected_config.insert(std::make_pair(std::string("enabled"), "true")); + expected_config.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr)); + expected_config.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(expected_config)) + .Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + // when the client listener runs with designated interface name, it should + // start the thread here + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_changed) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_1.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = "172.16.2.3"; + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_2.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_2)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_same) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_1.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = "192.168.1.1"; // same as before + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_2.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(std::string("tcp_port"), test_port)); + + // client listener should not generate TransportConfigUpdated event + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(_)).Times(0); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_disabled) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_1.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = ""; + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(std::string("enabled"), "false")); + expected_config_2.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_2)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_reenabled) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_1.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = ""; + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(std::string("enabled"), "false")); + expected_config_2.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_2)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + const std::string test_ipv4_addr_3 = "192.168.1.1"; + TransportConfig expected_config_3; + expected_config_3.insert(std::make_pair(std::string("enabled"), "true")); + expected_config_3.insert( + std::make_pair(std::string("tcp_ip_address"), test_ipv4_addr_3)); + expected_config_3.insert(std::make_pair(std::string("tcp_port"), test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_3)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_3, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); } -TEST_F(TcpClientListenerTest, Init) { - EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_.Init()); +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_EmptyIPv4Address) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr = ""; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + // if the client listener receives an empty IP address after started, it + // should ignore it + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(_)).Times(0); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); } +INSTANTIATE_TEST_CASE_P(NetworkInterfaceName, + TcpClientListenerTest, + ::testing::Values(std::string(""), + std::string("dummy_interface0"))); + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/tcp_transport_adapter_test.cc b/src/components/transport_manager/test/tcp_transport_adapter_test.cc index 5bd5b96954..d6abf5e813 100644 --- a/src/components/transport_manager/test/tcp_transport_adapter_test.cc +++ b/src/components/transport_manager/test/tcp_transport_adapter_test.cc @@ -347,6 +347,37 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevices_RestoreData) { } } +TEST_F(TcpAdapterTest, NotifyTransportConfigUpdated) { + MockTransportAdapterListener mock_adapter_listener; + + MockTCPTransportAdapter transport_adapter( + port, last_state_, transport_manager_settings); + transport_adapter.AddListener(&mock_adapter_listener); + + TransportConfig config; + config["enabled"] = std::string("enabled"); + config["tcp_ip_address"] = std::string("192.168.1.1"); + config["tcp_port"] = std::string("12345"); + + EXPECT_CALL(mock_adapter_listener, OnTransportConfigUpdated(_)).Times(1); + + transport_adapter.TransportConfigUpdated(config); +} + +TEST_F(TcpAdapterTest, GetTransportConfiguration) { + MockTCPTransportAdapter transport_adapter( + port, last_state_, transport_manager_settings); + + TransportConfig config; + config["enabled"] = std::string("enabled"); + config["tcp_ip_address"] = std::string("192.168.1.1"); + config["tcp_port"] = std::string("12345"); + + transport_adapter.TransportConfigUpdated(config); + + EXPECT_EQ(config, transport_adapter.GetTransportConfiguration()); +} + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/transport_adapter_listener_test.cc b/src/components/transport_manager/test/transport_adapter_listener_test.cc index 14b8850b49..1494844519 100644 --- a/src/components/transport_manager/test/transport_adapter_listener_test.cc +++ b/src/components/transport_manager/test/transport_adapter_listener_test.cc @@ -230,6 +230,15 @@ TEST_F(TransportAdapterListenerTest, OnUnexpectedDisconnect) { &adapter_mock, dev_id, app_handle, err); } +TEST_F(TransportAdapterListenerTest, OnTransportConfigUpdated) { + EXPECT_CALL( + tr_mock, + ReceiveEventFromDevice(IsEvent( + EventTypeEnum::ON_TRANSPORT_CONFIG_UPDATED, &adapter_mock, "", 0))) + .WillOnce(Return(E_SUCCESS)); + transport_listener.OnTransportConfigUpdated(&adapter_mock); +} + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/transport_adapter_test.cc b/src/components/transport_manager/test/transport_adapter_test.cc index 6d709e0c17..ab2683193c 100644 --- a/src/components/transport_manager/test/transport_adapter_test.cc +++ b/src/components/transport_manager/test/transport_adapter_test.cc @@ -809,6 +809,35 @@ TEST_F(TransportAdapterTest, StopDevice) { transport_adapter.StopDevice(uniq_id); } +TEST_F(TransportAdapterTest, TransportConfigUpdated) { + MockTransportAdapterImpl transport_adapter( + NULL, NULL, NULL, last_state_, transport_manager_settings); + EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); + transport_adapter.Init(); + + MockTransportAdapterListener mock_listener; + transport_adapter.AddListener(&mock_listener); + + TransportConfig config; + config["enabled"] = std::string("enabled"); + config["tcp_ip_address"] = std::string("192.168.1.1"); + config["tcp_port"] = std::string("12345"); + + EXPECT_CALL(mock_listener, OnTransportConfigUpdated(_)); + transport_adapter.TransportConfigUpdated(config); +} + +TEST_F(TransportAdapterTest, GetTransportConfigration) { + MockTransportAdapterImpl transport_adapter( + NULL, NULL, NULL, last_state_, transport_manager_settings); + EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); + transport_adapter.Init(); + + TransportConfig empty_config; + + EXPECT_EQ(empty_config, transport_adapter.GetTransportConfiguration()); +} + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/transport_manager_impl_test.cc b/src/components/transport_manager/test/transport_manager_impl_test.cc index eebb247908..b2643f2938 100644 --- a/src/components/transport_manager/test/transport_manager_impl_test.cc +++ b/src/components/transport_manager/test/transport_manager_impl_test.cc @@ -1323,6 +1323,26 @@ TEST_F(TransportManagerImplTest, tm_.OnDeviceListUpdated(mock_adapter_); } +TEST_F(TransportManagerImplTest, OnTransportConfigUpdated) { + TransportAdapterEvent test_event(EventTypeEnum::ON_TRANSPORT_CONFIG_UPDATED, + mock_adapter_, + "", + 0, + test_message_, + error_); + + transport_adapter::TransportConfig config; + config["enabled"] = std::string("enabled"); + config["tcp_ip_address"] = std::string("192.168.1.1"); + config["tcp_port"] = std::string("12345"); + + EXPECT_CALL(*mock_adapter_, GetTransportConfiguration()) + .WillOnce(Return(config)); + + EXPECT_CALL(*tm_listener_, OnTransportConfigUpdated(config)); + tm_.TestHandle(test_event); +} + } // namespace transport_manager_test } // namespace components } // namespace test |