改进
This commit is contained in:
@@ -193,3 +193,132 @@ TEST(render_graph_runtime_test,
|
||||
EXPECT_TRUE(source.complete());
|
||||
execution.join();
|
||||
}
|
||||
|
||||
TEST(external_operation_test, cancellation_is_terminal_and_delivered_once) {
|
||||
External_Operation_Source source;
|
||||
const auto operation = source.operation();
|
||||
EXPECT_TRUE(operation.cancel());
|
||||
EXPECT_FALSE(source.complete());
|
||||
EXPECT_EQ(operation.status(), External_Operation_Status::cancelled);
|
||||
|
||||
int completion_count{};
|
||||
std::exception_ptr completion_error;
|
||||
operation.on_complete([&](std::exception_ptr error) {
|
||||
completion_error = std::move(error);
|
||||
++completion_count;
|
||||
});
|
||||
EXPECT_EQ(completion_count, 1);
|
||||
ASSERT_TRUE(completion_error);
|
||||
EXPECT_THROW(std::rethrow_exception(completion_error),
|
||||
External_Operation_Cancelled);
|
||||
}
|
||||
|
||||
TEST(external_operation_test, deadline_cancels_pending_operation) {
|
||||
External_Operation_Source source;
|
||||
const auto operation = source.operation();
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
bool completed{};
|
||||
std::exception_ptr completion_error;
|
||||
operation.on_complete([&](std::exception_ptr error) {
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
completion_error = std::move(error);
|
||||
completed = true;
|
||||
}
|
||||
condition.notify_one();
|
||||
});
|
||||
source.set_deadline(External_Operation_Source::Clock::now());
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
ASSERT_TRUE(condition.wait_for(lock, std::chrono::seconds(1),
|
||||
[&] { return completed; }));
|
||||
}
|
||||
ASSERT_TRUE(completion_error);
|
||||
EXPECT_THROW(std::rethrow_exception(completion_error),
|
||||
External_Operation_Deadline_Exceeded);
|
||||
EXPECT_EQ(operation.status(), External_Operation_Status::cancelled);
|
||||
}
|
||||
|
||||
TEST(render_graph_runtime_test,
|
||||
cancellation_releases_external_wait_and_blocks_successor) {
|
||||
const auto plan = two_node_plan();
|
||||
External_Operation_Source source;
|
||||
std::vector<Node_Execution> execution_storage;
|
||||
auto slots = execution_slots(*plan, execution_storage);
|
||||
std::atomic<bool> submit_started{};
|
||||
std::atomic<bool> publish_executed{};
|
||||
std::exception_ptr graph_error;
|
||||
|
||||
renderive::render_graph::detail::Render_Graph_Runtime runtime(*plan);
|
||||
const auto execute_node = [&](std::size_t index, Node_Execution_Metrics*) {
|
||||
if (index == 0) {
|
||||
submit_started.store(true, std::memory_order_release);
|
||||
submit_started.notify_all();
|
||||
return Node_Execution_Result::external(source.operation());
|
||||
}
|
||||
publish_executed.store(true, std::memory_order_release);
|
||||
return Node_Execution_Result::completed();
|
||||
};
|
||||
|
||||
std::thread execution([&] {
|
||||
try {
|
||||
runtime.execute(slots, execute_node);
|
||||
} catch (...) {
|
||||
graph_error = std::current_exception();
|
||||
}
|
||||
});
|
||||
submit_started.wait(false, std::memory_order_acquire);
|
||||
runtime.cancel_pending();
|
||||
execution.join();
|
||||
|
||||
ASSERT_TRUE(graph_error);
|
||||
EXPECT_THROW(std::rethrow_exception(graph_error),
|
||||
External_Operation_Cancelled);
|
||||
EXPECT_FALSE(publish_executed.load(std::memory_order_acquire));
|
||||
EXPECT_EQ(execution_storage[0].status, Node_Execution_Status::cancelled);
|
||||
EXPECT_EQ(source.operation().status(), External_Operation_Status::cancelled);
|
||||
}
|
||||
|
||||
TEST(external_operation_test, completion_commit_is_exclusive_with_cancellation) {
|
||||
External_Operation_Source source;
|
||||
const auto operation = source.operation();
|
||||
std::atomic<int> published{};
|
||||
EXPECT_TRUE(operation.cancel());
|
||||
EXPECT_FALSE(source.complete([&] {
|
||||
published.fetch_add(1, std::memory_order_relaxed);
|
||||
}));
|
||||
EXPECT_EQ(published.load(std::memory_order_relaxed), 0);
|
||||
}
|
||||
|
||||
TEST(external_operation_test, completion_commit_precedes_completion_notification) {
|
||||
External_Operation_Source source;
|
||||
const auto operation = source.operation();
|
||||
std::atomic<int> published{};
|
||||
int observed{};
|
||||
operation.on_complete([&](std::exception_ptr error) {
|
||||
EXPECT_FALSE(error);
|
||||
observed = published.load(std::memory_order_acquire);
|
||||
});
|
||||
|
||||
EXPECT_TRUE(source.complete([&] {
|
||||
published.store(1, std::memory_order_release);
|
||||
EXPECT_EQ(operation.status(), External_Operation_Status::pending);
|
||||
}));
|
||||
EXPECT_EQ(observed, 1);
|
||||
EXPECT_EQ(operation.status(), External_Operation_Status::completed);
|
||||
}
|
||||
|
||||
TEST(external_operation_test, completion_commit_failure_fails_operation) {
|
||||
External_Operation_Source source;
|
||||
const auto operation = source.operation();
|
||||
std::exception_ptr completion_error;
|
||||
operation.on_complete([&](std::exception_ptr error) {
|
||||
completion_error = std::move(error);
|
||||
});
|
||||
|
||||
EXPECT_TRUE(source.complete([] { throw std::runtime_error("publish failed"); }));
|
||||
ASSERT_TRUE(completion_error);
|
||||
EXPECT_THROW(std::rethrow_exception(completion_error), std::runtime_error);
|
||||
EXPECT_EQ(operation.status(), External_Operation_Status::failed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user