1
0
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:
Teemu Ollakka
2018-04-18 15:03:12 +03:00
parent e8f4b2d183
commit cd21425e07
11 changed files with 253 additions and 62 deletions

View File

@ -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
)

View File

@ -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>&)
{ }

View 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;
}

View File

@ -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_;
};
}

View File

@ -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
View 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
View 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);
}

View File

@ -94,6 +94,9 @@ int trrep::server_context::on_apply(
{
ret = 1;
}
assert(ret ||
transaction_context.state() ==
trrep::transaction_context::s_committed);
}
else
{

View File

@ -36,7 +36,6 @@ namespace trrep
, name_(name)
, id_(id)
, rollback_mode_(rollback_mode)
{ }
//

View 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);
}

View File

@ -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));