| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| #ifndef _tests_TxMocks_h |
| #define _tests_TxMocks_h |
| |
| |
| #include "qpid/Exception.h" |
| #include "qpid/Msg.h" |
| #include "qpid/broker/TransactionalStore.h" |
| #include "qpid/broker/TxOp.h" |
| #include <iostream> |
| #include <vector> |
| |
| using namespace qpid::broker; |
| using boost::static_pointer_cast; |
| using std::string; |
| |
| namespace qpid { |
| namespace tests { |
| |
| template <class T> void assertEqualVector(std::vector<T>& expected, std::vector<T>& actual){ |
| unsigned int i = 0; |
| while(i < expected.size() && i < actual.size()){ |
| BOOST_CHECK_EQUAL(expected[i], actual[i]); |
| i++; |
| } |
| if (i < expected.size()) { |
| throw qpid::Exception(QPID_MSG("Missing " << expected[i])); |
| } else if (i < actual.size()) { |
| throw qpid::Exception(QPID_MSG("Extra " << actual[i])); |
| } |
| BOOST_CHECK_EQUAL(expected.size(), actual.size()); |
| } |
| |
| class TxOpConstants{ |
| protected: |
| const string PREPARE; |
| const string COMMIT; |
| const string ROLLBACK; |
| |
| TxOpConstants() : PREPARE("PREPARE"), COMMIT("COMMIT"), ROLLBACK("ROLLBACK") {} |
| }; |
| |
| class MockTxOp : public TxOp, public TxOpConstants{ |
| std::vector<string> expected; |
| std::vector<string> actual; |
| bool failOnPrepare; |
| string debugName; |
| public: |
| typedef boost::shared_ptr<MockTxOp> shared_ptr; |
| |
| MockTxOp() : failOnPrepare(false) {} |
| MockTxOp(bool _failOnPrepare) : failOnPrepare(_failOnPrepare) {} |
| |
| void setDebugName(string name){ |
| debugName = name; |
| } |
| |
| void printExpected(){ |
| std::cout << std::endl << "MockTxOp[" << debugName << "] expects: "; |
| for (std::vector<string>::iterator i = expected.begin(); i < expected.end(); i++) { |
| if(i != expected.begin()) std::cout << ", "; |
| std::cout << *i; |
| } |
| std::cout << std::endl; |
| } |
| |
| void printActual(){ |
| std::cout << std::endl << "MockTxOp[" << debugName << "] actual: "; |
| for (std::vector<string>::iterator i = actual.begin(); i < actual.end(); i++) { |
| if(i != actual.begin()) std::cout << ", "; |
| std::cout << *i; |
| } |
| std::cout << std::endl; |
| } |
| |
| bool prepare(TransactionContext*) throw(){ |
| actual.push_back(PREPARE); |
| return !failOnPrepare; |
| } |
| void commit() throw(){ |
| actual.push_back(COMMIT); |
| } |
| void rollback() throw(){ |
| if(!debugName.empty()) std::cout << std::endl << "MockTxOp[" << debugName << "]::rollback()" << std::endl; |
| actual.push_back(ROLLBACK); |
| } |
| |
| void callObserver(const boost::shared_ptr<TransactionObserver>&) {} |
| |
| MockTxOp& expectPrepare(){ |
| expected.push_back(PREPARE); |
| return *this; |
| } |
| MockTxOp& expectCommit(){ |
| expected.push_back(COMMIT); |
| return *this; |
| } |
| MockTxOp& expectRollback(){ |
| expected.push_back(ROLLBACK); |
| return *this; |
| } |
| void check(){ |
| assertEqualVector(expected, actual); |
| } |
| |
| ~MockTxOp(){} |
| }; |
| |
| class MockTransactionalStore : public TransactionalStore{ |
| const string BEGIN; |
| const string BEGIN2PC; |
| const string PREPARE; |
| const string COMMIT; |
| const string ABORT; |
| std::vector<string> expected; |
| std::vector<string> actual; |
| |
| enum states {OPEN = 1, PREPARED = 2, COMMITTED = 3, ABORTED = 4}; |
| int state; |
| |
| class TestTransactionContext : public TPCTransactionContext{ |
| MockTransactionalStore* store; |
| public: |
| TestTransactionContext(MockTransactionalStore* _store) : store(_store) {} |
| void prepare(){ |
| if(!store->isOpen()) throw "txn already completed"; |
| store->state = PREPARED; |
| } |
| |
| void commit(){ |
| if(!store->isOpen() && !store->isPrepared()) throw "txn already completed"; |
| store->state = COMMITTED; |
| } |
| |
| void abort(){ |
| if(!store->isOpen() && !store->isPrepared()) throw "txn already completed"; |
| store->state = ABORTED; |
| } |
| ~TestTransactionContext(){} |
| }; |
| |
| public: |
| MockTransactionalStore() : |
| BEGIN("BEGIN"), BEGIN2PC("BEGIN2PC"), PREPARE("PREPARE"), COMMIT("COMMIT"), ABORT("ABORT"), state(OPEN){} |
| |
| void collectPreparedXids(std::set<std::string>&) |
| { |
| throw "Operation not supported"; |
| } |
| |
| std::auto_ptr<TPCTransactionContext> begin(const std::string&){ |
| actual.push_back(BEGIN2PC); |
| std::auto_ptr<TPCTransactionContext> txn(new TestTransactionContext(this)); |
| return txn; |
| } |
| std::auto_ptr<TransactionContext> begin(){ |
| actual.push_back(BEGIN); |
| std::auto_ptr<TransactionContext> txn(new TestTransactionContext(this)); |
| return txn; |
| } |
| void prepare(TPCTransactionContext& ctxt){ |
| actual.push_back(PREPARE); |
| dynamic_cast<TestTransactionContext&>(ctxt).prepare(); |
| } |
| void commit(TransactionContext& ctxt){ |
| actual.push_back(COMMIT); |
| dynamic_cast<TestTransactionContext&>(ctxt).commit(); |
| } |
| void abort(TransactionContext& ctxt){ |
| actual.push_back(ABORT); |
| dynamic_cast<TestTransactionContext&>(ctxt).abort(); |
| } |
| MockTransactionalStore& expectBegin(){ |
| expected.push_back(BEGIN); |
| return *this; |
| } |
| MockTransactionalStore& expectBegin2PC(){ |
| expected.push_back(BEGIN2PC); |
| return *this; |
| } |
| MockTransactionalStore& expectPrepare(){ |
| expected.push_back(PREPARE); |
| return *this; |
| } |
| MockTransactionalStore& expectCommit(){ |
| expected.push_back(COMMIT); |
| return *this; |
| } |
| MockTransactionalStore& expectAbort(){ |
| expected.push_back(ABORT); |
| return *this; |
| } |
| void check(){ |
| assertEqualVector(expected, actual); |
| } |
| |
| bool isPrepared(){ |
| return state == PREPARED; |
| } |
| |
| bool isCommitted(){ |
| return state == COMMITTED; |
| } |
| |
| bool isAborted(){ |
| return state == ABORTED; |
| } |
| |
| bool isOpen() const{ |
| return state == OPEN; |
| } |
| ~MockTransactionalStore(){} |
| }; |
| |
| }} // namespace qpid::tests |
| |
| #endif |