-
Notifications
You must be signed in to change notification settings - Fork 552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base tests on raft_fixture #18531
base tests on raft_fixture #18531
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vbuild/debug/clang/bin/gtest_raft_rpunit -- --gtest_filter=kv1_stm_fixture.test_mux_state_machine_simple_scenarios
to reproduce the problem
d78899a
to
c7c1118
Compare
/dt |
- remove CRTP from stm_raft_fixture to improve readability - in raft_fixture::retry_with_leader assume unknown error types are not to be retried - in raft_fixture::retry_with_leader assume unknown errors are not retryable - in raft_fixture::retry_with_leader hold the function with do_with - in raft_fixture expose base_directory and stop_and_recreate_nodes()
c7c1118
to
e89d56e
Compare
/dt |
@@ -543,16 +536,10 @@ class raft_fixture | |||
bool _enable_longest_log_detection = true; | |||
}; | |||
|
|||
template<class CRTPImpl, class... STM> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:D easy on the eyes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really waiting for C++23 to express compile-time inheritance as easily as runtime
@@ -470,30 +467,26 @@ class raft_fixture | |||
}; | |||
return ss::do_with( | |||
retry_state{}, | |||
[this, deadline, f = std::forward<Func>(f), backoff]( | |||
retry_state& state) mutable { | |||
std::forward<Func>(f), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I wonder if this should be a forward or a move
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be a forward. The lazy monkey argument would be that all subsequent calls forward it, so why should we break this chain? Really, they seem to do it for a reason, the reason being do_with
actually working "well" with lvalue references. It accepts an lvalue reference and never copies or moves the object. In this example the object is not copiable, and after calling with an lvalue reference we can check it has not been moved-from either:
struct kv1_stm_fixture : kv_stm_fixture<kv1_stm_t> {
...
ss::future<int> foo_rvref() {
std::unique_ptr<int> uptr = std::make_unique<int>(5);
return ss::do_with(std::move(uptr), [](const std::unique_ptr<int>& p) {
return foo_impl(p);
});
}
// the test fails with `AddressSanitizer: stack-use-after-return` if we declare it in the function body
std::unique_ptr<int> member_uptr = std::make_unique<int>(5);
ss::future<int> foo_lvref() {
return ss::do_with(
std::ref(member_uptr),
[](const std::unique_ptr<int>& p) { return foo_impl(p); });
}
static ss::future<int>
foo_impl(const std::unique_ptr<int>& non_copiable_parameter) {
co_await ss::sleep(1s);
vlog(kvlog.info, "lv");
co_return *non_copiable_parameter.get();
}
static ss::future<int>
foo_impl(std::unique_ptr<int>&& non_copiable_parameter) {
co_await ss::sleep(1s);
vlog(kvlog.info, "rv");
co_return *std::move(non_copiable_parameter).release();
}
};
TEST_F_CORO(kv1_stm_fixture, test_mux_state_machine_simple_scenarios) {
ASSERT_EQ_CORO(co_await foo_lvref(), 5);
ASSERT_TRUE_CORO(member_uptr);
ASSERT_EQ_CORO(co_await foo_rvref(), 5);
...
}
I put "well" in quotes because, when called with an lvalue reference, do_with
does not attempt to extend the object lifetime (and it's not that it has a chance to). So, despite do_with
it remains the caller's responsibility to ensure the object is alive until the future completion.
I find it handy, as it allows us code universal functions like retry_with_leader
to accept lvalue references to long-life objects as well as rvalue references to temporaries. We don't have to code separate versions of such functions, one with do_with
and another one without, we just need to forward in there.
The only problem is that this behaviour of do_with
is undocumented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put "well" in quotes because, when called with an lvalue reference, do_with does not attempt to extend the object lifetime (and it's not that it has a chance to). So, despite do_with it remains the caller's responsibility to ensure the object is alive until the future completion.
Right.. I was wondering whether we should disallow lvalue refs here to avoid this footgun. To your point that it is handy to just forward and let the callers handle the lifetime seems like a fair argument, especially in this test code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I only checked forwarding/moving of arguments, not the function itself. But I think there's no harm in making them behave consistently as, eventually they anyway form a closure together.
e89d56e
to
bd70f92
Compare
Improve raft_fixture and stm_raft_fixture, base mux_state_machine_test and tm_stm_tests on them.
Backports Required
Release Notes