summaryrefslogtreecommitdiffstats
path: root/wsrep-lib/test/mock_client_state.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'wsrep-lib/test/mock_client_state.hpp')
-rw-r--r--wsrep-lib/test/mock_client_state.hpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/wsrep-lib/test/mock_client_state.hpp b/wsrep-lib/test/mock_client_state.hpp
new file mode 100644
index 00000000..73b27755
--- /dev/null
+++ b/wsrep-lib/test/mock_client_state.hpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2018 Codership Oy <info@codership.com>
+ *
+ * This file is part of wsrep-lib.
+ *
+ * Wsrep-lib is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Wsrep-lib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wsrep-lib. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef WSREP_MOCK_CLIENT_CONTEXT_HPP
+#define WSREP_MOCK_CLIENT_CONTEXT_HPP
+
+#include "wsrep/client_state.hpp"
+#include "wsrep/mutex.hpp"
+#include "wsrep/compiler.hpp"
+#include "wsrep/client_service.hpp"
+#include "wsrep/condition_variable.hpp"
+
+#include "test_utils.hpp"
+
+namespace wsrep
+{
+ class mock_client_state : public wsrep::client_state
+ {
+ public:
+ mock_client_state(wsrep::server_state& server_state,
+ wsrep::client_service& client_service,
+ const wsrep::client_id& id,
+ enum wsrep::client_state::mode mode)
+ : wsrep::client_state(mutex_, cond_, server_state, client_service,
+ id, mode)
+ , mutex_()
+ , cond_()
+ { }
+ ~mock_client_state() WSREP_OVERRIDE
+ {
+ if (transaction().active())
+ {
+ (void)client_service().bf_rollback();
+ }
+ }
+ private:
+ wsrep::default_mutex mutex_;
+ wsrep::default_condition_variable cond_;
+ public:
+ private:
+ };
+
+
+ class mock_client_service : public wsrep::client_service
+ {
+ public:
+ mock_client_service(wsrep::mock_client_state* client_state)
+ : wsrep::client_service()
+ , is_autocommit_()
+ , do_2pc_()
+ // , fail_next_applying_()
+ // , fail_next_toi_()
+ , bf_abort_during_wait_()
+ , bf_abort_during_fragment_removal_()
+ , error_during_prepare_data_()
+ , killed_before_certify_()
+ , sync_point_enabled_()
+ , sync_point_action_()
+ , bytes_generated_()
+ , client_state_(client_state)
+ , will_replay_called_()
+ , replays_()
+ , unordered_replays_()
+ , aborts_()
+ { }
+ mock_client_service(const mock_client_service&) = delete;
+ mock_client_service& operator=(const mock_client_service&) = delete;
+
+ int bf_rollback() WSREP_OVERRIDE;
+
+ bool interrupted(wsrep::unique_lock<wsrep::mutex>&)
+ const WSREP_OVERRIDE
+ { return killed_before_certify_; }
+
+
+ void emergency_shutdown() WSREP_OVERRIDE { ++aborts_; }
+
+ int remove_fragments() WSREP_OVERRIDE
+ {
+ if (bf_abort_during_fragment_removal_)
+ {
+ client_state_->before_rollback();
+ client_state_->after_rollback();
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ void will_replay() WSREP_OVERRIDE { will_replay_called_ = true; }
+
+ void signal_replayed() WSREP_OVERRIDE { }
+
+ enum wsrep::provider::status replay() WSREP_OVERRIDE;
+
+ enum wsrep::provider::status replay_unordered() WSREP_OVERRIDE
+ {
+ unordered_replays_++;
+ return wsrep::provider::success;
+ }
+
+ void wait_for_replayers(
+ wsrep::unique_lock<wsrep::mutex>& lock)
+ WSREP_OVERRIDE
+ {
+ lock.unlock();
+ if (bf_abort_during_wait_)
+ {
+ wsrep_test::bf_abort_unordered(*client_state_);
+ }
+ lock.lock();
+ }
+
+ int prepare_data_for_replication() WSREP_OVERRIDE
+ {
+ if (error_during_prepare_data_)
+ {
+ return 1;
+ }
+ static const char buf[1] = { 1 };
+ wsrep::const_buffer data = wsrep::const_buffer(buf, 1);
+ return client_state_->append_data(data);
+ }
+
+ void cleanup_transaction() WSREP_OVERRIDE { }
+
+ size_t bytes_generated() const WSREP_OVERRIDE
+ {
+ return bytes_generated_;
+ }
+
+ bool statement_allowed_for_streaming() const WSREP_OVERRIDE
+ { return true; }
+ int prepare_fragment_for_replication(wsrep::mutable_buffer& buffer, size_t& position)
+ WSREP_OVERRIDE
+ {
+ if (error_during_prepare_data_)
+ {
+ return 1;
+ }
+ static const char buf[1] = { 1 };
+ buffer.push_back(&buf[0], &buf[1]);
+ wsrep::const_buffer data(buffer.data(), buffer.size());
+ position = buffer.size();
+ return client_state_->append_data(data);
+ }
+
+ void store_globals() WSREP_OVERRIDE { }
+ void reset_globals() WSREP_OVERRIDE { }
+
+ enum wsrep::provider::status commit_by_xid() WSREP_OVERRIDE
+ {
+ return wsrep::provider::success;
+ }
+
+ bool is_explicit_xa() WSREP_OVERRIDE
+ {
+ return false;
+ }
+
+ bool is_xa_rollback() WSREP_OVERRIDE
+ {
+ return false;
+ }
+
+ void debug_sync(const char* sync_point) WSREP_OVERRIDE
+ {
+ if (sync_point_enabled_ == sync_point)
+ {
+ switch (sync_point_action_)
+ {
+ case spa_bf_abort_unordered:
+ wsrep_test::bf_abort_unordered(*client_state_);
+ break;
+ case spa_bf_abort_ordered:
+ wsrep_test::bf_abort_ordered(*client_state_);
+ break;
+ }
+ }
+ }
+
+ void debug_crash(const char*) WSREP_OVERRIDE
+ {
+ // Not going to do this while unit testing
+ }
+
+
+ //
+ // Knobs to tune the behavior
+ //
+ bool is_autocommit_;
+ bool do_2pc_;
+ // bool fail_next_applying_;
+ // bool fail_next_toi_;
+ bool bf_abort_during_wait_;
+ bool bf_abort_during_fragment_removal_;
+ bool error_during_prepare_data_;
+ bool killed_before_certify_;
+ std::string sync_point_enabled_;
+ enum sync_point_action
+ {
+ spa_bf_abort_unordered,
+ spa_bf_abort_ordered
+ } sync_point_action_;
+ size_t bytes_generated_;
+
+ //
+ // Verifying the state
+ //
+ bool will_replay_called() const { return will_replay_called_; }
+ size_t replays() const { return replays_; }
+ size_t unordered_replays() const { return unordered_replays_; }
+ size_t aborts() const { return aborts_; }
+ private:
+ wsrep::mock_client_state* client_state_;
+ bool will_replay_called_;
+ size_t replays_;
+ size_t unordered_replays_;
+ size_t aborts_;
+ };
+
+ class mock_client
+ : public mock_client_state
+ , public mock_client_service
+ {
+ public:
+ mock_client(wsrep::server_state& server_state,
+ const wsrep::client_id& id,
+ enum wsrep::client_state::mode mode)
+ : mock_client_state(server_state, *this, id, mode)
+ , mock_client_service(static_cast<mock_client_state*>(this))
+ { }
+
+ int after_row()
+ {
+ bytes_generated_++;
+ return wsrep::client_state::after_row();
+ }
+ };
+}
+
+#endif // WSREP_MOCK_CLIENT_CONTEXT_HPP