Unverified Commit cc7f3496 authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #1514

Move legacy tests to proper subfolder
parents 10f1f01f f901e643
...@@ -109,16 +109,16 @@ elseif(MSVC) ...@@ -109,16 +109,16 @@ elseif(MSVC)
target_compile_options(caf_internal INTERFACE /EHsc) target_compile_options(caf_internal INTERFACE /EHsc)
endif() endif()
# -- unit testing setup / caf_add_test_suites function ------------------------ # -- unit testing setup / caf_add_legacy_test_suites function ------------------------
if(CAF_ENABLE_TESTING) if(CAF_ENABLE_TESTING)
enable_testing() enable_testing()
function(caf_add_test_suites target) function(caf_add_legacy_test_suites target)
foreach(suiteName ${ARGN}) foreach(suiteName ${ARGN})
if(NOT ${suiteName} IN_LIST CAF_EXCLUDE_TESTS) if(NOT ${suiteName} IN_LIST CAF_EXCLUDE_TESTS)
string(REPLACE "." "/" suitePath ${suiteName}) string(REPLACE "." "/" suitePath ${suiteName})
target_sources(${target} PRIVATE target_sources(${target} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/test/${suitePath}.cpp") "${CMAKE_CURRENT_SOURCE_DIR}/tests/legacy/${suitePath}.cpp")
add_test(NAME ${suiteName} add_test(NAME ${suiteName}
COMMAND ${target} -r300 -n -v5 -s "^${suiteName}$") COMMAND ${target} -r300 -n -v5 -s "^${suiteName}$")
endif() endif()
...@@ -313,14 +313,14 @@ endfunction() ...@@ -313,14 +313,14 @@ endfunction()
# ... # ...
# SOURCES # SOURCES
# ... # ...
# TEST_SOURCES # LEGACY_TEST_SOURCES
# ... # ...
# TEST_SUITES # LEGACY_TEST_SUITES
# ... # ...
# ) # )
function(caf_add_component name) function(caf_add_component name)
set(varargs DEPENDENCIES HEADERS SOURCES TEST_SOURCES TEST_SUITES ENUM_TYPES set(varargs DEPENDENCIES HEADERS SOURCES ENUM_TYPES LEGACY_TEST_SOURCES
LEGACY_TEST_SOURCES LEGACY_TEST_SUITES) LEGACY_TEST_SUITES)
cmake_parse_arguments(CAF_ADD_COMPONENT "" "" "${varargs}" ${ARGN}) cmake_parse_arguments(CAF_ADD_COMPONENT "" "" "${varargs}" ${ARGN})
if(NOT CAF_ADD_COMPONENT_HEADERS) if(NOT CAF_ADD_COMPONENT_HEADERS)
message(FATAL_ERROR "Cannot add CAF component without at least one header.") message(FATAL_ERROR "Cannot add CAF component without at least one header.")
...@@ -369,20 +369,6 @@ function(caf_add_component name) ...@@ -369,20 +369,6 @@ function(caf_add_component name)
"${PROJECT_SOURCE_DIR}/cmake/dummy.cpp" "${PROJECT_SOURCE_DIR}/cmake/dummy.cpp"
$<TARGET_OBJECTS:${obj_lib_target}>) $<TARGET_OBJECTS:${obj_lib_target}>)
endif() endif()
if(CAF_ENABLE_TESTING AND CAF_ADD_COMPONENT_TEST_SOURCES)
set(tst_bin_target "caf-${name}-test")
list(APPEND targets ${tst_bin_target})
add_executable(${tst_bin_target}
${CAF_ADD_COMPONENT_TEST_SOURCES}
$<TARGET_OBJECTS:${obj_lib_target}>)
target_link_libraries(${tst_bin_target} PRIVATE libcaf_test
${CAF_ADD_COMPONENT_DEPENDENCIES})
target_include_directories(${tst_bin_target} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/test")
if(CAF_ADD_COMPONENT_TEST_SUITES)
caf_add_test_suites(${tst_bin_target} ${CAF_ADD_COMPONENT_TEST_SUITES})
endif()
endif()
if(CAF_ENABLE_TESTING AND CAF_ADD_COMPONENT_LEGACY_TEST_SOURCES) if(CAF_ENABLE_TESTING AND CAF_ADD_COMPONENT_LEGACY_TEST_SOURCES)
set(tst_bin_target "caf-${name}-legacy-test") set(tst_bin_target "caf-${name}-legacy-test")
list(APPEND targets ${tst_bin_target}) list(APPEND targets ${tst_bin_target})
...@@ -392,9 +378,9 @@ function(caf_add_component name) ...@@ -392,9 +378,9 @@ function(caf_add_component name)
target_link_libraries(${tst_bin_target} PRIVATE libcaf_test target_link_libraries(${tst_bin_target} PRIVATE libcaf_test
${CAF_ADD_COMPONENT_DEPENDENCIES}) ${CAF_ADD_COMPONENT_DEPENDENCIES})
target_include_directories(${tst_bin_target} PRIVATE target_include_directories(${tst_bin_target} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/test") "${CMAKE_CURRENT_SOURCE_DIR}/tests/legacy")
if(CAF_ADD_COMPONENT_LEGACY_TEST_SUITES) if(CAF_ADD_COMPONENT_LEGACY_TEST_SUITES)
caf_add_test_suites(${tst_bin_target} ${CAF_ADD_COMPONENT_LEGACY_TEST_SUITES}) caf_add_legacy_test_suites(${tst_bin_target} ${CAF_ADD_COMPONENT_LEGACY_TEST_SUITES})
endif() endif()
endif() endif()
target_link_libraries(${pub_lib_target} ${CAF_ADD_COMPONENT_DEPENDENCIES}) target_link_libraries(${pub_lib_target} ${CAF_ADD_COMPONENT_DEPENDENCIES})
......
...@@ -224,8 +224,8 @@ caf_add_component( ...@@ -224,8 +224,8 @@ caf_add_component(
caf/uri_builder.cpp caf/uri_builder.cpp
caf/uuid.cpp caf/uuid.cpp
LEGACY_TEST_SOURCES LEGACY_TEST_SOURCES
test/core-test.cpp tests/legacy/core-test.cpp
test/nasty.cpp tests/legacy/nasty.cpp
LEGACY_TEST_SUITES LEGACY_TEST_SUITES
action action
actor_clock actor_clock
...@@ -386,5 +386,5 @@ if(NOT CAF_USE_STD_FORMAT) ...@@ -386,5 +386,5 @@ if(NOT CAF_USE_STD_FORMAT)
endif() endif()
if(CAF_ENABLE_TESTING AND CAF_ENABLE_EXCEPTIONS) if(CAF_ENABLE_TESTING AND CAF_ENABLE_EXCEPTIONS)
caf_add_test_suites(caf-core-legacy-test custom_exception_handler) caf_add_legacy_test_suites(caf-core-legacy-test custom_exception_handler)
endif() endif()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.drr_cached_queue
#include "caf/intrusive/drr_cached_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) : value(x) {
// nop
}
};
std::string to_string(const inode& x) {
return std::to_string(x.value);
}
struct inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
static inline task_size_type task_size(const mapped_type&) noexcept {
return 1;
}
};
using queue_type = drr_cached_queue<inode_policy>;
struct fixture {
inode_policy policy;
queue_type queue{policy};
template <class Queue>
void fill(Queue&) {
// nop
}
template <class Queue, class T, class... Ts>
void fill(Queue& q, T x, Ts... xs) {
q.emplace_back(x);
fill(q, xs...);
}
};
auto make_new_round_result(size_t consumed_items, bool stop_all) {
return new_round_result{consumed_items, stop_all};
}
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
CAF_REQUIRE_EQUAL(queue.deficit(), 0);
CAF_REQUIRE_EQUAL(queue.total_task_size(), 0);
CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
}
CAF_TEST(new_round) {
// Define a function object for consuming even numbers.
std::string fseq;
auto f = [&](inode& x) -> task_result {
if ((x.value & 0x01) == 1)
return task_result::skip;
fseq += to_string(x);
return task_result::resume;
};
// Define a function object for consuming odd numbers.
std::string gseq;
auto g = [&](inode& x) -> task_result {
if ((x.value & 0x01) == 0)
return task_result::skip;
gseq += to_string(x);
return task_result::resume;
};
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Allow f to consume 2, 4, and 6.
auto round_result = queue.new_round(3, f);
CHECK_EQ(round_result, make_new_round_result(3, false));
CHECK_EQ(fseq, "246");
CHECK_EQ(queue.deficit(), 0);
// Allow g to consume 1, 3, 5, and 7.
round_result = queue.new_round(4, g);
CHECK_EQ(round_result, make_new_round_result(4, false));
CHECK_EQ(gseq, "1357");
CHECK_EQ(queue.deficit(), 0);
}
CAF_TEST(skipping) {
// Define a function object for consuming even numbers.
std::string seq;
auto f = [&](inode& x) -> task_result {
if ((x.value & 0x01) == 1)
return task_result::skip;
seq += to_string(x);
return task_result::resume;
};
MESSAGE("make a round on an empty queue");
CHECK_EQ(queue.new_round(10, f), make_new_round_result(0, false));
MESSAGE("make a round on a queue with only odd numbers (skip all)");
fill(queue, 1, 3, 5);
CHECK_EQ(queue.new_round(10, f), make_new_round_result(0, false));
MESSAGE("make a round on a queue with an even number at the front");
fill(queue, 2);
CHECK_EQ(queue.new_round(10, f), make_new_round_result(1, false));
CHECK_EQ(seq, "2");
MESSAGE("make a round on a queue with an even number in between");
fill(queue, 7, 9, 4, 11, 13);
CHECK_EQ(queue.new_round(10, f), make_new_round_result(1, false));
CHECK_EQ(seq, "24");
MESSAGE("make a round on a queue with an even number at the back");
fill(queue, 15, 17, 6);
CHECK_EQ(queue.new_round(10, f), make_new_round_result(1, false));
CHECK_EQ(seq, "246");
}
CAF_TEST(take_front) {
std::string seq;
fill(queue, 1, 2, 3, 4, 5, 6);
auto f = [&](inode& x) {
seq += to_string(x);
return task_result::resume;
};
CHECK_EQ(queue.deficit(), 0);
while (!queue.empty()) {
auto ptr = queue.take_front();
f(*ptr);
}
CHECK_EQ(seq, "123456");
fill(queue, 5, 4, 3, 2, 1);
while (!queue.empty()) {
auto ptr = queue.take_front();
f(*ptr);
}
CHECK_EQ(seq, "12345654321");
CHECK_EQ(queue.deficit(), 0);
}
CAF_TEST(alternating_consumer) {
using fun_type = std::function<task_result(inode&)>;
fun_type f;
fun_type g;
fun_type* selected = &f;
// Define a function object for consuming even numbers.
std::string seq;
f = [&](inode& x) -> task_result {
if ((x.value & 0x01) == 1)
return task_result::skip;
seq += to_string(x);
selected = &g;
return task_result::resume;
};
// Define a function object for consuming odd numbers.
g = [&](inode& x) -> task_result {
if ((x.value & 0x01) == 0)
return task_result::skip;
seq += to_string(x);
selected = &f;
return task_result::resume;
};
/// Define a function object that alternates between f and g.
auto h = [&](inode& x) { return (*selected)(x); };
// Fill and consume queue, h leaves 9 in the cache since it reads (odd, even)
// sequences and no odd value to read after 7 is available.
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9);
auto round_result = queue.new_round(1000, h);
CHECK_EQ(round_result, make_new_round_result(8, false));
CHECK_EQ(seq, "21436587");
CHECK_EQ(queue.deficit(), 0);
CHECK_EQ(deep_to_string(queue.cache()), "[9]");
}
CAF_TEST(peek_all) {
auto queue_to_string = [&] {
std::string str;
auto peek_fun = [&](const inode& x) {
if (!str.empty())
str += ", ";
str += std::to_string(x.value);
};
queue.peek_all(peek_fun);
return str;
};
CHECK_EQ(queue_to_string(), "");
queue.emplace_back(2);
CHECK_EQ(queue_to_string(), "2");
queue.cache().emplace_back(1);
CHECK_EQ(queue_to_string(), "2");
queue.emplace_back(3);
CHECK_EQ(queue_to_string(), "2, 3");
queue.flush_cache();
CHECK_EQ(queue_to_string(), "1, 2, 3");
}
CAF_TEST(to_string) {
CHECK_EQ(deep_to_string(queue.items()), "[]");
fill(queue, 3, 4);
CHECK_EQ(deep_to_string(queue.items()), "[3, 4]");
fill(queue.cache(), 1, 2);
CHECK_EQ(deep_to_string(queue.items()), "[3, 4]");
queue.flush_cache();
CHECK_EQ(deep_to_string(queue.items()), "[1, 2, 3, 4]");
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.drr_queue
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) : value(x) {
// nop
}
};
std::string to_string(const inode& x) {
return std::to_string(x.value);
}
struct inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
static inline task_size_type task_size(const mapped_type& x) {
return x.value;
}
};
using queue_type = drr_queue<inode_policy>;
struct fixture {
inode_policy policy;
queue_type queue{policy};
void fill(queue_type&) {
// nop
}
template <class T, class... Ts>
void fill(queue_type& q, T x, Ts... xs) {
q.emplace_back(x);
fill(q, xs...);
}
};
auto make_new_round_result(size_t consumed_items, bool stop_all) {
return new_round_result{consumed_items, stop_all};
}
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
CAF_REQUIRE_EQUAL(queue.deficit(), 0);
CAF_REQUIRE_EQUAL(queue.total_task_size(), 0);
CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
CAF_REQUIRE_EQUAL(queue.next(), nullptr);
CAF_REQUIRE_EQUAL(queue.begin(), queue.end());
}
CAF_TEST(inc_deficit) {
// Increasing the deficit does nothing as long as the queue is empty.
queue.inc_deficit(100);
CAF_REQUIRE_EQUAL(queue.deficit(), 0);
// Increasing the deficit must work on non-empty queues.
fill(queue, 1);
queue.inc_deficit(100);
CAF_REQUIRE_EQUAL(queue.deficit(), 100);
// Deficit must drop back down to 0 once the queue becomes empty.
queue.next();
CAF_REQUIRE_EQUAL(queue.deficit(), 0);
}
CAF_TEST(new_round) {
std::string seq;
fill(queue, 1, 2, 3, 4, 5, 6);
auto f = [&](inode& x) {
seq += to_string(x);
return task_result::resume;
};
// Allow f to consume 1, 2, and 3 with a leftover deficit of 1.
auto round_result = queue.new_round(7, f);
CHECK_EQ(round_result, make_new_round_result(3, false));
CHECK_EQ(seq, "123");
CHECK_EQ(queue.deficit(), 1);
// Allow f to consume 4 and 5 with a leftover deficit of 0.
round_result = queue.new_round(8, f);
CHECK_EQ(round_result, make_new_round_result(2, false));
CHECK_EQ(seq, "12345");
CHECK_EQ(queue.deficit(), 0);
// Allow f to consume 6 with a leftover deficit of 0 (queue is empty).
round_result = queue.new_round(1000, f);
CHECK_EQ(round_result, make_new_round_result(1, false));
CHECK_EQ(seq, "123456");
CHECK_EQ(queue.deficit(), 0);
// new_round on an empty queue does nothing.
round_result = queue.new_round(1000, f);
CHECK_EQ(round_result, make_new_round_result(0, false));
CHECK_EQ(seq, "123456");
CHECK_EQ(queue.deficit(), 0);
}
CAF_TEST(next) {
std::string seq;
fill(queue, 1, 2, 3, 4, 5, 6);
auto f = [&](inode& x) {
seq += to_string(x);
return task_result::resume;
};
auto take = [&] {
queue.flush_cache();
queue.inc_deficit(queue.peek()->value);
return queue.next();
};
while (!queue.empty()) {
auto ptr = take();
f(*ptr);
}
CHECK_EQ(seq, "123456");
fill(queue, 5, 4, 3, 2, 1);
while (!queue.empty()) {
auto ptr = take();
f(*ptr);
}
CHECK_EQ(seq, "12345654321");
CHECK_EQ(queue.deficit(), 0);
}
CAF_TEST(peek_all) {
auto queue_to_string = [&] {
std::string str;
auto peek_fun = [&](const inode& x) {
if (!str.empty())
str += ", ";
str += std::to_string(x.value);
};
queue.peek_all(peek_fun);
return str;
};
CHECK_EQ(queue_to_string(), "");
queue.emplace_back(1);
CHECK_EQ(queue_to_string(), "1");
queue.emplace_back(2);
CHECK_EQ(queue_to_string(), "1, 2");
queue.emplace_back(3);
CHECK_EQ(queue_to_string(), "1, 2, 3");
queue.emplace_back(4);
CHECK_EQ(queue_to_string(), "1, 2, 3, 4");
}
CAF_TEST(to_string) {
CHECK_EQ(deep_to_string(queue), "[]");
fill(queue, 1, 2, 3, 4);
CHECK_EQ(deep_to_string(queue), "[1, 2, 3, 4]");
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.fifo_inbox
#include "caf/intrusive/fifo_inbox.hpp"
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) : value(x) {
// nop
}
};
std::string to_string(const inode& x) {
return std::to_string(x.value);
}
struct inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
using queue_type = drr_queue<inode_policy>;
static constexpr task_size_type task_size(const inode&) noexcept {
return 1;
}
};
using inbox_type = fifo_inbox<inode_policy>;
struct fixture {
inode_policy policy;
inbox_type inbox{policy};
void fill(inbox_type&) {
// nop
}
template <class T, class... Ts>
void fill(inbox_type& i, T x, Ts... xs) {
i.emplace_back(x);
fill(i, xs...);
}
std::string fetch() {
std::string result;
auto f = [&](inode& x) {
result += to_string(x);
return task_result::resume;
};
inbox.new_round(1000, f);
return result;
}
std::string close_and_fetch() {
std::string result;
auto f = [&](inode& x) {
result += to_string(x);
return task_result::resume;
};
inbox.close();
inbox.queue().new_round(1000, f);
return result;
}
};
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(inbox.empty(), true);
}
CAF_TEST(push_front) {
fill(inbox, 1, 2, 3);
CAF_REQUIRE_EQUAL(close_and_fetch(), "123");
CAF_REQUIRE_EQUAL(inbox.closed(), true);
}
CAF_TEST(push_after_close) {
inbox.close();
auto res = inbox.push_back(new inode(0));
CAF_REQUIRE_EQUAL(res, inbox_result::queue_closed);
}
CAF_TEST(unblock) {
CAF_REQUIRE_EQUAL(inbox.try_block(), true);
auto res = inbox.push_back(new inode(0));
CAF_REQUIRE_EQUAL(res, inbox_result::unblocked_reader);
res = inbox.push_back(new inode(1));
CAF_REQUIRE_EQUAL(res, inbox_result::success);
CAF_REQUIRE_EQUAL(close_and_fetch(), "01");
}
CAF_TEST(await) {
std::mutex mx;
std::condition_variable cv;
std::thread t{[&] { inbox.synchronized_emplace_back(mx, cv, 1); }};
inbox.synchronized_await(mx, cv);
CAF_REQUIRE_EQUAL(close_and_fetch(), "1");
t.join();
}
CAF_TEST(timed_await) {
std::mutex mx;
std::condition_variable cv;
auto tout = std::chrono::system_clock::now();
tout += std::chrono::microseconds(1);
auto res = inbox.synchronized_await(mx, cv, tout);
CAF_REQUIRE_EQUAL(res, false);
fill(inbox, 1);
res = inbox.synchronized_await(mx, cv, tout);
CAF_REQUIRE_EQUAL(res, true);
CHECK_EQ(fetch(), "1");
tout += std::chrono::hours(1000);
std::thread t{[&] { inbox.synchronized_emplace_back(mx, cv, 2); }};
res = inbox.synchronized_await(mx, cv, tout);
CAF_REQUIRE_EQUAL(res, true);
CAF_REQUIRE_EQUAL(close_and_fetch(), "2");
t.join();
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.lifo_inbox
#include "caf/intrusive/lifo_inbox.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) : value(x) {
// nop
}
};
std::string to_string(const inode& x) {
return std::to_string(x.value);
}
struct inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
};
using inbox_type = lifo_inbox<inode_policy>;
struct fixture {
inode_policy policy;
inbox_type inbox;
void fill(inbox_type&) {
// nop
}
template <class T, class... Ts>
void fill(inbox_type& i, T x, Ts... xs) {
i.emplace_front(x);
fill(i, xs...);
}
std::string fetch() {
std::string result;
inode_policy::unique_pointer ptr{inbox.take_head()};
while (ptr != nullptr) {
auto next = ptr->next;
result += to_string(*ptr);
ptr.reset(inbox_type::promote(next));
}
return result;
}
std::string close_and_fetch() {
std::string result;
auto f = [&](inode* x) {
result += to_string(*x);
delete x;
};
inbox.close(f);
return result;
}
};
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(inbox.empty(), true);
}
CAF_TEST(push_front) {
fill(inbox, 1, 2, 3);
CAF_REQUIRE_EQUAL(close_and_fetch(), "321");
CAF_REQUIRE_EQUAL(inbox.closed(), true);
}
CAF_TEST(push_after_close) {
inbox.close();
auto res = inbox.push_front(new inode(0));
CAF_REQUIRE_EQUAL(res, inbox_result::queue_closed);
}
CAF_TEST(unblock) {
CAF_REQUIRE_EQUAL(inbox.try_block(), true);
auto res = inbox.push_front(new inode(1));
CAF_REQUIRE_EQUAL(res, inbox_result::unblocked_reader);
res = inbox.push_front(new inode(2));
CAF_REQUIRE_EQUAL(res, inbox_result::success);
CAF_REQUIRE_EQUAL(close_and_fetch(), "21");
}
CAF_TEST(await) {
std::mutex mx;
std::condition_variable cv;
std::thread t{[&] { inbox.synchronized_emplace_front(mx, cv, 1); }};
inbox.synchronized_await(mx, cv);
CAF_REQUIRE_EQUAL(close_and_fetch(), "1");
t.join();
}
CAF_TEST(timed_await) {
std::mutex mx;
std::condition_variable cv;
auto tout = std::chrono::system_clock::now();
tout += std::chrono::microseconds(1);
auto res = inbox.synchronized_await(mx, cv, tout);
CAF_REQUIRE_EQUAL(res, false);
fill(inbox, 1);
res = inbox.synchronized_await(mx, cv, tout);
CAF_REQUIRE_EQUAL(res, true);
CHECK_EQ(fetch(), "1");
tout += std::chrono::hours(1000);
std::thread t{[&] { inbox.synchronized_emplace_front(mx, cv, 2); }};
res = inbox.synchronized_await(mx, cv, tout);
CAF_REQUIRE_EQUAL(res, true);
CAF_REQUIRE_EQUAL(close_and_fetch(), "2");
t.join();
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.task_queue
#include "caf/intrusive/task_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) : value(x) {
// nop
}
};
[[maybe_unused]] std::string to_string(const inode& x) {
return std::to_string(x.value);
}
struct inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
static inline task_size_type task_size(const mapped_type& x) {
return x.value;
}
};
using queue_type = task_queue<inode_policy>;
struct fixture {
inode_policy policy;
queue_type queue{policy};
void fill(queue_type&) {
// nop
}
template <class T, class... Ts>
void fill(queue_type& q, T x, Ts... xs) {
q.emplace_back(x);
fill(q, xs...);
}
};
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
CAF_REQUIRE_EQUAL(queue.total_task_size(), 0);
CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
CAF_REQUIRE_EQUAL(queue.begin(), queue.end());
}
CAF_TEST(push_back) {
queue.emplace_back(1);
queue.push_back(inode_policy::unique_pointer{new inode(2)});
queue.push_back(new inode(3));
CAF_REQUIRE_EQUAL(deep_to_string(queue), "[1, 2, 3]");
}
CAF_TEST(lifo_conversion) {
queue.lifo_append(new inode(3));
queue.lifo_append(new inode(2));
queue.lifo_append(new inode(1));
queue.stop_lifo_append();
CAF_REQUIRE_EQUAL(deep_to_string(queue), "[1, 2, 3]");
}
CAF_TEST(move_construct) {
fill(queue, 1, 2, 3);
queue_type q2 = std::move(queue);
CAF_REQUIRE_EQUAL(queue.empty(), true);
CAF_REQUIRE_EQUAL(q2.empty(), false);
CAF_REQUIRE_EQUAL(deep_to_string(q2), "[1, 2, 3]");
}
CAF_TEST(move_assign) {
queue_type q2{policy};
fill(q2, 1, 2, 3);
queue = std::move(q2);
CAF_REQUIRE_EQUAL(q2.empty(), true);
CAF_REQUIRE_EQUAL(queue.empty(), false);
CAF_REQUIRE_EQUAL(deep_to_string(queue), "[1, 2, 3]");
}
CAF_TEST(append) {
queue_type q2{policy};
fill(queue, 1, 2, 3);
fill(q2, 4, 5, 6);
queue.append(q2);
CAF_REQUIRE_EQUAL(q2.empty(), true);
CAF_REQUIRE_EQUAL(queue.empty(), false);
CAF_REQUIRE_EQUAL(deep_to_string(queue), "[1, 2, 3, 4, 5, 6]");
}
CAF_TEST(prepend) {
queue_type q2{policy};
fill(queue, 1, 2, 3);
fill(q2, 4, 5, 6);
queue.prepend(q2);
CAF_REQUIRE_EQUAL(q2.empty(), true);
CAF_REQUIRE_EQUAL(queue.empty(), false);
CAF_REQUIRE_EQUAL(deep_to_string(queue), "[4, 5, 6, 1, 2, 3]");
}
CAF_TEST(peek) {
CHECK_EQ(queue.peek(), nullptr);
fill(queue, 1, 2, 3);
CHECK_EQ(queue.peek()->value, 1);
}
CAF_TEST(task_size) {
fill(queue, 1, 2, 3);
CHECK_EQ(queue.total_task_size(), 6);
fill(queue, 4, 5);
CHECK_EQ(queue.total_task_size(), 15);
queue.clear();
CHECK_EQ(queue.total_task_size(), 0);
}
CAF_TEST(to_string) {
CHECK_EQ(deep_to_string(queue), "[]");
fill(queue, 1, 2, 3, 4);
CHECK_EQ(deep_to_string(queue), "[1, 2, 3, 4]");
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.wdrr_dynamic_multiplexed_queue
#include "caf/intrusive/wdrr_dynamic_multiplexed_queue.hpp"
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) noexcept : value(x) {
// nop
}
};
std::string to_string(const inode& x) {
return std::to_string(x.value);
}
struct nested_inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
static task_size_type task_size(const mapped_type&) noexcept {
return 1;
}
std::unique_ptr<int> queue_id;
nested_inode_policy(int i) : queue_id(new int(i)) {
// nop
}
nested_inode_policy(nested_inode_policy&&) noexcept = default;
nested_inode_policy& operator=(nested_inode_policy&&) noexcept = default;
};
struct inode_policy {
using mapped_type = inode;
using key_type = int;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
using queue_type = drr_queue<nested_inode_policy>;
using queue_map_type = std::map<key_type, queue_type>;
static key_type id_of(const inode& x) noexcept {
return x.value % 3;
}
static bool enabled(const queue_type&) noexcept {
return true;
}
deficit_type quantum(const queue_type& q, deficit_type x) noexcept {
return enable_priorities && *q.policy().queue_id == 0 ? 2 * x : x;
}
static void cleanup(queue_type&) noexcept {
// nop
}
static bool push_back(queue_type& q, mapped_type* ptr) noexcept {
return q.push_back(ptr);
}
bool enable_priorities = false;
};
using queue_type = wdrr_dynamic_multiplexed_queue<inode_policy>;
using nested_queue_type = inode_policy::queue_type;
struct fixture {
inode_policy policy;
queue_type queue{policy};
int fill(queue_type&) {
return 0;
}
template <class T, class... Ts>
int fill(queue_type& q, T x, Ts... xs) {
return (q.emplace_back(x) ? 1 : 0) + fill(q, xs...);
}
std::string fetch(int quantum) {
std::string result;
auto f = [&](int id, nested_queue_type& q, inode& x) {
CHECK_EQ(id, *q.policy().queue_id);
if (!result.empty())
result += ',';
result += to_string(id);
result += ':';
result += to_string(x);
return task_result::resume;
};
queue.new_round(quantum, f);
return result;
}
void make_queues() {
for (int i = 0; i < 3; ++i)
queue.queues().emplace(i, nested_inode_policy{i});
}
};
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(dropping) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
CAF_REQUIRE_EQUAL(fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12), 0);
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(new_round) {
make_queues();
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12);
CAF_REQUIRE_EQUAL(queue.empty(), false);
CHECK_EQ(fetch(1), "0:3,1:1,2:2");
CAF_REQUIRE_EQUAL(queue.empty(), false);
CHECK_EQ(fetch(9), "0:6,0:9,0:12,1:4,1:7,2:5,2:8");
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(priorities) {
make_queues();
queue.policy().enable_priorities = true;
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Allow f to consume 2 items from the high priority and 1 item otherwise.
CHECK_EQ(fetch(1), "0:3,0:6,1:1,2:2");
CAF_REQUIRE_EQUAL(queue.empty(), false);
// Drain the high-priority queue with one item left per other queue.
CHECK_EQ(fetch(1), "0:9,1:4,2:5");
CAF_REQUIRE_EQUAL(queue.empty(), false);
// Drain queue.
CHECK_EQ(fetch(1000), "1:7,2:8");
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(peek_all) {
auto queue_to_string = [&] {
std::string str;
auto peek_fun = [&](const inode& x) {
if (!str.empty())
str += ", ";
str += std::to_string(x.value);
};
queue.peek_all(peek_fun);
return str;
};
make_queues();
CHECK_EQ(queue_to_string(), "");
queue.emplace_back(1);
CHECK_EQ(queue_to_string(), "1");
queue.emplace_back(2);
CHECK_EQ(queue_to_string(), "1, 2");
queue.emplace_back(3);
// Lists are iterated in order and 3 is stored in the first queue for
// `x mod 3 == 0` values.
CHECK_EQ(queue_to_string(), "3, 1, 2");
queue.emplace_back(4);
CHECK_EQ(queue_to_string(), "3, 1, 4, 2");
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE intrusive.wdrr_fixed_multiplexed_queue
#include "caf/intrusive/wdrr_fixed_multiplexed_queue.hpp"
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "core-test.hpp"
#include <memory>
using namespace caf;
using namespace caf::intrusive;
namespace {
struct inode : singly_linked<inode> {
int value;
inode(int x = 0) : value(x) {
// nop
}
};
std::string to_string(const inode& x) {
return std::to_string(x.value);
}
class high_prio_queue;
struct inode_policy {
using mapped_type = inode;
using task_size_type = int;
using deficit_type = int;
using deleter_type = std::default_delete<mapped_type>;
using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;
static inline task_size_type task_size(const mapped_type&) {
return 1;
}
static inline size_t id_of(const inode& x) {
return x.value % 3;
}
template <class Queue>
deficit_type quantum(const Queue&, deficit_type x) {
return x;
}
deficit_type quantum(const high_prio_queue&, deficit_type x) {
return enable_priorities ? 2 * x : x;
}
bool enable_priorities = false;
};
class high_prio_queue : public drr_queue<inode_policy> {
public:
using super = drr_queue<inode_policy>;
using super::super;
};
using nested_queue_type = drr_queue<inode_policy>;
using queue_type
= wdrr_fixed_multiplexed_queue<inode_policy, high_prio_queue,
nested_queue_type, nested_queue_type>;
struct fetch_helper {
std::string result;
template <size_t I, class Queue>
task_result
operator()(std::integral_constant<size_t, I>, const Queue&, inode& x) {
if (!result.empty())
result += ',';
result += std::to_string(I);
result += ':';
result += to_string(x);
return task_result::resume;
}
};
struct fixture {
inode_policy policy;
queue_type queue{policy, policy, policy, policy};
void fill(queue_type&) {
// nop
}
template <class T, class... Ts>
void fill(queue_type& q, T x, Ts... xs) {
q.emplace_back(x);
fill(q, xs...);
}
std::string fetch(int quantum) {
std::string result;
auto f = [&](size_t id, drr_queue<inode_policy>&, inode& x) {
if (!result.empty())
result += ',';
result += std::to_string(id);
result += ':';
result += to_string(x);
return task_result::resume;
};
queue.new_round(quantum, f);
return result;
}
};
auto make_new_round_result(size_t consumed_items, bool stop_all) {
return new_round_result{consumed_items, stop_all};
}
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(new_round) {
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12);
// Allow f to consume 2 items per nested queue.
fetch_helper f;
auto round_result = queue.new_round(2, f);
CHECK_EQ(round_result, make_new_round_result(6, false));
CHECK_EQ(f.result, "0:3,0:6,1:1,1:4,2:2,2:5");
CAF_REQUIRE_EQUAL(queue.empty(), false);
// Allow f to consume one more item from each queue.
f.result.clear();
round_result = queue.new_round(1, f);
CHECK_EQ(round_result, make_new_round_result(3, false));
CHECK_EQ(f.result, "0:9,1:7,2:8");
CAF_REQUIRE_EQUAL(queue.empty(), false);
// Allow f to consume the remainder, i.e., 12.
f.result.clear();
round_result = queue.new_round(1000, f);
CHECK_EQ(round_result, make_new_round_result(1, false));
CHECK_EQ(f.result, "0:12");
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(priorities) {
queue.policy().enable_priorities = true;
fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// Allow f to consume 2 items from the high priority and 1 item otherwise.
CHECK_EQ(fetch(1), "0:3,0:6,1:1,2:2");
CAF_REQUIRE_EQUAL(queue.empty(), false);
// Drain the high-priority queue with one item left per other queue.
CHECK_EQ(fetch(1), "0:9,1:4,2:5");
CAF_REQUIRE_EQUAL(queue.empty(), false);
// Drain queue.
CHECK_EQ(fetch(1000), "1:7,2:8");
CAF_REQUIRE_EQUAL(queue.empty(), true);
}
CAF_TEST(peek_all) {
auto queue_to_string = [&] {
std::string str;
auto peek_fun = [&](const inode& x) {
if (!str.empty())
str += ", ";
str += std::to_string(x.value);
};
queue.peek_all(peek_fun);
return str;
};
CHECK_EQ(queue_to_string(), "");
queue.emplace_back(1);
CHECK_EQ(queue_to_string(), "1");
queue.emplace_back(2);
CHECK_EQ(queue_to_string(), "1, 2");
queue.emplace_back(3);
// Lists are iterated in order and 3 is stored in the first queue for
// `x mod 3 == 0` values.
CHECK_EQ(queue_to_string(), "3, 1, 2");
queue.emplace_back(4);
CHECK_EQ(queue_to_string(), "3, 1, 4, 2");
}
END_FIXTURE_SCOPE()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE policy.categorized
#include "caf/policy/categorized.hpp"
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/fifo_inbox.hpp"
#include "caf/intrusive/wdrr_dynamic_multiplexed_queue.hpp"
#include "caf/intrusive/wdrr_fixed_multiplexed_queue.hpp"
#include "caf/policy/normal_messages.hpp"
#include "caf/policy/urgent_messages.hpp"
#include "caf/unit.hpp"
#include "core-test.hpp"
using namespace caf;
namespace {
using urgent_queue = intrusive::drr_queue<policy::urgent_messages>;
using normal_queue = intrusive::drr_queue<policy::normal_messages>;
struct mailbox_policy {
using deficit_type = size_t;
using mapped_type = mailbox_element;
using unique_pointer = mailbox_element_ptr;
using queue_type
= intrusive::wdrr_fixed_multiplexed_queue<policy::categorized, urgent_queue,
normal_queue>;
};
using mailbox_type = intrusive::fifo_inbox<mailbox_policy>;
struct fixture {};
struct consumer {
std::vector<int> ints;
template <class Key, class Queue>
intrusive::task_result
operator()(const Key&, const Queue&, const mailbox_element& x) {
if (!x.content().match_elements<int>())
CAF_FAIL("unexpected message: " << x.content());
ints.emplace_back(x.content().get_as<int>(0));
return intrusive::task_result::resume;
}
template <class Key, class Queue, class... Ts>
intrusive::task_result operator()(const Key&, const Queue&, const Ts&...) {
CAF_FAIL("unexpected message type"); // << typeid(Ts).name());
return intrusive::task_result::resume;
}
};
} // namespace
BEGIN_FIXTURE_SCOPE(fixture)
CAF_TEST(priorities) {
mailbox_type mbox{unit, unit, unit};
mbox.push_back(make_mailbox_element(nullptr, make_message_id(), {}, 123));
mbox.push_back(make_mailbox_element(
nullptr, make_message_id(message_priority::high), {}, 456));
consumer f;
mbox.new_round(1000, f);
CHECK_EQ(f.ints, std::vector<int>({456, 123}));
}
END_FIXTURE_SCOPE()
...@@ -60,7 +60,7 @@ caf_add_component( ...@@ -60,7 +60,7 @@ caf_add_component(
caf/policy/tcp.cpp caf/policy/tcp.cpp
caf/policy/udp.cpp caf/policy/udp.cpp
LEGACY_TEST_SOURCES LEGACY_TEST_SOURCES
test/io-test.cpp tests/legacy/io-test.cpp
LEGACY_TEST_SUITES LEGACY_TEST_SUITES
detail.prometheus_broker detail.prometheus_broker
io.basp.message_queue io.basp.message_queue
...@@ -77,5 +77,5 @@ caf_add_component( ...@@ -77,5 +77,5 @@ caf_add_component(
io.worker) io.worker)
if(CAF_ENABLE_TESTING AND UNIX) if(CAF_ENABLE_TESTING AND UNIX)
caf_add_test_suites(caf-io-legacy-test io.middleman) caf_add_legacy_test_suites(caf-io-legacy-test io.middleman)
endif() endif()
...@@ -4,7 +4,7 @@ file(GLOB_RECURSE CAF_NET_HEADERS "caf/*.hpp") ...@@ -4,7 +4,7 @@ file(GLOB_RECURSE CAF_NET_HEADERS "caf/*.hpp")
# -- add targets --------------------------------------------------------------- # -- add targets ---------------------------------------------------------------
configure_file(test/pem.cpp.in test/pem.cpp @ONLY) configure_file(tests/legacy/pem.cpp.in tests/legacy/pem.cpp @ONLY)
caf_add_component( caf_add_component(
net net
...@@ -94,8 +94,8 @@ caf_add_component( ...@@ -94,8 +94,8 @@ caf_add_component(
caf/net/web_socket/server.cpp caf/net/web_socket/server.cpp
caf/net/web_socket/upper_layer.cpp caf/net/web_socket/upper_layer.cpp
LEGACY_TEST_SOURCES LEGACY_TEST_SOURCES
${CMAKE_CURRENT_BINARY_DIR}/test/pem.cpp ${CMAKE_CURRENT_BINARY_DIR}/tests/legacy/pem.cpp
test/net-test.cpp tests/legacy/net-test.cpp
LEGACY_TEST_SUITES LEGACY_TEST_SUITES
detail.convert_ip_endpoint detail.convert_ip_endpoint
net.accept_socket net.accept_socket
......
#include <string_view>
// clang-format off
const char* ca_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/ca.pem";
const char* cert_1_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/cert_1.pem";
const char* cert_2_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/cert_2.pem";
const char* key_1_enc_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/key_1_enc.pem";
const char* key_1_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/key_1.pem";
const char* key_2_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/test/net/ssl/key_2.pem";
// clang-format on
#include <string_view>
// clang-format off
const char* ca_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/tests/legacy/net/ssl/ca.pem";
const char* cert_1_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/tests/legacy/net/ssl/cert_1.pem";
const char* cert_2_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/tests/legacy/net/ssl/cert_2.pem";
const char* key_1_enc_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/tests/legacy/net/ssl/key_1_enc.pem";
const char* key_1_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/tests/legacy/net/ssl/key_1.pem";
const char* key_2_pem_path = "@CMAKE_CURRENT_SOURCE_DIR@/tests/legacy/net/ssl/key_2.pem";
// clang-format on
...@@ -22,7 +22,7 @@ caf_add_component( ...@@ -22,7 +22,7 @@ caf_add_component(
caf/openssl/remote_actor.cpp caf/openssl/remote_actor.cpp
caf/openssl/session.cpp caf/openssl/session.cpp
LEGACY_TEST_SUITES LEGACY_TEST_SUITES
test/openssl-test.cpp tests/legacy/openssl-test.cpp
LEGACY_TEST_SUITES LEGACY_TEST_SUITES
openssl.authentication openssl.authentication
openssl.remote_actor) openssl.remote_actor)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment