blob: 8b54e7484b529011df3f8c50b32eb2d9e4bd8884 [file] [log] [blame]
/*
*
* 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