Add initial test suite with some batch job tests

This commit is contained in:
Jason Rhinelander 2020-02-06 18:10:26 -04:00
parent 03ea49167c
commit 63c71396be
6 changed files with 153 additions and 2 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "cppzmq"]
path = cppzmq
url = https://github.com/zeromq/cppzmq.git
[submodule "Catch2"]
path = tests/Catch2
url = https://github.com/catchorg/Catch2.git

View File

@ -20,9 +20,9 @@ add_subdirectory(cppzmq EXCLUDE_FROM_ALL)
foreach(target lokimq lokimq-static)
target_include_directories(${target}
PUBLIC
$<INSTALL_INTERFACE:lokimq>
$<INSTALL_INTERFACE:>
$<INSTALL_INTERFACE:mapbox-variant/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lokimq>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/mapbox-variant/include>
)
@ -34,3 +34,7 @@ endforeach()
target_link_libraries(lokimq PUBLIC cppzmq)
target_link_libraries(lokimq-static PUBLIC cppzmq-static)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()

13
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
add_subdirectory(Catch2)
set(LMQ_TEST_SRC
main.cpp
test_batch.cpp
)
add_executable(tests ${LMQ_TEST_SRC})
target_link_libraries(tests Catch2::Catch2 lokimq)
add_custom_target(check COMMAND tests)

1
tests/Catch2 Submodule

@ -0,0 +1 @@
Subproject commit b3b07215d1ca2224aea6ff3e21d87ad0f7750df2

3
tests/main.cpp Normal file
View File

@ -0,0 +1,3 @@
// Let Catch provide main():
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

127
tests/test_batch.cpp Normal file
View File

@ -0,0 +1,127 @@
#include "lokimq/lokimq.h"
#include "lokimq/batch.h"
#include <future>
#include <catch2/catch.hpp>
double do_my_task(int input) {
if (input % 10 == 7)
throw std::domain_error("I don't do '7s, sorry");
if (input == 1)
return 5.0;
return 3.0 * input;
}
std::promise<std::pair<double, int>> done;
void continue_big_task(std::vector<lokimq::job_result<double>> results) {
double sum = 0;
int exc_count = 0;
for (auto& r : results) {
try {
sum += r.get();
} catch (const std::exception& e) {
exc_count++;
}
}
done.set_value({sum, exc_count});
}
void start_big_task(lokimq::LokiMQ& lmq) {
size_t num_jobs = 32;
lokimq::Batch<double /*return type*/> batch;
batch.reserve(num_jobs);
for (size_t i = 0; i < num_jobs; i++)
batch.add_job([i]() { return do_my_task(i); });
batch.completion(&continue_big_task);
lmq.batch(std::move(batch));
}
TEST_CASE("batching many small jobs", "[batch-many]") {
lokimq::LokiMQ lmq{
"", "", // generate ephemeral keys
false, // not a service node
{}, // don't listen
[](auto &) { return ""; },
[](auto ip, auto pk) { return lokimq::Allow{lokimq::AuthLevel::none, false}; },
};
lmq.set_general_threads(4);
lmq.set_batch_threads(4);
lmq.start();
start_big_task(lmq);
auto sum = done.get_future().get();
REQUIRE( sum.first == 1337.0 );
REQUIRE( sum.second == 3 );
}
TEST_CASE("batch exception propagation", "[batch-exceptions]") {
lokimq::LokiMQ lmq{
"", "", // generate ephemeral keys
false, // not a service node
{}, // don't listen
[](auto &) { return ""; },
[](auto ip, auto pk) { return lokimq::Allow{lokimq::AuthLevel::none, false}; },
};
lmq.set_general_threads(4);
lmq.set_batch_threads(4);
lmq.start();
std::promise<void> done_promise;
std::future<void> done_future = done_promise.get_future();
using Catch::Matchers::Message;
SECTION( "value return" ) {
lokimq::Batch<int> batch;
for (int i : {1, 2})
batch.add_job([i]() { if (i == 1) return 42; throw std::domain_error("bad value " + std::to_string(i)); });
batch.completion([&done_promise](auto results) {
REQUIRE( results.size() == 2 );
REQUIRE( results[0].get() == 42 );
REQUIRE_THROWS_MATCHES( results[1].get() == 0, std::domain_error, Message("bad value 2") );
done_promise.set_value();
});
lmq.batch(std::move(batch));
done_future.get();
}
SECTION( "lvalue return" ) {
lokimq::Batch<int&> batch;
int forty_two = 42;
for (int i : {1, 2})
batch.add_job([i,&forty_two]() -> int& {
if (i == 1)
return forty_two;
throw std::domain_error("bad value " + std::to_string(i));
});
batch.completion([&done_promise,&forty_two](auto results) {
REQUIRE( results.size() == 2 );
auto& r = results[0].get();
REQUIRE( &r == &forty_two );
REQUIRE( r == 42 );
REQUIRE_THROWS_MATCHES( results[1].get(), std::domain_error, Message("bad value 2") );
done_promise.set_value();
});
lmq.batch(std::move(batch));
done_future.get();
}
SECTION( "void return" ) {
lokimq::Batch<void> batch;
for (int i : {1, 2})
batch.add_job([i]() { if (i != 1) throw std::domain_error("bad value " + std::to_string(i)); });
batch.completion([&done_promise](auto results) {
REQUIRE( results.size() == 2 );
REQUIRE_NOTHROW( results[0].get() );
REQUIRE_THROWS_MATCHES( results[1].get(), std::domain_error, Message("bad value 2") );
done_promise.set_value();
});
lmq.batch(std::move(batch));
done_future.get();
}
}