diff options
author | David Percy <david.percy@mongodb.com> | 2014-11-05 11:42:40 -0500 |
---|---|---|
committer | David Percy <david.percy@mongodb.com> | 2014-11-06 19:18:16 -0500 |
commit | e1fa60e4d8b3f525575b4602b208f2a1ef353735 (patch) | |
tree | 634a6debfaa9d1f8e3eb58403f085b1b4607850a /src/mongo/dbtests/rollbacktests.cpp | |
parent | a1fc18243a20cc8c5fd4ef7ee3e9f2078b4139d7 (diff) | |
download | mongo-e1fa60e4d8b3f525575b4602b208f2a1ef353735.tar.gz |
SERVER-13635 Test collection and index rollback
Diffstat (limited to 'src/mongo/dbtests/rollbacktests.cpp')
-rw-r--r-- | src/mongo/dbtests/rollbacktests.cpp | 684 |
1 files changed, 684 insertions, 0 deletions
diff --git a/src/mongo/dbtests/rollbacktests.cpp b/src/mongo/dbtests/rollbacktests.cpp new file mode 100644 index 00000000000..324f97c7924 --- /dev/null +++ b/src/mongo/dbtests/rollbacktests.cpp @@ -0,0 +1,684 @@ +// rollbacktests.cpp + +/** + * Copyright (C) 2014 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/bson/bsonobj.h" +#include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/database_catalog_entry.h" +#include "mongo/db/catalog/database_holder.h" +#include "mongo/db/catalog/index_create.h" +#include "mongo/db/diskloc.h" +#include "mongo/db/operation_context_impl.h" +#include "mongo/dbtests/dbtests.h" +#include "mongo/unittest/unittest.h" + +using std::list; +using std::string; + +namespace RollbackTests { + +namespace { + void dropDatabase( OperationContext* txn, const NamespaceString& nss ) { + Lock::GlobalWrite globalWriteLock( txn->lockState() ); + Database* db = dbHolder().get( txn, nss.db() ); + + if ( db ) { + dropDatabase( txn, db ); + } + } + bool collectionExists( Client::Context* ctx, const string& ns ) { + const DatabaseCatalogEntry* dbEntry = ctx->db()->getDatabaseCatalogEntry(); + list<string> names; + dbEntry->getCollectionNamespaces( &names ); + return std::find( names.begin(), names.end(), ns ) != names.end(); + } + void createCollection( OperationContext* txn, const NamespaceString& nss ) { + Lock::DBLock dbXLock( txn->lockState(), nss.db(), MODE_X ); + Client::Context ctx( txn, nss.ns() ); + { + WriteUnitOfWork uow( txn ); + ASSERT( !collectionExists( &ctx, nss.ns() ) ); + ASSERT_OK( userCreateNS( txn, ctx.db(), nss.ns(), BSONObj(), false, false ) ); + ASSERT( collectionExists( &ctx, nss.ns() ) ); + uow.commit(); + } + } + Status renameCollection( OperationContext* txn, + const NamespaceString& source, + const NamespaceString& target ) { + ASSERT_EQ( source.db(), target.db() ); + Database* db = dbHolder().get( txn, source.db() ); + return db->renameCollection( txn, source.ns(), target.ns(), false ); + } + Status truncateCollection( OperationContext* txn, const NamespaceString& nss ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + return coll->truncate( txn ); + } + DiskLoc insertRecord( OperationContext* txn, + const NamespaceString& nss, + const BSONObj& data ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + StatusWith<DiskLoc> status = coll->insertDocument( txn, data, false ); + ASSERT_OK( status.getStatus() ); + return status.getValue(); + } + void assertOnlyRecord( OperationContext* txn, + const NamespaceString& nss, + const BSONObj& data ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + scoped_ptr<RecordIterator> iter( coll->getIterator( txn ) ); + ASSERT( !iter->isEOF() ); + DiskLoc loc = iter->getNext(); + ASSERT( iter->isEOF() ); + ASSERT_EQ( data, coll->docFor( txn, loc ) ); + } + void assertEmpty( OperationContext* txn, const NamespaceString& nss ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + scoped_ptr<RecordIterator> iter( coll->getIterator( txn ) ); + ASSERT( iter->isEOF() ); + } + bool indexExists( OperationContext* txn, const NamespaceString& nss, const string& idxName ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + return coll->getIndexCatalog()->findIndexByName( txn, idxName, true ) != NULL; + } + bool indexReady( OperationContext* txn, const NamespaceString& nss, const string& idxName ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + return coll->getIndexCatalog()->findIndexByName( txn, idxName, false ) != NULL; + } + size_t getNumIndexEntries( OperationContext* txn, + const NamespaceString& nss, + const string& idxName ) { + size_t numEntries = 0; + + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + IndexCatalog* catalog = coll->getIndexCatalog(); + IndexDescriptor* desc = catalog->findIndexByName( txn, idxName, false ); + + if ( desc ) { + CursorOptions cursorOptions; + cursorOptions.direction = CursorOptions::INCREASING; + + IndexCursor *cursor; + ASSERT_OK( catalog->getIndex( desc )->newCursor( txn, cursorOptions, &cursor ) ); + ASSERT_OK( cursor->seek( minKey ) ); + + while ( !cursor->isEOF() ) { + numEntries++; + cursor->next(); + } + delete cursor; + } + + return numEntries; + } + void dropIndex( OperationContext* txn, const NamespaceString& nss, const string& idxName ) { + Collection* coll = dbHolder().get( txn, nss.db() )->getCollection( txn, nss.ns() ); + IndexDescriptor* desc = coll->getIndexCatalog()->findIndexByName( txn, idxName ); + ASSERT( desc ); + ASSERT_OK( coll->getIndexCatalog()->dropIndex( txn, desc ) ); + } +} // namespace + + template<bool rollback, bool defaultIndexes> + class CreateCollection { + public: + void run() { + string ns = "unittests.rollback_create_collection"; + OperationContextImpl txn; + NamespaceString nss( ns ); + dropDatabase( &txn, nss ); + + Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); + Client::Context ctx( &txn, ns ); + { + WriteUnitOfWork uow( &txn ); + ASSERT( !collectionExists( &ctx, ns ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), ns, BSONObj(), false, defaultIndexes ) ); + ASSERT( collectionExists( &ctx, ns ) ); + if ( !rollback ) { + uow.commit(); + } + } + if ( rollback ) { + ASSERT( !collectionExists( &ctx, ns ) ); + } + else { + ASSERT( collectionExists( &ctx, ns ) ); + } + } + }; + + template<bool rollback, bool defaultIndexes> + class DropCollection { + public: + void run() { + string ns = "unittests.rollback_drop_collection"; + OperationContextImpl txn; + NamespaceString nss( ns ); + dropDatabase( &txn, nss ); + + Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); + Client::Context ctx( &txn, ns ); + { + WriteUnitOfWork uow( &txn ); + ASSERT( !collectionExists( &ctx, ns ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), ns, BSONObj(), false, defaultIndexes ) ); + uow.commit(); + } + ASSERT( collectionExists( &ctx, ns ) ); + + // END OF SETUP / START OF TEST + + { + WriteUnitOfWork uow( &txn ); + ASSERT( collectionExists( &ctx, ns ) ); + ASSERT_OK( ctx.db()->dropCollection( &txn, ns ) ); + ASSERT( !collectionExists( &ctx, ns ) ); + if ( !rollback ) { + uow.commit(); + } + } + if ( rollback ) { + ASSERT( collectionExists( &ctx, ns ) ); + } + else { + ASSERT( !collectionExists( &ctx, ns ) ); + } + } + }; + + template<bool rollback, bool defaultIndexes> + class RenameCollection { + public: + void run() { + NamespaceString source( "unittests.rollback_rename_collection_src" ); + NamespaceString target( "unittests.rollback_rename_collection_dest" ); + OperationContextImpl txn; + + dropDatabase( &txn, source ); + dropDatabase( &txn, target ); + + Lock::GlobalWrite globalWriteLock( txn.lockState() ); + Client::Context ctx( &txn, source ); + + { + WriteUnitOfWork uow( &txn ); + ASSERT( !collectionExists( &ctx, source ) ); + ASSERT( !collectionExists( &ctx, target ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), source.ns(), BSONObj(), false, + defaultIndexes ) ); + uow.commit(); + } + ASSERT( collectionExists( &ctx, source ) ); + ASSERT( !collectionExists( &ctx, target ) ); + + // END OF SETUP / START OF TEST + + { + WriteUnitOfWork uow( &txn ); + ASSERT_OK( renameCollection( &txn, source, target ) ); + ASSERT( !collectionExists( &ctx, source ) ); + ASSERT( collectionExists( &ctx, target ) ); + if ( !rollback ) { + uow.commit(); + } + } + if ( rollback ) { + ASSERT( collectionExists( &ctx, source ) ); + ASSERT( !collectionExists( &ctx, target ) ); + } + else { + ASSERT( !collectionExists( &ctx, source ) ); + ASSERT( collectionExists( &ctx, target ) ); + } + } + }; + + template<bool rollback, bool defaultIndexes> + class RenameDropTargetCollection { + public: + void run() { + NamespaceString source( "unittests.rollback_rename_droptarget_collection_src" ); + NamespaceString target( "unittests.rollback_rename_droptarget_collection_dest" ); + OperationContextImpl txn; + + dropDatabase( &txn, source ); + dropDatabase( &txn, target ); + + Lock::GlobalWrite globalWriteLock( txn.lockState() ); + Client::Context ctx( &txn, source ); + + BSONObj sourceDoc = BSON( "_id" << "source" ); + BSONObj targetDoc = BSON( "_id" << "target" ); + + { + WriteUnitOfWork uow( &txn ); + ASSERT( !collectionExists( &ctx, source ) ); + ASSERT( !collectionExists( &ctx, target ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), source.ns(), BSONObj(), false, + defaultIndexes ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), target.ns(), BSONObj(), false, + defaultIndexes ) ); + + insertRecord( &txn, source, sourceDoc ); + insertRecord( &txn, target, targetDoc ); + + uow.commit(); + } + ASSERT( collectionExists( &ctx, source ) ); + ASSERT( collectionExists( &ctx, target ) ); + assertOnlyRecord( &txn, source, sourceDoc ); + assertOnlyRecord( &txn, target, targetDoc ); + + // END OF SETUP / START OF TEST + + { + WriteUnitOfWork uow( &txn ); + ASSERT_OK( ctx.db()->dropCollection( &txn, target.ns() ) ); + ASSERT_OK( renameCollection( &txn, source, target ) ); + ASSERT( !collectionExists( &ctx, source ) ); + ASSERT( collectionExists( &ctx, target ) ); + assertOnlyRecord( &txn, target, sourceDoc ); + if ( !rollback ) { + uow.commit(); + } + } + if ( rollback ) { + ASSERT( collectionExists( &ctx, source ) ); + ASSERT( collectionExists( &ctx, target ) ); + assertOnlyRecord( &txn, source, sourceDoc ); + assertOnlyRecord( &txn, target, targetDoc ); + } + else { + ASSERT( !collectionExists( &ctx, source ) ); + ASSERT( collectionExists( &ctx, target ) ); + assertOnlyRecord( &txn, target, sourceDoc ); + } + } + }; + + template<bool rollback, bool defaultIndexes> + class ReplaceCollection { + public: + void run() { + NamespaceString nss( "unittests.rollback_replace_collection" ); + OperationContextImpl txn; + dropDatabase( &txn, nss ); + + Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); + Client::Context ctx( &txn, nss ); + + BSONObj oldDoc = BSON( "_id" << "old" ); + BSONObj newDoc = BSON( "_id" << "new" ); + + { + WriteUnitOfWork uow( &txn ); + ASSERT( !collectionExists( &ctx, nss ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), nss.ns(), BSONObj(), false, + defaultIndexes ) ); + insertRecord( &txn, nss, oldDoc ); + uow.commit(); + } + ASSERT( collectionExists( &ctx, nss ) ); + assertOnlyRecord( &txn, nss, oldDoc ); + + // END OF SETUP / START OF TEST + + { + WriteUnitOfWork uow( &txn ); + ASSERT_OK( ctx.db()->dropCollection( &txn, nss.ns() ) ); + ASSERT( !collectionExists( &ctx, nss ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), nss.ns(), BSONObj(), false, + defaultIndexes ) ); + ASSERT( collectionExists( &ctx, nss ) ); + insertRecord( &txn, nss, newDoc ); + assertOnlyRecord( &txn, nss, newDoc ); + if ( !rollback ) { + uow.commit(); + } + } + ASSERT( collectionExists( &ctx, nss ) ); + if ( rollback ) { + assertOnlyRecord( &txn, nss, oldDoc ); + } + else { + assertOnlyRecord( &txn, nss, newDoc ); + } + } + }; + + template<bool rollback, bool defaultIndexes> + class CreateDropCollection { + public: + void run() { + NamespaceString nss( "unittests.rollback_create_drop_collection" ); + OperationContextImpl txn; + dropDatabase( &txn, nss ); + + Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); + Client::Context ctx( &txn, nss ); + + BSONObj doc = BSON( "_id" << "example string" ); + + ASSERT( !collectionExists( &ctx, nss ) ); + { + WriteUnitOfWork uow( &txn ); + + ASSERT_OK( userCreateNS( &txn, ctx.db(), nss.ns(), BSONObj(), false, + defaultIndexes ) ); + ASSERT( collectionExists( &ctx, nss ) ); + insertRecord( &txn, nss, doc ); + assertOnlyRecord( &txn, nss, doc ); + + ASSERT_OK( ctx.db()->dropCollection( &txn, nss.ns() ) ); + ASSERT( !collectionExists( &ctx, nss ) ); + + if ( !rollback ) { + uow.commit(); + } + } + ASSERT( !collectionExists( &ctx, nss ) ); + } + }; + + template<bool rollback, bool defaultIndexes> + class TruncateCollection { + public: + void run() { + NamespaceString nss( "unittests.rollback_truncate_collection" ); + OperationContextImpl txn; + dropDatabase( &txn, nss ); + + Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); + Client::Context ctx( &txn, nss ); + + BSONObj doc = BSON( "_id" << "foo" ); + + ASSERT( !collectionExists( &ctx, nss ) ); + { + WriteUnitOfWork uow( &txn ); + + ASSERT_OK( userCreateNS( &txn, ctx.db(), nss.ns(), BSONObj(), false, + defaultIndexes ) ); + ASSERT( collectionExists( &ctx, nss ) ); + insertRecord( &txn, nss, doc ); + assertOnlyRecord( &txn, nss, doc ); + uow.commit(); + } + assertOnlyRecord( &txn, nss, doc ); + + // END OF SETUP / START OF TEST + + { + WriteUnitOfWork uow( &txn ); + + ASSERT_OK( truncateCollection( &txn, nss ) ); + ASSERT( collectionExists( &ctx, nss ) ); + assertEmpty( &txn, nss ); + + if ( !rollback ) { + uow.commit(); + } + } + ASSERT( collectionExists( &ctx, nss ) ); + if ( rollback ) { + assertOnlyRecord( &txn, nss, doc ); + } + else { + assertEmpty( &txn, nss ); + } + } + }; + + template<bool rollback> + class CreateIndex { + public: + void run() { + string ns = "unittests.rollback_create_index"; + OperationContextImpl txn; + NamespaceString nss( ns ); + dropDatabase( &txn, nss ); + createCollection( &txn, nss ); + + Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); + Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); + + Client::Context ctx( &txn, ns ); + Collection* coll = ctx.db()->getCollection( &txn, ns ); + IndexCatalog* catalog = coll->getIndexCatalog(); + + string idxName = "a"; + BSONObj spec = BSON( "ns" << ns << "key" << BSON( "a" << 1 ) << "name" << idxName ); + + // END SETUP / START TEST + + { + WriteUnitOfWork uow( &txn ); + ASSERT_OK( catalog->createIndexOnEmptyCollection( &txn, spec ) ); + insertRecord( &txn, nss, BSON( "a" << 1 ) ); + insertRecord( &txn, nss, BSON( "a" << 2 ) ); + insertRecord( &txn, nss, BSON( "a" << 3 ) ); + if ( !rollback ) { + uow.commit(); + } + } + + if ( rollback ) { + ASSERT( !indexExists( &txn, nss, idxName ) ); + } + else { + ASSERT( indexReady( &txn, nss, idxName ) ); + } + } + }; + + template<bool rollback> + class DropIndex { + public: + void run() { + string ns = "unittests.rollback_drop_index"; + OperationContextImpl txn; + NamespaceString nss( ns ); + dropDatabase( &txn, nss ); + createCollection( &txn, nss ); + + Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); + Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); + + Client::Context ctx( &txn, ns ); + Collection* coll = ctx.db()->getCollection( &txn, ns ); + IndexCatalog* catalog = coll->getIndexCatalog(); + + string idxName = "a"; + BSONObj spec = BSON( "ns" << ns << "key" << BSON( "a" << 1 ) << "name" << idxName ); + + { + WriteUnitOfWork uow( &txn ); + ASSERT_OK( catalog->createIndexOnEmptyCollection( &txn, spec ) ); + insertRecord( &txn, nss, BSON( "a" << 1 ) ); + insertRecord( &txn, nss, BSON( "a" << 2 ) ); + insertRecord( &txn, nss, BSON( "a" << 3 ) ); + uow.commit(); + } + ASSERT( indexReady( &txn, nss, idxName ) ); + ASSERT_EQ( 3u, getNumIndexEntries( &txn, nss, idxName ) ); + + // END SETUP / START TEST + + { + WriteUnitOfWork uow( &txn ); + + dropIndex( &txn, nss, idxName ); + ASSERT( !indexExists( &txn, nss, idxName ) ); + + if ( !rollback ) { + uow.commit(); + } + } + if ( rollback ) { + ASSERT( indexExists( &txn, nss, idxName ) ); + ASSERT( indexReady( &txn, nss, idxName ) ); + ASSERT_EQ( 3u, getNumIndexEntries( &txn, nss, idxName ) ); + } + else { + ASSERT( !indexExists( &txn, nss, idxName ) ); + } + } + }; + + template<bool rollback> + class CreateDropIndex { + public: + void run() { + string ns = "unittests.rollback_create_drop_index"; + OperationContextImpl txn; + NamespaceString nss( ns ); + dropDatabase( &txn, nss ); + createCollection( &txn, nss ); + + Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); + Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); + + Client::Context ctx( &txn, ns ); + Collection* coll = ctx.db()->getCollection( &txn, ns ); + IndexCatalog* catalog = coll->getIndexCatalog(); + + string idxName = "a"; + BSONObj spec = BSON( "ns" << ns << "key" << BSON( "a" << 1 ) << "name" << idxName ); + + // END SETUP / START TEST + + { + WriteUnitOfWork uow( &txn ); + + ASSERT_OK( catalog->createIndexOnEmptyCollection( &txn, spec ) ); + insertRecord( &txn, nss, BSON( "a" << 1 ) ); + insertRecord( &txn, nss, BSON( "a" << 2 ) ); + insertRecord( &txn, nss, BSON( "a" << 3 ) ); + ASSERT( indexExists( &txn, nss, idxName ) ); + ASSERT_EQ( 3u, getNumIndexEntries( &txn, nss, idxName ) ); + + dropIndex( &txn, nss, idxName ); + ASSERT( !indexExists( &txn, nss, idxName ) ); + + if ( !rollback ) { + uow.commit(); + } + } + + ASSERT( !indexExists( &txn, nss, idxName ) ); + } + }; + + template<bool rollback> + class CreateCollectionAndIndexes { + public: + void run() { + string ns = "unittests.rollback_create_collection_and_indexes"; + OperationContextImpl txn; + NamespaceString nss( ns ); + dropDatabase( &txn, nss ); + Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); + Client::Context ctx( &txn, nss.ns() ); + string idxNameA = "indexA"; + string idxNameB = "indexB"; + string idxNameC = "indexC"; + BSONObj specA = BSON( "ns" << ns << "key" << BSON( "a" << 1 ) << "name" << idxNameA ); + BSONObj specB = BSON( "ns" << ns << "key" << BSON( "b" << 1 ) << "name" << idxNameB ); + BSONObj specC = BSON( "ns" << ns << "key" << BSON( "c" << 1 ) << "name" << idxNameC ); + + // END SETUP / START TEST + + { + WriteUnitOfWork uow( &txn ); + ASSERT( !collectionExists( &ctx, nss.ns() ) ); + ASSERT_OK( userCreateNS( &txn, ctx.db(), nss.ns(), BSONObj(), false, false ) ); + ASSERT( collectionExists( &ctx, nss.ns() ) ); + Collection* coll = ctx.db()->getCollection( &txn, ns ); + IndexCatalog* catalog = coll->getIndexCatalog(); + + ASSERT_OK( catalog->createIndexOnEmptyCollection( &txn, specA ) ); + ASSERT_OK( catalog->createIndexOnEmptyCollection( &txn, specB ) ); + ASSERT_OK( catalog->createIndexOnEmptyCollection( &txn, specC ) ); + + if ( !rollback ) { + uow.commit(); + } + } // uow + if ( rollback ) { + ASSERT( !collectionExists( &ctx, ns ) ); + } + else { + ASSERT( collectionExists( &ctx, ns ) ); + ASSERT( indexReady( &txn, nss, idxNameA ) ); + ASSERT( indexReady( &txn, nss, idxNameB ) ); + ASSERT( indexReady( &txn, nss, idxNameC ) ); + } + } + }; + + + class All : public Suite { + public: + All() : Suite( "rollback" ) { + } + + template< template<bool> class T > + void addAll() { + add< T<false> >(); + add< T<true> >(); + } + + template< template<bool, bool> class T > + void addAll() { + add< T<false, false> >(); + add< T<true, false> >(); + add< T<false, true> >(); + add< T<true, true> >(); + } + + void setupTests() { + addAll< CreateCollection >(); + addAll< RenameCollection >(); + addAll< DropCollection >(); + addAll< RenameDropTargetCollection >(); + addAll< ReplaceCollection >(); + addAll< CreateDropCollection >(); + addAll< TruncateCollection >(); + addAll< CreateIndex >(); + addAll< DropIndex >(); + addAll< CreateDropIndex >(); + addAll< CreateCollectionAndIndexes >(); + } + }; + + SuiteInstance<All> all; + +} // namespace RollbackTests + |