diff options
author | Eliot Horowitz <eliot@10gen.com> | 2014-09-16 13:01:46 -0400 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2014-09-17 10:49:29 -0400 |
commit | bb0a34d80b4b1e555fab5dda4ddac8ae48e99152 (patch) | |
tree | a3458d9a4fb63f6b8c0723be95f54aa295c9d5be /src/mongo/db | |
parent | cce6a04bcb073699a9e16a6ce9eca587060f8c3f (diff) | |
download | mongo-bb0a34d80b4b1e555fab5dda4ddac8ae48e99152.tar.gz |
SERVER-13635: make generic RecordStoreTestHarness
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/storage/SConscript | 8 | ||||
-rw-r--r-- | src/mongo/db/storage/heap1/SConscript | 10 | ||||
-rw-r--r-- | src/mongo/db/storage/heap1/heap1_record_store_test.cpp | 56 | ||||
-rw-r--r-- | src/mongo/db/storage/record_store_test_harness.cpp | 373 | ||||
-rw-r--r-- | src/mongo/db/storage/record_store_test_harness.h | 54 |
5 files changed, 501 insertions, 0 deletions
diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript index 9da4736e018..fbb4cbb8516 100644 --- a/src/mongo/db/storage/SConscript +++ b/src/mongo/db/storage/SConscript @@ -23,3 +23,11 @@ env.Library( ], LIBDEPS=[] ) + +env.Library( + target='record_store_test_harness', + source=[ + 'record_store_test_harness.cpp', + ], + LIBDEPS=[] + ) diff --git a/src/mongo/db/storage/heap1/SConscript b/src/mongo/db/storage/heap1/SConscript index bd6784c6a5d..9ce15f15997 100644 --- a/src/mongo/db/storage/heap1/SConscript +++ b/src/mongo/db/storage/heap1/SConscript @@ -71,3 +71,13 @@ env.CppUnitTest( ] ) +env.CppUnitTest( + target='storage_heap1_record_storetest', + source=['heap1_record_store_test.cpp' + ], + LIBDEPS=[ + 'storage_heap1_fake', + '$BUILD_DIR/mongo/db/storage/record_store_test_harness' + ] + ) + diff --git a/src/mongo/db/storage/heap1/heap1_record_store_test.cpp b/src/mongo/db/storage/heap1/heap1_record_store_test.cpp new file mode 100644 index 00000000000..cac88f3646d --- /dev/null +++ b/src/mongo/db/storage/heap1/heap1_record_store_test.cpp @@ -0,0 +1,56 @@ +// heap1_record_store_test.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/db/storage/heap1/record_store_heap.h" +#include "mongo/db/storage/heap1/heap1_recovery_unit.h" +#include "mongo/db/storage/record_store_test_harness.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { + + class MyHarnessHelper : public HarnessHelper { + public: + MyHarnessHelper() { + } + + virtual RecordStore* newNonCappedRecordStore() { + return new HeapRecordStore( "a.b" ); + } + + virtual RecoveryUnit* newRecoveryUnit() { + return new Heap1RecoveryUnit(); + } + }; + + HarnessHelper* newHarnessHelper() { + return new MyHarnessHelper(); + } + +} diff --git a/src/mongo/db/storage/record_store_test_harness.cpp b/src/mongo/db/storage/record_store_test_harness.cpp new file mode 100644 index 00000000000..889ee900f1a --- /dev/null +++ b/src/mongo/db/storage/record_store_test_harness.cpp @@ -0,0 +1,373 @@ +// record_store_test_harness.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/db/storage/record_store_test_harness.h" + +#include "mongo/db/storage/record_store.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { + TEST( RecordStoreTestHarness, Simple1 ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + string s = "eliot was here"; + + DiskLoc loc1; + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ); + ASSERT_OK( res.getStatus() ); + loc1 = res.getValue(); + uow.commit(); + } + + ASSERT_EQUALS( s, rs->dataFor( opCtx.get(), loc1 ).data() ); + } + + ASSERT_EQUALS( s, rs->dataFor( NULL, loc1 ).data() ); + ASSERT_EQUALS( 1, rs->numRecords( NULL ) ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ); + ASSERT_OK( res.getStatus() ); + uow.commit(); + } + + } + + ASSERT_EQUALS( 2, rs->numRecords( NULL ) ); + } + + namespace { + class DummyDocWriter : public DocWriter { + public: + virtual ~DummyDocWriter(){} + virtual void writeDocument( char* buf ) const { + memcpy( buf, "eliot", 6 ); + } + virtual size_t documentSize() const { return 6; } + virtual bool addPadding() const { return false; } + + }; + } + + + TEST( RecordStoreTestHarness, Simple1InsertDocWroter ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + DiskLoc loc1; + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + + { + WriteUnitOfWork uow( opCtx.get() ); + DummyDocWriter dw; + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), &dw, false ); + ASSERT_OK( res.getStatus() ); + loc1 = res.getValue(); + uow.commit(); + } + + ASSERT_EQUALS( string("eliot"), rs->dataFor( opCtx.get(), loc1 ).data() ); + } + } + + TEST( RecordStoreTestHarness, Delete1 ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + string s = "eliot was here"; + + DiskLoc loc; + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ); + ASSERT_OK( res.getStatus() ); + loc = res.getValue(); + uow.commit(); + } + + ASSERT_EQUALS( s, rs->dataFor( opCtx.get(), loc ).data() ); + + } + + ASSERT_EQUALS( 1, rs->numRecords( NULL ) ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + + { + WriteUnitOfWork uow( opCtx.get() ); + rs->deleteRecord( opCtx.get(), loc ); + uow.commit(); + } + + ASSERT_EQUALS( 0, rs->numRecords( opCtx.get() ) ); + } + + } + + TEST( RecordStoreTestHarness, Delete2 ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + string s = "eliot was here"; + + DiskLoc loc; + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ); + ASSERT_OK( res.getStatus() ); + res = rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ); + ASSERT_OK( res.getStatus() ); + loc = res.getValue(); + uow.commit(); + } + + } + ASSERT_EQUALS( s, rs->dataFor( NULL, loc ).data() ); + ASSERT_EQUALS( 2, rs->numRecords( NULL ) ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + rs->deleteRecord( opCtx.get(), loc ); + uow.commit(); + } + } + } + + TEST( RecordStoreTestHarness, Update1 ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + string s1 = "eliot was here"; + string s2 = "eliot was here again"; + + DiskLoc loc; + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), + s1.c_str(), s1.size() + 1, + false ); + ASSERT_OK( res.getStatus() ); + loc = res.getValue(); + uow.commit(); + } + + } + + ASSERT_EQUALS( s1, rs->dataFor( NULL, loc ).data() ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->updateRecord( opCtx.get(), loc, + s2.c_str(), s2.size() + 1, + false, NULL ); + ASSERT_OK( res.getStatus() ); + ASSERT_EQUALS( loc, res.getValue() ); + uow.commit(); + } + + } + + ASSERT_EQUALS( 1, rs->numRecords( NULL ) ); + ASSERT_EQUALS( s2, rs->dataFor( NULL, loc ).data() ); + + } + + TEST( RecordStoreTestHarness, UpdateInPlace1 ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + string s1 = "aaa111bbb"; + string s2 = "aaa222bbb"; + + DiskLoc loc; + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), + s1.c_str(), + s1.size() + 1, + -1 ); + ASSERT_OK( res.getStatus() ); + loc = res.getValue(); + uow.commit(); + } + + } + + ASSERT_EQUALS( s1, rs->dataFor( NULL, loc ).data() ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + const char* damageSource = "222"; + mutablebson::DamageVector dv; + dv.push_back( mutablebson::DamageEvent() ); + dv[0].sourceOffset = 0; + dv[0].targetOffset = 3; + dv[0].size = 3; + Status res = rs->updateWithDamages( opCtx.get(), + loc, + damageSource, + dv ); + ASSERT_OK( res ); + uow.commit(); + } + } + ASSERT_EQUALS( s2, rs->dataFor( NULL, loc ).data() ); + } + + + TEST( RecordStoreTestHarness, Truncate1 ) { + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + string s = "eliot was here"; + + DiskLoc loc; + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ); + ASSERT_OK( res.getStatus() ); + loc = res.getValue(); + uow.commit(); + } + + } + + ASSERT_EQUALS( s, rs->dataFor( NULL, loc ).data() ); + + ASSERT_EQUALS( 1, rs->numRecords( NULL ) ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + rs->truncate( opCtx.get() ); + uow.commit(); + } + + } + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + } + + TEST( RecordStoreTestHarness, Cursor1 ) { + const int N = 10; + + scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); + scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); + + ASSERT_EQUALS( 0, rs->numRecords( NULL ) ); + + { + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + { + WriteUnitOfWork uow( opCtx.get() ); + for ( int i = 0; i < N; i++ ) { + string s = str::stream() << "eliot" << i; + ASSERT_OK( rs->insertRecord( opCtx.get(), s.c_str(), s.size() + 1, false ).getStatus() ); + } + uow.commit(); + } + } + + ASSERT_EQUALS( N, rs->numRecords( NULL ) ); + + { + int x = 0; + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + scoped_ptr<RecordIterator> it( rs->getIterator( opCtx.get() ) ); + while ( !it->isEOF() ) { + DiskLoc loc = it->getNext(); + RecordData data = it->dataFor( loc ); + string s = str::stream() << "eliot" << x++; + ASSERT_EQUALS( s, data.data() ); + } + ASSERT_EQUALS( N, x ); + } + + { + int x = N; + scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); + scoped_ptr<RecordIterator> it( rs->getIterator( opCtx.get(), + DiskLoc(), + false, + CollectionScanParams::BACKWARD ) ); + while ( !it->isEOF() ) { + DiskLoc loc = it->getNext(); + RecordData data = it->dataFor( loc ); + string s = str::stream() << "eliot" << --x; + ASSERT_EQUALS( s, data.data() ); + } + ASSERT_EQUALS( 0, x ); + } + + } + +} diff --git a/src/mongo/db/storage/record_store_test_harness.h b/src/mongo/db/storage/record_store_test_harness.h new file mode 100644 index 00000000000..cecaea06c55 --- /dev/null +++ b/src/mongo/db/storage/record_store_test_harness.h @@ -0,0 +1,54 @@ +// record_store_test_harness.h + +/** + * 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. + */ + +#pragma once + +#include "mongo/db/operation_context_noop.h" + +namespace mongo { + + class RecordStore; + class RecoveryUnit; + + class HarnessHelper { + public: + HarnessHelper(){} + virtual ~HarnessHelper(){} + + virtual RecordStore* newNonCappedRecordStore() = 0; + virtual RecoveryUnit* newRecoveryUnit() = 0; + + virtual OperationContext* newOperationContext() { + return new OperationContextNoop( newRecoveryUnit() ); + } + }; + + HarnessHelper* newHarnessHelper(); +} |