/* * * 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 #include using namespace qpid::broker; using boost::static_pointer_cast; using std::string; namespace qpid { namespace tests { template void assertEqualVector(std::vector& expected, std::vector& 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 expected; std::vector actual; bool failOnPrepare; string debugName; public: typedef boost::shared_ptr 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::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::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); } 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); } void accept(TxOpConstVisitor&) const {} ~MockTxOp(){} }; class MockTransactionalStore : public TransactionalStore{ const string BEGIN; const string BEGIN2PC; const string PREPARE; const string COMMIT; const string ABORT; std::vector expected; std::vector 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&) { throw "Operation not supported"; } std::auto_ptr begin(const std::string&){ actual.push_back(BEGIN2PC); std::auto_ptr txn(new TestTransactionContext(this)); return txn; } std::auto_ptr begin(){ actual.push_back(BEGIN); std::auto_ptr txn(new TestTransactionContext(this)); return txn; } void prepare(TPCTransactionContext& ctxt){ actual.push_back(PREPARE); dynamic_cast(ctxt).prepare(); } void commit(TransactionContext& ctxt){ actual.push_back(COMMIT); dynamic_cast(ctxt).commit(); } void abort(TransactionContext& ctxt){ actual.push_back(ABORT); dynamic_cast(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