summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Ronneburg <fronneburg@xevo.com>2018-04-12 09:23:41 +0900
committerfronneburg <fronneburg@xevo.com>2018-04-11 17:25:49 -0700
commitf9d0a8c9d9117b91deda42c9c9148bd5917e6dd2 (patch)
tree1d0ad97d3e1edf6f37a11cb5c320f1cfc70404e9
parente0caccd349cd66a21508c00bcfab8f288d688d86 (diff)
downloadsdl_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
-rw-r--r--src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h132
-rw-r--r--src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h218
-rw-r--r--src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h8
-rw-r--r--src/components/transport_manager/src/tcp/network_interface_listener_impl.cpp (renamed from src/components/transport_manager/src/tcp/network_interface_listener.cpp)69
-rw-r--r--src/components/transport_manager/src/tcp/tcp_client_listener.cc26
-rw-r--r--src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h66
-rw-r--r--src/components/transport_manager/test/network_interface_listener_test.cc597
-rw-r--r--src/components/transport_manager/test/tcp_client_listener_test.cc509
-rw-r--r--src/components/transport_manager/test/tcp_transport_adapter_test.cc31
-rw-r--r--src/components/transport_manager/test/transport_adapter_listener_test.cc9
-rw-r--r--src/components/transport_manager/test/transport_adapter_test.cc29
-rw-r--r--src/components/transport_manager/test/transport_manager_impl_test.cc20
12 files changed, 1534 insertions, 180 deletions
diff --git a/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h
index dd6e94b2f3..91ddb3839c 100644
--- a/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h
+++ b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h
@@ -33,160 +33,38 @@
#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_H_
#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_H_
-#include <map>
-#include <string>
-#include <vector>
-
-#include <netinet/in.h>
-#include "utils/macro.h"
-#include "utils/threads/thread_delegate.h"
-
-class Thread;
-struct ifaddrmsg;
-
namespace transport_manager {
namespace transport_adapter {
-class TcpClientListener;
-
-/**
- * @brief Struct to keep network interface's status flags and IP addresses
- */
-class InterfaceStatus {
- public:
- InterfaceStatus() : flags_(0), has_ipv4_(false), has_ipv6_(false) {}
- ~InterfaceStatus() {}
-
- bool IsAvailable() const;
- bool IsLoopback() const;
- // only for debugging output
- unsigned int GetFlags() const {
- return flags_;
- }
-
- bool HasIPAddress() const;
- std::string GetIPv4Address() const;
- std::string GetIPv6Address() const;
-
- void SetFlags(unsigned int flags) {
- flags_ = flags;
- }
-
- // specify NULL to remove existing address
- void SetIPv4Address(struct in_addr* addr);
- void SetIPv6Address(struct in6_addr* addr);
-
- private:
- unsigned int flags_;
- bool has_ipv4_;
- bool has_ipv6_;
- struct in_addr ipv4_address_;
- struct in6_addr ipv6_address_;
-};
-
-typedef std::map<std::string, InterfaceStatus> InterfaceStatusTable;
-
/**
* @brief Listener to detect various events on network interfaces
*/
class NetworkInterfaceListener {
public:
/**
- * @brief Constructor
- *
- * @param tcp_client_listener an instance of TcpClientListener which receives
- * status updates
- * @param designated_interface if we want to listen only on a specific
- * network interface, specify its name
- */
- NetworkInterfaceListener(TcpClientListener* tcp_client_listener,
- const std::string designated_interface = "");
-
- /**
* @brief Destructor
*/
- virtual ~NetworkInterfaceListener();
+ virtual ~NetworkInterfaceListener() {}
/**
* @brief Initialize this listener
*/
- bool Init();
+ virtual bool Init() = 0;
/**
* @brief Deinitialize this listener
*/
- void Deinit();
+ virtual void Deinit() = 0;
/**
* @brief Start this listener
*/
- bool Start();
+ virtual bool Start() = 0;
/**
* @brief Stop this listener
*/
- bool Stop();
-
- private:
- // Struct to hold an event on a network interface.
- // The event can be either an update on flags or an update on IP address.
- struct EventParam {
- unsigned int if_index;
- unsigned int flags;
- struct sockaddr_storage address;
-
- EventParam(int interface_index, unsigned int interface_flags = 0)
- : if_index(interface_index), flags(interface_flags) {}
- };
-
- // parent class which we will notify the events to
- TcpClientListener* tcp_client_listener_;
- // if configured, NetworkInterfaceListener will always look into the IP
- // addresses of this interface
- const std::string designated_interface_;
-
- // a map to store status of each interface
- InterfaceStatusTable status_table_;
- // this is the name of the interface we are currently focusing on
- std::string selected_interface_;
- // previous IP addresses that we have notified
- std::string notified_ipv4_addr_;
- std::string notified_ipv6_addr_;
-
- int socket_;
- int pipe_fds_[2];
- threads::Thread* thread_;
-
- void Loop();
- bool StopLoop();
-
- // reset status_table_ by fetching current status of each interface
- bool InitializeStatus();
- // update status_table_ by applying the events
- bool UpdateStatus(uint16_t type, std::vector<EventParam>& params);
- // update notified_ipv4_addr_ and notified_ipv6_addr_ then notify the parent
- // class of the change if necessary
- void NotifyIPAddresses();
- // Select an appropriate network interface that we will get IP addresses. Also
- // update selected_interface_.
- const std::string SelectInterface();
- // convert ifaddrmsg to a list of EventParam structs
- std::vector<EventParam> ParseIFAddrMessage(struct ifaddrmsg* message,
- unsigned int size);
- // for debugging
- void DumpTable() const;
-
- class ListenerThreadDelegate : public threads::ThreadDelegate {
- public:
- explicit ListenerThreadDelegate(NetworkInterfaceListener* parent);
- virtual void threadMain();
- void exitThreadMain();
-
- private:
- NetworkInterfaceListener* parent_;
- };
-
- DISALLOW_COPY_AND_ASSIGN(NetworkInterfaceListener);
+ virtual bool Stop() = 0;
};
} // namespace transport_adapter
diff --git a/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h
new file mode 100644
index 0000000000..972419f791
--- /dev/null
+++ b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h
@@ -0,0 +1,218 @@
+/*
+ * 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 names 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_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_IMPL_H_
+#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_IMPL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <netinet/in.h>
+#include "transport_manager/tcp/network_interface_listener.h"
+#include "utils/macro.h"
+#include "utils/threads/thread_delegate.h"
+
+class Thread;
+struct ifaddrmsg;
+
+namespace transport_manager {
+namespace transport_adapter {
+
+class TcpClientListener;
+
+/**
+ * @brief Struct to keep network interface's status flags and IP addresses
+ */
+class InterfaceStatus {
+ public:
+ InterfaceStatus() : flags_(0), has_ipv4_(false), has_ipv6_(false) {}
+ ~InterfaceStatus() {}
+
+ bool IsAvailable() const;
+ bool IsLoopback() const;
+ // only for debugging output
+ unsigned int GetFlags() const {
+ return flags_;
+ }
+
+ bool HasIPAddress() const;
+ std::string GetIPv4Address() const;
+ std::string GetIPv6Address() const;
+
+ void SetFlags(unsigned int flags) {
+ flags_ = flags;
+ }
+
+ // specify NULL to remove existing address
+ void SetIPv4Address(struct in_addr* addr);
+ void SetIPv6Address(struct in6_addr* addr);
+
+ private:
+ unsigned int flags_;
+ bool has_ipv4_;
+ bool has_ipv6_;
+ struct in_addr ipv4_address_;
+ struct in6_addr ipv6_address_;
+};
+
+typedef std::map<std::string, InterfaceStatus> InterfaceStatusTable;
+
+/**
+ * @brief Listener to detect various events on network interfaces
+ */
+class NetworkInterfaceListenerImpl : public NetworkInterfaceListener {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * @param tcp_client_listener an instance of TcpClientListener which receives
+ * status updates
+ * @param designated_interface if we want to listen only on a specific
+ * network interface, specify its name
+ */
+ NetworkInterfaceListenerImpl(TcpClientListener* tcp_client_listener,
+ const std::string designated_interface = "");
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~NetworkInterfaceListenerImpl();
+
+ /**
+ * @brief Initialize this listener
+ */
+ bool Init() OVERRIDE;
+
+ /**
+ * @brief Deinitialize this listener
+ */
+ void Deinit() OVERRIDE;
+
+ /**
+ * @brief Start this listener
+ */
+ bool Start() OVERRIDE;
+
+ /**
+ * @brief Stop this listener
+ */
+ bool Stop() OVERRIDE;
+
+#ifdef BUILD_TESTS
+ int GetSocket() const {
+ return socket_;
+ }
+
+ threads::Thread* GetThread() const {
+ return thread_;
+ }
+
+ void OverwriteStatusTable(const InterfaceStatusTable dummy_table) {
+ status_table_ = dummy_table;
+ }
+
+ void testCallNotifyIPAddresses() {
+ NotifyIPAddresses();
+ }
+
+ const std::string& GetSelectedInterfaceName() const {
+ return selected_interface_;
+ }
+#endif // BUILD_TESTS
+
+ private:
+ // Struct to hold an event on a network interface.
+ // The event can be either an update on flags or an update on IP address.
+ struct EventParam {
+ unsigned int if_index;
+ unsigned int flags;
+ struct sockaddr_storage address;
+
+ EventParam(int interface_index, unsigned int interface_flags = 0)
+ : if_index(interface_index), flags(interface_flags) {}
+ };
+
+ // parent class which we will notify the events to
+ TcpClientListener* tcp_client_listener_;
+ // if configured, NetworkInterfaceListener will always look into the IP
+ // addresses of this interface
+ const std::string designated_interface_;
+
+ // a map to store status of each interface
+ InterfaceStatusTable status_table_;
+ // this is the name of the interface we are currently focusing on
+ std::string selected_interface_;
+ // previous IP addresses that we have notified
+ std::string notified_ipv4_addr_;
+ std::string notified_ipv6_addr_;
+
+ int socket_;
+ int pipe_fds_[2];
+ threads::Thread* thread_;
+
+ void Loop();
+ bool StopLoop();
+
+ // reset status_table_ by fetching current status of each interface
+ bool InitializeStatus();
+ // update status_table_ by applying the events
+ bool UpdateStatus(uint16_t type, std::vector<EventParam>& params);
+ // update notified_ipv4_addr_ and notified_ipv6_addr_ then notify the parent
+ // class of the change if necessary
+ void NotifyIPAddresses();
+ // Select an appropriate network interface that we will get IP addresses. Also
+ // update selected_interface_.
+ const std::string SelectInterface();
+ // convert ifaddrmsg to a list of EventParam structs
+ std::vector<EventParam> ParseIFAddrMessage(struct ifaddrmsg* message,
+ unsigned int size);
+ // for debugging
+ void DumpTable() const;
+
+ class ListenerThreadDelegate : public threads::ThreadDelegate {
+ public:
+ explicit ListenerThreadDelegate(NetworkInterfaceListenerImpl* parent);
+ virtual void threadMain();
+ void exitThreadMain();
+
+ private:
+ NetworkInterfaceListenerImpl* parent_;
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkInterfaceListenerImpl);
+};
+
+} // namespace transport_adapter
+} // namespace transport_manager
+
+#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_IMPL_H_
diff --git a/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h b/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h
index 90af32ec39..a44387a282 100644
--- a/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h
+++ b/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h
@@ -115,10 +115,14 @@ class TcpClientListener : public ClientConnectionListener {
* @brief Called from NetworkInterfaceListener when IP address of the network
* interface is changed.
*/
- void OnIPAddressUpdated(const std::string ipv4_addr,
- const std::string ipv6_addr);
+ virtual void OnIPAddressUpdated(const std::string ipv4_addr,
+ const std::string ipv6_addr);
#ifdef BUILD_TESTS
+ void set_network_interface_listener(NetworkInterfaceListener* listener) {
+ interface_listener_ = listener;
+ }
+
uint16_t port() const {
return port_;
}
diff --git a/src/components/transport_manager/src/tcp/network_interface_listener.cpp b/src/components/transport_manager/src/tcp/network_interface_listener_impl.cpp
index 0bf317dc2e..f78617aa91 100644
--- a/src/components/transport_manager/src/tcp/network_interface_listener.cpp
+++ b/src/components/transport_manager/src/tcp/network_interface_listener_impl.cpp
@@ -30,7 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "transport_manager/tcp/network_interface_listener.h"
+#include "transport_manager/tcp/network_interface_listener_impl.h"
#include <arpa/inet.h>
#include <asm/types.h>
@@ -74,7 +74,7 @@ bool InterfaceStatus::HasIPAddress() const {
std::string InterfaceStatus::GetIPv4Address() const {
char buf[INET_ADDRSTRLEN] = "";
- if (has_ipv4_) {
+ if (has_ipv4_ && IsAvailable()) {
inet_ntop(AF_INET, &ipv4_address_, buf, sizeof(buf));
}
return std::string(buf);
@@ -82,7 +82,7 @@ std::string InterfaceStatus::GetIPv4Address() const {
std::string InterfaceStatus::GetIPv6Address() const {
char buf[INET6_ADDRSTRLEN] = "";
- if (has_ipv6_) {
+ if (has_ipv6_ && IsAvailable()) {
inet_ntop(AF_INET6, &ipv6_address_, buf, sizeof(buf));
}
return std::string(buf);
@@ -106,7 +106,7 @@ void InterfaceStatus::SetIPv6Address(struct in6_addr* addr) {
}
}
-NetworkInterfaceListener::NetworkInterfaceListener(
+NetworkInterfaceListenerImpl::NetworkInterfaceListenerImpl(
TcpClientListener* tcp_client_listener,
const std::string designated_interface)
: tcp_client_listener_(tcp_client_listener)
@@ -116,11 +116,11 @@ NetworkInterfaceListener::NetworkInterfaceListener(
, notified_ipv6_addr_("")
, socket_(-1) {
pipe_fds_[0] = pipe_fds_[1] = -1;
- thread_ = threads::CreateThread("NetworkInterfaceListener",
+ thread_ = threads::CreateThread("NetworkInterfaceListenerImpl",
new ListenerThreadDelegate(this));
}
-NetworkInterfaceListener::~NetworkInterfaceListener() {
+NetworkInterfaceListenerImpl::~NetworkInterfaceListenerImpl() {
LOG4CXX_AUTO_TRACE(logger_);
Stop();
@@ -130,7 +130,7 @@ NetworkInterfaceListener::~NetworkInterfaceListener() {
threads::DeleteThread(thread_);
}
-bool NetworkInterfaceListener::Init() {
+bool NetworkInterfaceListenerImpl::Init() {
LOG4CXX_AUTO_TRACE(logger_);
if (socket_ >= 0) {
@@ -176,7 +176,7 @@ bool NetworkInterfaceListener::Init() {
return true;
}
-void NetworkInterfaceListener::Deinit() {
+void NetworkInterfaceListenerImpl::Deinit() {
LOG4CXX_AUTO_TRACE(logger_);
if (socket_ >= 0) {
@@ -193,7 +193,7 @@ void NetworkInterfaceListener::Deinit() {
}
}
-bool NetworkInterfaceListener::Start() {
+bool NetworkInterfaceListenerImpl::Start() {
LOG4CXX_AUTO_TRACE(logger_);
if (socket_ < 0) {
@@ -215,7 +215,7 @@ bool NetworkInterfaceListener::Start() {
return true;
}
-bool NetworkInterfaceListener::Stop() {
+bool NetworkInterfaceListenerImpl::Stop() {
LOG4CXX_AUTO_TRACE(logger_);
if (!thread_->is_running()) {
@@ -229,7 +229,7 @@ bool NetworkInterfaceListener::Stop() {
return true;
}
-void NetworkInterfaceListener::Loop() {
+void NetworkInterfaceListenerImpl::Loop() {
LOG4CXX_AUTO_TRACE(logger_);
InitializeStatus();
@@ -274,6 +274,7 @@ void NetworkInterfaceListener::Loop() {
}
}
+#ifndef BUILD_TESTS // don't enable events from network interface while testing
if (FD_ISSET(socket_, &rfds)) {
ret = recv(socket_, buf, sizeof(buf), 0);
if (ret < 0) {
@@ -324,10 +325,11 @@ void NetworkInterfaceListener::Loop() {
NotifyIPAddresses();
}
+#endif
}
}
-bool NetworkInterfaceListener::StopLoop() {
+bool NetworkInterfaceListenerImpl::StopLoop() {
LOG4CXX_AUTO_TRACE(logger_);
LOG4CXX_INFO(logger_, "Stopping network interface listener");
@@ -348,9 +350,14 @@ bool NetworkInterfaceListener::StopLoop() {
return true;
}
-bool NetworkInterfaceListener::InitializeStatus() {
+bool NetworkInterfaceListenerImpl::InitializeStatus() {
LOG4CXX_AUTO_TRACE(logger_);
+#ifdef BUILD_TESTS
+ // don't actually call getifaddrs()
+ return true;
+#endif
+
struct ifaddrs* if_list, *interface;
if (getifaddrs(&if_list) != 0) {
LOG4CXX_WARN(logger_,
@@ -400,8 +407,8 @@ bool NetworkInterfaceListener::InitializeStatus() {
return true;
}
-bool NetworkInterfaceListener::UpdateStatus(uint16_t type,
- std::vector<EventParam>& params) {
+bool NetworkInterfaceListenerImpl::UpdateStatus(
+ uint16_t type, std::vector<EventParam>& params) {
LOG4CXX_AUTO_TRACE(logger_);
for (std::vector<EventParam>::iterator it = params.begin();
@@ -469,7 +476,7 @@ bool NetworkInterfaceListener::UpdateStatus(uint16_t type,
return true;
}
-void NetworkInterfaceListener::NotifyIPAddresses() {
+void NetworkInterfaceListenerImpl::NotifyIPAddresses() {
LOG4CXX_AUTO_TRACE(logger_);
std::string ipv4_addr;
@@ -479,9 +486,12 @@ void NetworkInterfaceListener::NotifyIPAddresses() {
// note that if interface_name is empty (i.e. no interface is selected),
// the IP addresses will be empty
if (!interface_name.empty()) {
- InterfaceStatus& status = status_table_[interface_name];
- ipv4_addr = status.GetIPv4Address();
- ipv6_addr = status.GetIPv6Address();
+ InterfaceStatusTable::iterator it = status_table_.find(interface_name);
+ if (status_table_.end() != it) {
+ InterfaceStatus& status = it->second;
+ ipv4_addr = status.GetIPv4Address();
+ ipv6_addr = status.GetIPv6Address();
+ }
}
if (notified_ipv4_addr_ != ipv4_addr || notified_ipv6_addr_ != ipv6_addr) {
@@ -499,7 +509,7 @@ void NetworkInterfaceListener::NotifyIPAddresses() {
}
}
-const std::string NetworkInterfaceListener::SelectInterface() {
+const std::string NetworkInterfaceListenerImpl::SelectInterface() {
LOG4CXX_AUTO_TRACE(logger_);
if (!designated_interface_.empty()) {
@@ -538,12 +548,13 @@ const std::string NetworkInterfaceListener::SelectInterface() {
return selected_interface_;
}
- return std::string();
+ selected_interface_ = "";
+ return selected_interface_;
}
-std::vector<NetworkInterfaceListener::EventParam>
-NetworkInterfaceListener::ParseIFAddrMessage(struct ifaddrmsg* message,
- unsigned int size) {
+std::vector<NetworkInterfaceListenerImpl::EventParam>
+NetworkInterfaceListenerImpl::ParseIFAddrMessage(struct ifaddrmsg* message,
+ unsigned int size) {
LOG4CXX_AUTO_TRACE(logger_);
std::vector<EventParam> params;
@@ -598,7 +609,7 @@ NetworkInterfaceListener::ParseIFAddrMessage(struct ifaddrmsg* message,
return params;
}
-void NetworkInterfaceListener::DumpTable() const {
+void NetworkInterfaceListenerImpl::DumpTable() const {
LOG4CXX_DEBUG(logger_,
"Number of network interfaces: " << status_table_.size());
@@ -616,15 +627,15 @@ void NetworkInterfaceListener::DumpTable() const {
}
}
-NetworkInterfaceListener::ListenerThreadDelegate::ListenerThreadDelegate(
- NetworkInterfaceListener* parent)
+NetworkInterfaceListenerImpl::ListenerThreadDelegate::ListenerThreadDelegate(
+ NetworkInterfaceListenerImpl* parent)
: parent_(parent) {}
-void NetworkInterfaceListener::ListenerThreadDelegate::threadMain() {
+void NetworkInterfaceListenerImpl::ListenerThreadDelegate::threadMain() {
parent_->Loop();
}
-void NetworkInterfaceListener::ListenerThreadDelegate::exitThreadMain() {
+void NetworkInterfaceListenerImpl::ListenerThreadDelegate::exitThreadMain() {
parent_->StopLoop();
}
diff --git a/src/components/transport_manager/src/tcp/tcp_client_listener.cc b/src/components/transport_manager/src/tcp/tcp_client_listener.cc
index b6610b77f2..a7d3dfc94c 100644
--- a/src/components/transport_manager/src/tcp/tcp_client_listener.cc
+++ b/src/components/transport_manager/src/tcp/tcp_client_listener.cc
@@ -62,7 +62,7 @@
#include "utils/make_shared.h"
#include "utils/threads/thread.h"
#include "transport_manager/transport_adapter/transport_adapter_controller.h"
-#include "transport_manager/tcp/network_interface_listener.h"
+#include "transport_manager/tcp/network_interface_listener_impl.h"
#include "transport_manager/tcp/tcp_device.h"
#include "transport_manager/tcp/tcp_socket_connection.h"
@@ -90,7 +90,7 @@ TcpClientListener::TcpClientListener(TransportAdapterController* controller,
thread_ = threads::CreateThread("TcpClientListener",
new ListeningThreadDelegate(this));
interface_listener_ =
- new NetworkInterfaceListener(this, designated_interface);
+ new NetworkInterfaceListenerImpl(this, designated_interface);
}
TransportAdapter::Error TcpClientListener::Init() {
@@ -130,11 +130,11 @@ TransportAdapter::Error TcpClientListener::Init() {
void TcpClientListener::Terminate() {
LOG4CXX_AUTO_TRACE(logger_);
+ if (!initialized_) {
+ return;
+ }
+
if (!IsListeningOnSpecificInterface()) {
- if (socket_ == -1) {
- LOG4CXX_WARN(logger_, "Socket has been closed");
- return;
- }
DestroyServerSocket(socket_);
socket_ = -1;
} else {
@@ -157,6 +157,7 @@ TcpClientListener::~TcpClientListener() {
delete thread_->delegate();
threads::DeleteThread(thread_);
Terminate();
+ delete interface_listener_;
}
void SetKeepaliveOptions(const int fd) {
@@ -541,7 +542,7 @@ int TcpClientListener::CreateIPv4ServerSocket(
struct in_addr ipv4_address;
memset(&ipv4_address, 0, sizeof(ipv4_address));
if (interface_name.empty()) {
- ipv4_address.s_addr = INADDR_ANY;
+ ipv4_address.s_addr = htonl(INADDR_ANY);
} else if (!GetIPv4Address(interface_name, &ipv4_address)) {
return -1;
}
@@ -597,6 +598,17 @@ bool TcpClientListener::GetIPv4Address(const std::string interface_name,
struct in_addr* ip_address) {
LOG4CXX_AUTO_TRACE(logger_);
+#ifdef BUILD_TESTS
+ // return a dummy address of INADDR_LOOPBACK
+ struct in_addr dummy_addr;
+ dummy_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (ip_address != NULL) {
+ *ip_address = dummy_addr;
+ }
+ return true;
+#endif
+
struct ifaddrs* if_list;
if (getifaddrs(&if_list) != 0) {
LOG4CXX_WARN(logger_, "getifaddrs failed");
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