aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2019-01-31 11:06:04 -0500
committerJack Lloyd <[email protected]>2019-01-31 11:07:59 -0500
commitf52cde49f5fcf8aa3a72c15c665940c16756a16b (patch)
treeb31eb1030d7c3d1bad779488def4c26cc3e8a4c9
parentb508bcf6c9f29319a198ad97975343d5ba3e8516 (diff)
Add a simple Thread_Pool test
And allow registering one-off functions as tests
-rw-r--r--src/tests/test_thread_utils.cpp56
-rw-r--r--src/tests/tests.h32
2 files changed, 88 insertions, 0 deletions
diff --git a/src/tests/test_thread_utils.cpp b/src/tests/test_thread_utils.cpp
new file mode 100644
index 000000000..2374df860
--- /dev/null
+++ b/src/tests/test_thread_utils.cpp
@@ -0,0 +1,56 @@
+/*
+* (C) 2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+
+#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_THREAD_UTILS)
+
+#include <botan/internal/thread_pool.h>
+#include <chrono>
+
+namespace Botan_Tests {
+
+// TODO test Barrier
+// TODO test Semaphore
+
+namespace {
+
+Test::Result thread_pool()
+ {
+ Test::Result result("Thread_Pool");
+
+ // Using lots of threads since here the works spend most of the time sleeping
+ Botan::Thread_Pool pool(16);
+
+ auto sleep_and_return = [](size_t x) -> size_t {
+ std::this_thread::sleep_for(std::chrono::milliseconds((x*97)%127));
+ return x;
+ };
+
+ std::vector<std::future<size_t>> futures;
+ for(size_t i = 0; i != 100; ++i)
+ {
+ auto fut = pool.run(sleep_and_return, i);
+ futures.push_back(std::move(fut));
+ }
+
+ for(size_t i = 0; i != futures.size(); ++i)
+ {
+ result.test_eq("Expected return value", futures[i].get(), i);
+ }
+
+ pool.shutdown();
+
+ return result;
+ }
+
+BOTAN_REGISTER_TEST_FN("thread_pool", thread_pool);
+
+}
+
+}
+
+#endif
diff --git a/src/tests/tests.h b/src/tests/tests.h
index 4bf9fb0db..22651ff8c 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -530,6 +530,38 @@ class Test
#define BOTAN_REGISTER_TEST(type, Test_Class) \
Test::Registration<Test_Class> reg_ ## Test_Class ## _tests(type)
+typedef Test::Result (*test_fn)();
+
+class FnTest : public Test
+ {
+ public:
+ FnTest(test_fn fn) : m_fn(fn) {}
+
+ std::vector<Test::Result> run() override
+ {
+ return {m_fn()};
+ }
+
+ private:
+ test_fn m_fn;
+ };
+
+class FnRegistration
+ {
+ public:
+ FnRegistration(const std::string& name, test_fn fn)
+ {
+ if(Test::global_registry().count(name) != 0)
+ throw Test_Error("Duplicate registration of test '" + name + "'");
+
+ auto maker = [=]() -> Test* { return new FnTest(fn); };
+ Test::global_registry().insert(std::make_pair(name, maker));
+ }
+ };
+
+#define BOTAN_REGISTER_TEST_FN(test_name, fn_name) \
+ FnRegistration reg_ ## fn_name(test_name, fn_name)
+
class VarMap
{
public: