diff options
author | Haavard <havardpe@yahoo-inc.com> | 2017-04-06 09:53:33 +0000 |
---|---|---|
committer | Haavard <havardpe@yahoo-inc.com> | 2017-04-07 13:44:36 +0000 |
commit | b680033c5ce26d1da2e7ef2d40aab1d23f99e921 (patch) | |
tree | a5eb286dca300d245fceff2d00605d5ec605240b /vespalib/src | |
parent | bde2604037eee583a9e1d21e0f2c352f206816c6 (diff) |
socket spec with test
Diffstat (limited to 'vespalib/src')
-rw-r--r-- | vespalib/src/tests/net/socket_spec/CMakeLists.txt | 8 | ||||
-rw-r--r-- | vespalib/src/tests/net/socket_spec/socket_spec_test.cpp | 109 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/net/CMakeLists.txt | 1 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/net/socket_spec.cpp | 69 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/net/socket_spec.h | 42 |
5 files changed, 229 insertions, 0 deletions
diff --git a/vespalib/src/tests/net/socket_spec/CMakeLists.txt b/vespalib/src/tests/net/socket_spec/CMakeLists.txt new file mode 100644 index 00000000000..66b4ea4d5d6 --- /dev/null +++ b/vespalib/src/tests/net/socket_spec/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespalib_socket_spec_test_app TEST + SOURCES + socket_spec_test.cpp + DEPENDS + vespalib +) +vespa_add_test(NAME vespalib_socket_spec_test_app COMMAND vespalib_socket_spec_test_app) diff --git a/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp b/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp new file mode 100644 index 00000000000..ca00377f049 --- /dev/null +++ b/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp @@ -0,0 +1,109 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/net/socket_spec.h> + +using namespace vespalib; + +void verify(const SocketSpec &spec, bool valid, const vespalib::string &path, const vespalib::string &host, int port) { + EXPECT_EQUAL(spec.valid(), valid); + EXPECT_EQUAL(spec.path(), path); + EXPECT_EQUAL(spec.host(), host); + EXPECT_EQUAL(spec.port(), port); +} + +void verify(const SocketSpec &spec, const vespalib::string &path) { + TEST_DO(verify(spec, true, path, "", -1)); +} + +void verify(const SocketSpec &spec, const vespalib::string &host, int port) { + TEST_DO(verify(spec, true, "", host, port)); +} + +void verify(const SocketSpec &spec, int port) { + TEST_DO(verify(spec, true, "", "", port)); +} + +void verify_invalid(const SocketSpec &spec) { + TEST_DO(verify(spec, false, "", "", -1)); +} + +//----------------------------------------------------------------------------- + +TEST("require that socket spec can be created directly from path") { + TEST_DO(verify(SocketSpec::from_path("my_path"), "my_path")); +} + +TEST("require that socket spec can be created directly from host and port") { + TEST_DO(verify(SocketSpec::from_host_port("my_host", 123), "my_host", 123)); +} + +TEST("require that socket spec can be created directly from port only") { + TEST_DO(verify(SocketSpec::from_port(123), 123)); +} + +TEST("require that empty spec is invalid") { + TEST_DO(verify_invalid(SocketSpec(""))); +} + +TEST("require that bogus spec is invalid") { + TEST_DO(verify_invalid(SocketSpec("bogus"))); +} + +TEST("require that socket spec can parse ipc spec") { + TEST_DO(verify(SocketSpec("ipc/file:my_path"), "my_path")); +} + +TEST("require that empty ipc path gives invalid socket spec") { + TEST_DO(verify_invalid(SocketSpec("ipc/file:"))); +} + +TEST("require that socket spec can parse host/port spec") { + TEST_DO(verify(SocketSpec("tcp/my_host:123"), "my_host", 123)); +} + +TEST("require that socket spec can parse port only spec") { + TEST_DO(verify(SocketSpec("tcp/123"), 123)); +} + +TEST("require that socket spec can parse the one true listen spec") { + TEST_DO(verify(SocketSpec("tcp/0"), 0)); +} + +TEST("require that host port separator can be given also without host") { + TEST_DO(verify(SocketSpec("tcp/:123"), 123)); + TEST_DO(verify(SocketSpec("tcp/:0"), 0)); +} + +TEST("require that non-number port gives invalid spec") { + TEST_DO(verify_invalid(SocketSpec("tcp/host:xyz"))); + TEST_DO(verify_invalid(SocketSpec("tcp/xyz"))); +} + +TEST("require that negative port gives invalid spec") { + TEST_DO(verify_invalid(SocketSpec("tcp/host:-123"))); + TEST_DO(verify_invalid(SocketSpec("tcp/-123"))); +} + +TEST("require that missing port number gives invalid spec") { + TEST_DO(verify_invalid(SocketSpec("tcp/host:"))); + TEST_DO(verify_invalid(SocketSpec("tcp/"))); +} + +TEST("require that host can be quoted") { + TEST_DO(verify(SocketSpec("tcp/[my:host]:123"), "my:host", 123)); +} + +TEST("require that missing host can be quoted") { + TEST_DO(verify(SocketSpec("tcp/[]:123"), 123)); +} + +TEST("require that partial quotes are treated as host") { + TEST_DO(verify(SocketSpec("tcp/[:123"), "[", 123)); + TEST_DO(verify(SocketSpec("tcp/]:123"), "]", 123)); +} + +TEST("require that inconvenient hosts can be parsed without quotes") { + TEST_DO(verify(SocketSpec("tcp/my:host:123"), "my:host", 123)); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/vespa/vespalib/net/CMakeLists.txt b/vespalib/src/vespa/vespalib/net/CMakeLists.txt index 40b8b656db7..303d16db41e 100644 --- a/vespalib/src/vespa/vespalib/net/CMakeLists.txt +++ b/vespalib/src/vespa/vespalib/net/CMakeLists.txt @@ -6,5 +6,6 @@ vespa_add_library(vespalib_vespalib_net OBJECT socket.cpp socket_address.cpp socket_handle.cpp + socket_spec.cpp DEPENDS ) diff --git a/vespalib/src/vespa/vespalib/net/socket_spec.cpp b/vespalib/src/vespa/vespalib/net/socket_spec.cpp new file mode 100644 index 00000000000..09d26417948 --- /dev/null +++ b/vespalib/src/vespa/vespalib/net/socket_spec.cpp @@ -0,0 +1,69 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "socket_spec.h" + +namespace vespalib { + +namespace { + +const vespalib::string tcp_prefix("tcp/"); +const vespalib::string ipc_prefix("ipc/file:"); + +} // namespace vespalib::<unnamed> + +SocketSpec::SocketSpec(const vespalib::string &spec) + : SocketSpec() +{ + if (starts_with(spec, ipc_prefix)) { + _path = spec.substr(ipc_prefix.size()); + } else if (starts_with(spec, tcp_prefix)) { + bool with_host = (spec.find(':') != spec.npos); + const char *port_str = spec.c_str() + (with_host + ? (spec.rfind(':') + 1) + : tcp_prefix.size()); + int port = atoi(port_str); + if ((port > 0) || (strcmp(port_str, "0") == 0)) { + _port = port; + if (with_host) { + const char *host_str = spec.c_str() + tcp_prefix.size(); + size_t host_str_len = (port_str - host_str) - 1; + if ((host_str_len >= 2) + && (host_str[0] == '[') + && (host_str[host_str_len - 1] == ']')) + { + ++host_str; + host_str_len -= 2; + } + _host.assign(host_str, host_str_len); + } + } + } +} + +SocketAddress +SocketSpec::client_address() const +{ + if (!valid()) { + return SocketAddress(); + } + if (!_path.empty()) { + return SocketAddress::from_path(_path); + } + const char *node = _host.empty() ? "localhost" : _host.c_str(); + return SocketAddress::select_remote(_port, node); +} + +SocketAddress +SocketSpec::server_address() const +{ + if (!valid()) { + return SocketAddress(); + } + if (!_path.empty()) { + return SocketAddress::from_path(_path); + } + const char *node = _host.empty() ? nullptr : _host.c_str(); + return SocketAddress::select_local(_port, node); +} + +} // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/socket_spec.h b/vespalib/src/vespa/vespalib/net/socket_spec.h new file mode 100644 index 00000000000..cd8a546a9fd --- /dev/null +++ b/vespalib/src/vespa/vespalib/net/socket_spec.h @@ -0,0 +1,42 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <vespa/vespalib/stllike/string.h> +#include "socket_address.h" + +namespace vespalib { + +/** + * High-level socket address specification. + **/ +class SocketSpec +{ +private: + vespalib::string _path; + vespalib::string _host; + int _port; + + SocketSpec() : _path(), _host(), _port(-1) {} + SocketSpec(const vespalib::string &path, const vespalib::string &host, int port) + : _path(path), _host(host), _port(port) {} +public: + SocketSpec(const vespalib::string &spec); + static SocketSpec from_path(const vespalib::string &path) { + return SocketSpec(path, "", -1); + } + static SocketSpec from_host_port(const vespalib::string &host, int port) { + return SocketSpec("", host, port); + } + static SocketSpec from_port(int port) { + return SocketSpec("", "", port); + } + bool valid() const { return (!_path.empty() || (_port >= 0)); } + const vespalib::string &path() const { return _path; } + const vespalib::string &host() const { return _host; } + int port() const { return _port; } + SocketAddress client_address() const; + SocketAddress server_address() const; +}; + +} // namespace vespalib |