diff --git a/Makefile.am b/Makefile.am index 925c10c1..248cb3b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,10 +60,15 @@ test_libbitcoin_protocol_test_LDADD = src/libbitcoin-protocol.la ${boost_unit_te test_libbitcoin_protocol_test_SOURCES = \ test/converter.cpp \ test/main.cpp \ - test/protocol.cpp \ - test/zmq/ironhouse2.cpp \ + test/examples/authenticator_example.cpp \ + test/examples/poller_example.cpp \ + test/zmq/authenticator.cpp \ + test/zmq/certificate.cpp \ + test/zmq/context.cpp \ + test/zmq/frame.cpp \ + test/zmq/message.cpp \ test/zmq/poller.cpp \ - test/zmq/zmq.cpp + test/zmq/socket.cpp endif WITH_TESTS diff --git a/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj b/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj index ace3cb35..b1ccdcbd 100644 --- a/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj +++ b/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj @@ -66,11 +66,16 @@ + + - - + + + + + - + diff --git a/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj.filters b/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj.filters index 3feb3063..1459f16a 100644 --- a/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj.filters +++ b/builds/msvc/vs2013/libbitcoin-protocol-test/libbitcoin-protocol-test.vcxproj.filters @@ -10,25 +10,43 @@ {be07d12d-9dae-4731-8b0d-acdec8ab7968} + + {cb493992-f913-4264-a0f1-33913ccc69e5} + src - - src - src - + src\zmq - + + src\zmq + + src\zmq src\zmq + + src\zmq + + + src\zmq + + + src\zmq + + + src\examples + + + src\examples + \ No newline at end of file diff --git a/include/bitcoin/protocol/zmq/context.hpp b/include/bitcoin/protocol/zmq/context.hpp index 205e9884..6e35551e 100644 --- a/include/bitcoin/protocol/zmq/context.hpp +++ b/include/bitcoin/protocol/zmq/context.hpp @@ -47,7 +47,7 @@ class BCP_API context context(const context&) = delete; void operator=(const context&) = delete; - /// True if the context construction was successful. + /// True if the context is valid. operator const bool() const; /// The underlying zeromq context. @@ -57,7 +57,6 @@ class BCP_API context bool stop(); private: - int32_t threads_; void* self_; }; diff --git a/include/bitcoin/protocol/zmq/socket.hpp b/include/bitcoin/protocol/zmq/socket.hpp index 345db2df..e5f2df0e 100644 --- a/include/bitcoin/protocol/zmq/socket.hpp +++ b/include/bitcoin/protocol/zmq/socket.hpp @@ -70,7 +70,7 @@ class BCP_API socket /// Free socket resources. virtual ~socket(); - /// True if there is an encapsultaed zeromq socket. + /// True if the socket is valid. operator const bool() const; /// The underlying zeromq socket. diff --git a/libbitcoin_protocol_test_runner.sh b/libbitcoin_protocol_test_runner.sh index 21eedbe9..a26032a4 100755 --- a/libbitcoin_protocol_test_runner.sh +++ b/libbitcoin_protocol_test_runner.sh @@ -9,7 +9,7 @@ # Define tests and options. #============================================================================== BOOST_UNIT_TEST_OPTIONS=\ -"--run_test=* "\ +"--run_test=authenticator_tests,certificate_tests,context_tests,frame_tests,message_tests,poller_tests,socket_tests "\ "--show_progress=no "\ "--detect_memory_leak=0 "\ "--report_level=no "\ diff --git a/src/packet.cpp b/src/packet.cpp index 8b9591bf..58839a87 100644 --- a/src/packet.cpp +++ b/src/packet.cpp @@ -17,6 +17,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +#ifdef LIBBITCOIN_VERSION4 + #include #include @@ -88,3 +90,5 @@ bool packet::send(zmq::socket& socket) } } + +#endif diff --git a/src/zmq/certificate.cpp b/src/zmq/certificate.cpp index 3361a136..91db9be0 100644 --- a/src/zmq/certificate.cpp +++ b/src/zmq/certificate.cpp @@ -90,7 +90,7 @@ bool certificate::create(std::string& out_public, std::string& out_private, if (zmq_curve_keypair(public_key, private_key) == zmq_fail) return false; - if (!setting || (ok_setting(public_key) && ok_setting(private_key))) + if (!setting || ((ok_setting(public_key) && ok_setting(private_key)))) { out_public = public_key; out_private = private_key; diff --git a/src/zmq/context.cpp b/src/zmq/context.cpp index 56f91fe5..972d55d3 100644 --- a/src/zmq/context.cpp +++ b/src/zmq/context.cpp @@ -28,11 +28,9 @@ namespace protocol { namespace zmq { static constexpr int32_t zmq_fail = -1; -static constexpr int32_t zmq_io_threads = 1; context::context() - : threads_(zmq_io_threads), - self_(zmq_init(threads_)) + : self_(zmq_ctx_new()) { } @@ -41,6 +39,8 @@ context::~context() stop(); } +// This could be made non-blocking by using zmq_ctx_shutdown here and +// zmq_ctx_term in a close method (invoked from the destructor). bool context::stop() { if (self() == nullptr) @@ -49,7 +49,9 @@ bool context::stop() // This aborts blocking operations but blocks here until either each socket // in the context is explicitly closed. // It is possible for this to fail due to signal interrupt. - return zmq_term(self_) != zmq_fail; + const auto result = zmq_ctx_term(self_) != zmq_fail; + self_ = nullptr; + return result; } context::operator const bool() const diff --git a/src/zmq/socket.cpp b/src/zmq/socket.cpp index 8dcf2514..837e4962 100644 --- a/src/zmq/socket.cpp +++ b/src/zmq/socket.cpp @@ -97,6 +97,11 @@ bool socket::stop() return closed; } +socket::operator const bool() const +{ + return socket_ != nullptr; +} + void socket::assign(socket&& other) { // Free any existing socket resources. @@ -174,11 +179,6 @@ socket::identifier socket::id() const return reinterpret_cast(socket_); } -socket::operator const bool() const -{ - return socket_ != nullptr; -} - } // namespace zmq } // namespace protocol } // namespace libbitcoin diff --git a/test/zmq/ironhouse2.cpp b/test/examples/authenticator_example.cpp similarity index 98% rename from test/zmq/ironhouse2.cpp rename to test/examples/authenticator_example.cpp index 490ec015..508a0e96 100644 --- a/test/zmq/ironhouse2.cpp +++ b/test/examples/authenticator_example.cpp @@ -94,7 +94,8 @@ void client_task(const std::string& client_private_key, puts("Ironhouse test OK"); } -int ironhouse2_example() +// TODO: move to test case. +int authenticator_example() { static const auto localhost = config::authority("127.0.0.1"); diff --git a/test/examples/poller_example.cpp b/test/examples/poller_example.cpp new file mode 100644 index 00000000..ed4eef7c --- /dev/null +++ b/test/examples/poller_example.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin-protocol. + * + * libbitcoin-protocol is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License with + * additional permissions to the one published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. For more information see LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include +#include + +using namespace bc; +using namespace bc::protocol; + +// TODO: move to test case. +int poller_example() +{ + zmq::context context; + assert(context); + + // Create a few sockets + zmq::socket vent(context, zmq::socket::role::pusher); + auto result = vent.bind("tcp://*:9000"); + assert(result); + + zmq::socket sink(context, zmq::socket::role::puller); + result = sink.connect("tcp://localhost:9000"); + assert(result); + + zmq::socket bowl(context, zmq::socket::role::puller); + zmq::socket dish(context, zmq::socket::role::puller); + + // Set-up poller. + zmq::poller poller; + poller.add(bowl); + poller.add(sink); + poller.add(dish); + + const std::string hello = "Hello, World"; + + // Build and send the message. + zmq::message message; + message.enqueue(hello); + result = message.send(vent); + assert(result); + + // We expect a message only on the sink. + const auto id = poller.wait(-1); + assert(id == sink.id()); + assert(!poller.expired()); + assert(!poller.terminated()); + + // Receive the message. + result = message.receive(sink); + assert(result); + + // Check the size. + assert(message.size() == 1); + + // Check the value. + const auto payload = message.dequeue_text(); + assert(payload == hello); + return 0; +} diff --git a/test/zmq/authenticator.cpp b/test/zmq/authenticator.cpp new file mode 100644 index 00000000..43429c36 --- /dev/null +++ b/test/zmq/authenticator.cpp @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin-protocol. + * + * libbitcoin-protocol is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License with + * additional permissions to the one published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. For more information see LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(authenticator_tests) + +BOOST_AUTO_TEST_CASE(authenticator_test) +{ +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/zmq/certificate.cpp b/test/zmq/certificate.cpp new file mode 100644 index 00000000..69c6e151 --- /dev/null +++ b/test/zmq/certificate.cpp @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin-protocol. + * + * libbitcoin-protocol is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License with + * additional permissions to the one published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. For more information see LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include +#include +#include + +using namespace bc; +using namespace bc::protocol::zmq; + +// These tests don't validate calls to zmq_curve_keypair or zmq_curve_public. +// These should be moved to trivial virtual methods for test isolation. + +BOOST_AUTO_TEST_SUITE(certificate_tests) + +static std::string base85_alphabet = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + ".-:+=^!/*?&<>()[]{}@%$#"; + + +static const std::string null_private_key = "0000000000000000000000000000000000000000"; +static const std::string null_public_key = "fxERSn6LHg6!4!qu+m-(f-Q<1UF!=7)u0-ysJ-^F"; + +static inline bool is_valid(const std::string& key, bool setting) +{ + for (const auto letter: key) + { + if (setting && letter == '#') + return false; + + if (base85_alphabet.find_first_of(letter) == std::string::npos) + return false; + } + + return key.size() == 40; +} + +class certificate_fixture + : public certificate +{ +public: + static bool derive(std::string& out_public, const std::string& private_key) + { + return certificate::derive(out_public, private_key); + } + + static bool create(std::string& out_public, std::string& out_private, + bool setting) + { + return certificate::create(out_public, out_private, setting); + } +}; + +BOOST_AUTO_TEST_CASE(certificate__construct1__default__creates_valid_keypair) +{ + certificate instance; + BOOST_REQUIRE(instance); + BOOST_REQUIRE(is_valid(instance.public_key(), false)); + BOOST_REQUIRE(is_valid(instance.private_key(), false)); +} + +BOOST_AUTO_TEST_CASE(certificate__construct1__setting__creates_valid_keypair) +{ + certificate instance(true); + BOOST_REQUIRE(instance); + BOOST_REQUIRE(is_valid(instance.public_key(), true)); + BOOST_REQUIRE(is_valid(instance.private_key(), true)); +} + +BOOST_AUTO_TEST_CASE(certificate__construct2__null_hash__expected_keypair) +{ + certificate instance(null_hash); + BOOST_REQUIRE(instance); + BOOST_REQUIRE_EQUAL(instance.public_key(), null_public_key); + BOOST_REQUIRE_EQUAL(instance.private_key(), null_private_key); +} + +BOOST_AUTO_TEST_CASE(certificate__construct3__null_key_string__expected_keypair) +{ + certificate instance(null_private_key); + BOOST_REQUIRE(instance); + BOOST_REQUIRE_EQUAL(instance.public_key(), null_public_key); + BOOST_REQUIRE_EQUAL(instance.private_key(), null_private_key); +} + +BOOST_AUTO_TEST_CASE(certificate__construct3__bogus_invalid_and_empty_keypair) +{ + certificate instance(std::string("bogus")); + BOOST_REQUIRE(!instance); + BOOST_REQUIRE_EQUAL(instance.public_key(), ""); + BOOST_REQUIRE_EQUAL(instance.private_key(), ""); +} + +BOOST_AUTO_TEST_CASE(certificate__derive__bogus__false_value_unchanged) +{ + const auto expected = "42"; + std::string out_public = expected; + BOOST_REQUIRE(!certificate_fixture::derive(out_public, "bogus")); + BOOST_REQUIRE_EQUAL(out_public, expected); +} + +BOOST_AUTO_TEST_CASE(certificate__derive__null_string__expected_public_key) +{ + std::string out_public; + BOOST_REQUIRE(certificate_fixture::derive(out_public, null_private_key)); + BOOST_REQUIRE_EQUAL(out_public, null_public_key); +} + +BOOST_AUTO_TEST_CASE(certificate__create__default__valid_keypair) +{ + std::string out_public; + std::string out_private; + BOOST_REQUIRE(certificate_fixture::create(out_public, out_private, false)); + BOOST_REQUIRE(is_valid(out_public, false)); + BOOST_REQUIRE(is_valid(out_private, false)); +} + +BOOST_AUTO_TEST_CASE(certificate__create__setting__valid_keypair) +{ + std::string out_public; + std::string out_private; + BOOST_REQUIRE(certificate_fixture::create(out_public, out_private, true)); + BOOST_REQUIRE(is_valid(out_public, true)); + BOOST_REQUIRE(is_valid(out_private, true)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/zmq/context.cpp b/test/zmq/context.cpp new file mode 100644 index 00000000..01267588 --- /dev/null +++ b/test/zmq/context.cpp @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin-protocol. + * + * libbitcoin-protocol is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License with + * additional permissions to the one published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. For more information see LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include +#include +#include + +using namespace bc::protocol::zmq; + +// These tests don't validate calls to zmq_ctx_new or zmq_ctx_term. +// These should be moved to trivial virtual methods for test isolation. + +BOOST_AUTO_TEST_SUITE(context_tests) + +BOOST_AUTO_TEST_CASE(context__constructor__always__creates_valid_instance) +{ + context instance; + BOOST_REQUIRE(instance); +} + +BOOST_AUTO_TEST_CASE(context__stop__always__invalidates_instance) +{ + context instance; + instance.stop(); + BOOST_REQUIRE(!instance); +} + +BOOST_AUTO_TEST_CASE(context__self__valid_instance__is_not_null) +{ + context instance; + BOOST_REQUIRE(instance.self() != nullptr); +} + +BOOST_AUTO_TEST_CASE(context__self__invalid_instance__is_null) +{ + context instance; + instance.stop(); + BOOST_REQUIRE(instance.self() == nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/zmq/zmq.cpp b/test/zmq/frame.cpp similarity index 88% rename from test/zmq/zmq.cpp rename to test/zmq/frame.cpp index bf49ef98..6b64341a 100644 --- a/test/zmq/zmq.cpp +++ b/test/zmq/frame.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS) + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) * * This file is part of libbitcoin-protocol. * @@ -21,9 +21,9 @@ #include #include -BOOST_AUTO_TEST_SUITE(zmq_tests) +BOOST_AUTO_TEST_SUITE(frame_tests) -BOOST_AUTO_TEST_CASE(zmq_test) +BOOST_AUTO_TEST_CASE(frame_test) { } diff --git a/test/protocol.cpp b/test/zmq/message.cpp similarity index 87% rename from test/protocol.cpp rename to test/zmq/message.cpp index 868b8acd..e0e7f155 100644 --- a/test/protocol.cpp +++ b/test/zmq/message.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS) + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) * * This file is part of libbitcoin-protocol. * @@ -21,9 +21,9 @@ #include #include -BOOST_AUTO_TEST_SUITE(protocol_tests) +BOOST_AUTO_TEST_SUITE(message_tests) -BOOST_AUTO_TEST_CASE(protocol_test) +BOOST_AUTO_TEST_CASE(message_test) { } diff --git a/test/zmq/poller.cpp b/test/zmq/poller.cpp index 2e415e14..6c5eb09c 100644 --- a/test/zmq/poller.cpp +++ b/test/zmq/poller.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS) + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) * * This file is part of libbitcoin-protocol. * @@ -17,58 +17,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#include +#include +#include #include -using namespace bc; -using namespace bc::protocol; +BOOST_AUTO_TEST_SUITE(poller_tests) -int poller_example() +BOOST_AUTO_TEST_CASE(poller_test) { - zmq::context context; - assert(context); - - // Create a few sockets - zmq::socket vent(context, zmq::socket::role::pusher); - auto result = vent.bind("tcp://*:9000"); - assert(result); - - zmq::socket sink(context, zmq::socket::role::puller); - result = sink.connect("tcp://localhost:9000"); - assert(result); - - zmq::socket bowl(context, zmq::socket::role::puller); - zmq::socket dish(context, zmq::socket::role::puller); - - // Set-up poller. - zmq::poller poller; - poller.add(bowl); - poller.add(sink); - poller.add(dish); - - const std::string hello = "Hello, World"; - - // Build and send the message. - zmq::message message; - message.enqueue(hello); - result = message.send(vent); - assert(result); - - // We expect a message only on the sink. - const auto id = poller.wait(-1); - assert(id == sink.id()); - assert(!poller.expired()); - assert(!poller.terminated()); - - // Receive the message. - result = message.receive(sink); - assert(result); - - // Check the size. - assert(message.size() == 1); - - // Check the value. - const auto payload = message.dequeue_text(); - assert(payload == hello); - return 0; } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/zmq/socket.cpp b/test/zmq/socket.cpp new file mode 100644 index 00000000..9185ddb4 --- /dev/null +++ b/test/zmq/socket.cpp @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin-protocol. + * + * libbitcoin-protocol is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License with + * additional permissions to the one published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. For more information see LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(socket_tests) + +BOOST_AUTO_TEST_CASE(socket_test) +{ +} + +BOOST_AUTO_TEST_SUITE_END()