Skip to content
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

Merged
merged 3 commits into from
May 22, 2024

Conversation

bashtanov
Copy link
Contributor

@bashtanov bashtanov commented May 16, 2024

Improve raft_fixture and stm_raft_fixture, base mux_state_machine_test and tm_stm_tests on them.

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v24.1.x
  • v23.3.x
  • v23.2.x

Release Notes

  • none

Copy link
Contributor Author

@bashtanov bashtanov left a 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

@bashtanov
Copy link
Contributor Author

/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()
@bashtanov
Copy link
Contributor Author

/dt

@bashtanov bashtanov marked this pull request as ready for review May 20, 2024 09:29
@@ -543,16 +536,10 @@ class raft_fixture
bool _enable_longest_log_detection = true;
};

template<class CRTPImpl, class... STM>
Copy link
Contributor

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.

Copy link
Contributor Author

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),
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

src/v/cluster/tests/CMakeLists.txt Show resolved Hide resolved
@bashtanov bashtanov merged commit 59439fe into redpanda-data:dev May 22, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants