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()