mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-07-27 09:01:50 +03:00
Added unit tests for server_context applying codepath.
This commit is contained in:
@ -11,6 +11,9 @@ add_library(trrep
|
||||
transaction_context.cpp)
|
||||
|
||||
add_executable(trrep_test
|
||||
mock_client_context.cpp
|
||||
mock_utils.cpp
|
||||
server_context_test.cpp
|
||||
transaction_context_test.cpp
|
||||
trrep_test.cpp
|
||||
)
|
||||
|
@ -62,15 +62,10 @@ namespace trrep
|
||||
trrep::provider& provider() const;
|
||||
|
||||
client_id id() const { return id_; }
|
||||
client_id id(const client_id& id)
|
||||
{
|
||||
assert(mode() == m_applier);
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
enum mode mode() const { return mode_; }
|
||||
enum state state() const { return state_; }
|
||||
|
||||
virtual bool do_2pc() const = 0;
|
||||
//
|
||||
//
|
||||
//
|
||||
@ -85,15 +80,15 @@ namespace trrep
|
||||
virtual int append_fragment(trrep::transaction_context&,
|
||||
uint32_t, const trrep::data&)
|
||||
{ return 0; }
|
||||
virtual int commit(trrep::transaction_context&) { return 0; }
|
||||
virtual int rollback(trrep::transaction_context&) { return 0; }
|
||||
virtual int commit(trrep::transaction_context&) = 0;
|
||||
virtual int rollback(trrep::transaction_context&) = 0;
|
||||
|
||||
virtual void will_replay(trrep::transaction_context&) { }
|
||||
virtual int replay(trrep::transaction_context& tc);
|
||||
|
||||
|
||||
virtual int apply(trrep::transaction_context&,
|
||||
const trrep::data&) { return 0; }
|
||||
const trrep::data&) = 0;
|
||||
|
||||
virtual void wait_for_replayers(trrep::unique_lock<trrep::mutex>&)
|
||||
{ }
|
||||
|
56
src/mock_client_context.cpp
Normal file
56
src/mock_client_context.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright (C) 2018 Codership Oy <info@codership.com>
|
||||
//
|
||||
|
||||
#include "transaction_context.hpp"
|
||||
#include "mock_client_context.hpp"
|
||||
|
||||
|
||||
int trrep::mock_client_context::apply(
|
||||
trrep::transaction_context& transaction_context,
|
||||
const trrep::data& data __attribute__((unused)))
|
||||
|
||||
{
|
||||
assert(transaction_context.state() == trrep::transaction_context::s_executing);
|
||||
return (fail_next_applying_ ? 1 : 0);
|
||||
}
|
||||
|
||||
int trrep::mock_client_context::commit(
|
||||
trrep::transaction_context& transaction_context)
|
||||
{
|
||||
int ret(0);
|
||||
if (do_2pc())
|
||||
{
|
||||
if (transaction_context.before_prepare())
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else if (transaction_context.after_prepare())
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
if (ret == 0 &&
|
||||
(transaction_context.before_commit() ||
|
||||
transaction_context.ordered_commit() ||
|
||||
transaction_context.after_commit()))
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int trrep::mock_client_context::rollback(
|
||||
trrep::transaction_context& transaction_context)
|
||||
{
|
||||
int ret(0);
|
||||
if (transaction_context.before_rollback())
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else if (transaction_context.after_rollback())
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -15,14 +15,27 @@ namespace trrep
|
||||
public:
|
||||
mock_client_context(trrep::server_context& server_context,
|
||||
const trrep::client_id& id,
|
||||
enum trrep::client_context::mode mode)
|
||||
enum trrep::client_context::mode mode,
|
||||
bool do_2pc = false)
|
||||
: trrep::client_context(mutex_, server_context, id, mode)
|
||||
// Note: Mutex is initialized only after passed
|
||||
// to client_context constructor.
|
||||
, mutex_()
|
||||
, do_2pc_(do_2pc)
|
||||
, fail_next_applying_()
|
||||
{ }
|
||||
int apply(trrep::transaction_context&, const trrep::data&);
|
||||
int commit(trrep::transaction_context&);
|
||||
int rollback(trrep::transaction_context&);
|
||||
bool do_2pc() const { return do_2pc_; }
|
||||
|
||||
// Mock state modifiers
|
||||
void fail_next_applying(bool fail_next_applying)
|
||||
{ fail_next_applying_ = fail_next_applying; }
|
||||
private:
|
||||
trrep::default_mutex mutex_;
|
||||
bool do_2pc_;
|
||||
bool fail_next_applying_;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace trrep
|
||||
, provider_()
|
||||
, last_client_id_(0)
|
||||
{ }
|
||||
trrep::provider& provider() const
|
||||
trrep::mock_provider& provider() const
|
||||
{ return provider_; }
|
||||
trrep::client_context* local_client_context()
|
||||
{
|
||||
|
42
src/mock_utils.cpp
Normal file
42
src/mock_utils.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright (C) 2018 Codership Oy <info@codership.com>
|
||||
//
|
||||
|
||||
#include "mock_utils.hpp"
|
||||
#include "client_context.hpp"
|
||||
#include "mock_server_context.hpp"
|
||||
|
||||
|
||||
// Simple BF abort method to BF abort unordered transasctions
|
||||
void trrep_mock::bf_abort_unordered(trrep::client_context& cc,
|
||||
trrep::transaction_context& tc)
|
||||
{
|
||||
trrep::unique_lock<trrep::mutex> lock(cc.mutex());
|
||||
tc.state(lock, trrep::transaction_context::s_must_abort);
|
||||
}
|
||||
|
||||
// BF abort method to abort transactions via provider
|
||||
void trrep_mock::bf_abort_provider(trrep::mock_server_context& sc,
|
||||
const trrep::transaction_context& tc,
|
||||
wsrep_seqno_t bf_seqno)
|
||||
{
|
||||
wsrep_seqno_t victim_seqno;
|
||||
sc.provider().bf_abort(bf_seqno, tc.id().get(), &victim_seqno);
|
||||
(void)victim_seqno;
|
||||
}
|
||||
|
||||
trrep::transaction_context trrep_mock::applying_transaction(
|
||||
trrep::client_context& cc,
|
||||
const trrep::transaction_id& id,
|
||||
wsrep_seqno_t seqno,
|
||||
uint32_t flags)
|
||||
{
|
||||
wsrep_ws_handle_t ws_handle = { id.get(), 0 };
|
||||
wsrep_trx_meta_t meta = {
|
||||
{ {1 }, seqno }, /* gtid */
|
||||
{ { static_cast<uint8_t>(cc.id().get()) }, id.get(), cc.id().get() }, /* stid */
|
||||
seqno - 1
|
||||
};
|
||||
trrep::transaction_context ret(cc, ws_handle, meta, flags);
|
||||
return ret;
|
||||
}
|
36
src/mock_utils.hpp
Normal file
36
src/mock_utils.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright (C) 2018 Codership Oy <info@codership.com>
|
||||
//
|
||||
|
||||
#include <wsrep_api.h> // Wsrep typedefs
|
||||
|
||||
// Forward declarations
|
||||
namespace trrep
|
||||
{
|
||||
class client_context;
|
||||
class mock_server_context;
|
||||
}
|
||||
|
||||
#include "transaction_context.hpp"
|
||||
|
||||
//
|
||||
// Utility functions
|
||||
//
|
||||
namespace trrep_mock
|
||||
{
|
||||
|
||||
// Simple BF abort method to BF abort unordered transasctions
|
||||
void bf_abort_unordered(trrep::client_context& cc,
|
||||
trrep::transaction_context& tc);
|
||||
|
||||
// BF abort method to abort transactions via provider
|
||||
void bf_abort_provider(trrep::mock_server_context& sc,
|
||||
const trrep::transaction_context& tc,
|
||||
wsrep_seqno_t bf_seqno);
|
||||
|
||||
trrep::transaction_context applying_transaction(
|
||||
trrep::client_context& cc,
|
||||
const trrep::transaction_id& id,
|
||||
wsrep_seqno_t seqno,
|
||||
uint32_t flags);
|
||||
}
|
@ -94,6 +94,9 @@ int trrep::server_context::on_apply(
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
assert(ret ||
|
||||
transaction_context.state() ==
|
||||
trrep::transaction_context::s_committed);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -36,7 +36,6 @@ namespace trrep
|
||||
, name_(name)
|
||||
, id_(id)
|
||||
, rollback_mode_(rollback_mode)
|
||||
|
||||
{ }
|
||||
|
||||
//
|
||||
|
84
src/server_context_test.cpp
Normal file
84
src/server_context_test.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright (C) 2018 Codership Oy <info@codership.com>
|
||||
//
|
||||
|
||||
#include "mock_server_context.hpp"
|
||||
#include "mock_utils.hpp"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
// Test on_apply() method for 1pc
|
||||
BOOST_AUTO_TEST_CASE(server_context_applying_1pc)
|
||||
{
|
||||
trrep::mock_server_context sc("s1", "s1",
|
||||
trrep::server_context::rm_sync);
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier,
|
||||
false);
|
||||
trrep::transaction_context tc(
|
||||
trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
char buf[1] = { 1 };
|
||||
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 0);
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed);
|
||||
}
|
||||
|
||||
// Test on_apply() method for 2pc
|
||||
BOOST_AUTO_TEST_CASE(server_context_applying_2pc)
|
||||
{
|
||||
trrep::mock_server_context sc("s1", "s1",
|
||||
trrep::server_context::rm_sync);
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier,
|
||||
true);
|
||||
trrep::transaction_context tc(
|
||||
trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
char buf[1] = { 1 };
|
||||
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 0);
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_committed);
|
||||
}
|
||||
|
||||
// Test on_apply() method for 1pc transaction which
|
||||
// fails applying and rolls back
|
||||
BOOST_AUTO_TEST_CASE(server_context_applying_1pc_rollback)
|
||||
{
|
||||
trrep::mock_server_context sc("s1", "s1",
|
||||
trrep::server_context::rm_sync);
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier,
|
||||
false);
|
||||
cc.fail_next_applying(true);
|
||||
trrep::transaction_context tc(
|
||||
trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
char buf[1] = { 1 };
|
||||
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 1);
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted);
|
||||
}
|
||||
|
||||
// Test on_apply() method for 2pc transaction which
|
||||
// fails applying and rolls back
|
||||
BOOST_AUTO_TEST_CASE(server_context_applying_2pc_rollback)
|
||||
{
|
||||
trrep::mock_server_context sc("s1", "s1",
|
||||
trrep::server_context::rm_sync);
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier,
|
||||
true);
|
||||
cc.fail_next_applying(true);
|
||||
trrep::transaction_context tc(
|
||||
trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
char buf[1] = { 1 };
|
||||
BOOST_REQUIRE(sc.on_apply(cc, tc, trrep::data(buf, 1)) == 1);
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_aborted);
|
||||
}
|
@ -7,50 +7,10 @@
|
||||
#include "mock_server_context.hpp"
|
||||
#include "provider.hpp"
|
||||
|
||||
#include "mock_utils.hpp"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
//
|
||||
// Utility functions
|
||||
//
|
||||
namespace
|
||||
{
|
||||
// Simple BF abort method to BF abort unordered transasctions
|
||||
void bf_abort_unordered(trrep::client_context& cc,
|
||||
trrep::transaction_context& tc)
|
||||
{
|
||||
trrep::unique_lock<trrep::mutex> lock(cc.mutex());
|
||||
tc.state(lock, trrep::transaction_context::s_must_abort);
|
||||
}
|
||||
|
||||
// BF abort method to abort transactions via provider
|
||||
void bf_abort_provider(trrep::mock_server_context& sc,
|
||||
const trrep::transaction_context& tc,
|
||||
wsrep_seqno_t bf_seqno)
|
||||
{
|
||||
wsrep_seqno_t victim_seqno;
|
||||
sc.provider().bf_abort(bf_seqno, tc.id().get(), &victim_seqno);
|
||||
(void)victim_seqno;
|
||||
}
|
||||
|
||||
trrep::transaction_context applying_transaction(
|
||||
trrep::client_context& cc,
|
||||
trrep::transaction_id id,
|
||||
wsrep_seqno_t seqno,
|
||||
uint32_t flags)
|
||||
{
|
||||
wsrep_ws_handle_t ws_handle = { id.get(), 0 };
|
||||
wsrep_trx_meta_t meta = {
|
||||
{ {1 }, seqno }, /* gtid */
|
||||
{ { static_cast<uint8_t>(cc.id().get()) }, id.get(), cc.id().get() }, /* stid */
|
||||
seqno - 1
|
||||
};
|
||||
trrep::transaction_context ret(cc, ws_handle, meta, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Test a succesful 1PC transaction lifecycle
|
||||
//
|
||||
@ -196,7 +156,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_before_before_commit)
|
||||
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
|
||||
|
||||
bf_abort_unordered(cc, tc);
|
||||
trrep_mock::bf_abort_unordered(cc, tc);
|
||||
|
||||
// Run before commit
|
||||
BOOST_REQUIRE(tc.before_commit());
|
||||
@ -237,7 +197,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc_bf_before_before_prepare)
|
||||
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
|
||||
|
||||
bf_abort_unordered(cc, tc);
|
||||
trrep_mock::bf_abort_unordered(cc, tc);
|
||||
|
||||
// Run before commit
|
||||
BOOST_REQUIRE(tc.before_prepare());
|
||||
@ -282,7 +242,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc_bf_before_after_prepare)
|
||||
BOOST_REQUIRE(tc.before_prepare() == 0);
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_preparing);
|
||||
|
||||
bf_abort_unordered(cc, tc);
|
||||
trrep_mock::bf_abort_unordered(cc, tc);
|
||||
|
||||
// Run before commit
|
||||
BOOST_REQUIRE(tc.after_prepare());
|
||||
@ -324,7 +284,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_uncertified
|
||||
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
|
||||
|
||||
bf_abort_provider(sc, tc, WSREP_SEQNO_UNDEFINED);
|
||||
trrep_mock::bf_abort_provider(sc, tc, WSREP_SEQNO_UNDEFINED);
|
||||
|
||||
// Run before commit
|
||||
BOOST_REQUIRE(tc.before_commit());
|
||||
@ -367,7 +327,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_bf_during_before_commit_certified)
|
||||
BOOST_REQUIRE(tc.id() == trrep::transaction_id(1));
|
||||
BOOST_REQUIRE(tc.state() == trrep::transaction_context::s_executing);
|
||||
|
||||
bf_abort_provider(sc, tc, 1);
|
||||
trrep_mock::bf_abort_provider(sc, tc, 1);
|
||||
|
||||
// Run before commit
|
||||
BOOST_REQUIRE(tc.before_commit());
|
||||
@ -395,7 +355,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_1pc_applying)
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier);
|
||||
trrep::transaction_context tc(applying_transaction(
|
||||
trrep::transaction_context tc(trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
|
||||
@ -420,7 +380,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_2pc_applying)
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier);
|
||||
trrep::transaction_context tc(applying_transaction(
|
||||
trrep::transaction_context tc(trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
|
||||
@ -449,7 +409,7 @@ BOOST_AUTO_TEST_CASE(transaction_context_applying_rollback)
|
||||
trrep::mock_client_context cc(sc,
|
||||
trrep::client_id(1),
|
||||
trrep::client_context::m_applier);
|
||||
trrep::transaction_context tc(applying_transaction(
|
||||
trrep::transaction_context tc(trrep_mock::applying_transaction(
|
||||
cc, 1, 1,
|
||||
WSREP_FLAG_TRX_START | WSREP_FLAG_TRX_END));
|
||||
|
||||
|
Reference in New Issue
Block a user