2009-01-17 14:57:27 +01:00
|
|
|
// namespacetests.cpp : namespace.{h,cpp} unit tests.
|
2008-12-11 17:07:05 +01:00
|
|
|
//
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copyright (C) 2008 10gen Inc.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-12-11 17:07:05 +01:00
|
|
|
* 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.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-12-11 17:07:05 +01:00
|
|
|
* 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.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-12-11 17:07:05 +01:00
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2008-12-11 21:20:28 +01:00
|
|
|
// Where IndexDetails defined.
|
|
|
|
#include "../db/namespace.h"
|
|
|
|
|
|
|
|
#include "../db/db.h"
|
|
|
|
#include "../db/json.h"
|
|
|
|
|
2008-12-11 17:07:05 +01:00
|
|
|
#include "dbtests.h"
|
|
|
|
|
2008-12-11 21:20:28 +01:00
|
|
|
namespace NamespaceTests {
|
2009-01-15 16:17:11 +01:00
|
|
|
namespace IndexDetailsTests {
|
|
|
|
class Base {
|
|
|
|
public:
|
|
|
|
Base() {
|
|
|
|
setClient( ns() );
|
|
|
|
}
|
2009-02-18 19:42:32 +01:00
|
|
|
virtual ~Base() {
|
2009-01-15 16:17:11 +01:00
|
|
|
if ( id_.info.isNull() )
|
|
|
|
return;
|
|
|
|
theDataFileMgr.deleteRecord( ns(), id_.info.rec(), id_.info );
|
|
|
|
ASSERT( theDataFileMgr.findAll( ns() )->eof() );
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
void create() {
|
|
|
|
BSONObjBuilder builder;
|
|
|
|
builder.append( "ns", ns() );
|
|
|
|
builder.append( "name", "testIndex" );
|
|
|
|
builder.append( "key", key() );
|
|
|
|
BSONObj bobj = builder.done();
|
|
|
|
id_.info = theDataFileMgr.insert( ns(), bobj.objdata(), bobj.objsize() );
|
|
|
|
// head not needed for current tests
|
|
|
|
// idx_.head = BtreeBucket::addHead( id_ );
|
|
|
|
}
|
|
|
|
static const char* ns() {
|
2009-05-12 21:58:26 +02:00
|
|
|
return "unittests.indexdetailstests";
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2009-02-13 18:58:05 +01:00
|
|
|
IndexDetails& id() {
|
2009-01-15 16:17:11 +01:00
|
|
|
return id_;
|
|
|
|
}
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
BSONObjBuilder k;
|
|
|
|
k.append( "a", 1 );
|
2009-02-09 19:04:32 +01:00
|
|
|
return k.obj();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
BSONObj aDotB() const {
|
|
|
|
BSONObjBuilder k;
|
|
|
|
k.append( "a.b", 1 );
|
2009-02-09 19:04:32 +01:00
|
|
|
return k.obj();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
BSONObj aAndB() const {
|
|
|
|
BSONObjBuilder k;
|
|
|
|
k.append( "a", 1 );
|
|
|
|
k.append( "b", 1 );
|
2009-02-09 19:04:32 +01:00
|
|
|
return k.obj();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
static vector< int > shortArray() {
|
|
|
|
vector< int > a;
|
|
|
|
a.push_back( 1 );
|
|
|
|
a.push_back( 2 );
|
|
|
|
a.push_back( 3 );
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
static BSONObj simpleBC( int i ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "b", i );
|
|
|
|
b.append( "c", 4 );
|
2009-02-09 19:04:32 +01:00
|
|
|
return b.obj();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
static void checkSize( int expected, const BSONObjSetDefaultOrder &objs ) {
|
|
|
|
ASSERT_EQUALS( BSONObjSetDefaultOrder::size_type( expected ), objs.size() );
|
|
|
|
}
|
|
|
|
static void assertEquals( const BSONObj &a, const BSONObj &b ) {
|
|
|
|
if ( a.woCompare( b ) != 0 ) {
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "expected: " << a.toString()
|
2009-01-15 16:17:11 +01:00
|
|
|
<< ", got: " << b.toString() << endl;
|
|
|
|
}
|
|
|
|
ASSERT( a.woCompare( b ) == 0 );
|
|
|
|
}
|
2009-08-03 20:32:23 +02:00
|
|
|
BSONObj nullObj() const {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.appendNull( "" );
|
|
|
|
return b.obj();
|
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
private:
|
2009-02-06 19:26:29 +01:00
|
|
|
dblock lk_;
|
2009-01-15 16:17:11 +01:00
|
|
|
IndexDetails id_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Create : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
ASSERT_EQUALS( "testIndex", id().indexName() );
|
|
|
|
ASSERT_EQUALS( ns(), id().parentNS() );
|
|
|
|
assertEquals( key(), id().keyPattern() );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GetKeysFromObjectSimple : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder b, e;
|
|
|
|
b.append( "b", 4 );
|
|
|
|
b.append( "a", 5 );
|
|
|
|
e.append( "", 5 );
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
|
|
|
checkSize( 1, keys );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( e.obj(), *keys.begin() );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GetKeysFromObjectDotted : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder a, e, b;
|
|
|
|
b.append( "b", 4 );
|
|
|
|
a.append( "a", b.done() );
|
|
|
|
a.append( "c", "foo" );
|
|
|
|
e.append( "", 4 );
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( a.done(), keys );
|
|
|
|
checkSize( 1, keys );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( e.obj(), *keys.begin() );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GetKeysFromArraySimple : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", shortArray()) ;
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
int j = 1;
|
|
|
|
for ( BSONObjSetDefaultOrder::iterator i = keys.begin(); i != keys.end(); ++i, ++j ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "", j );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( b.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GetKeysFromArrayFirstElement : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", shortArray() );
|
|
|
|
b.append( "b", 2 );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
int j = 1;
|
|
|
|
for ( BSONObjSetDefaultOrder::iterator i = keys.begin(); i != keys.end(); ++i, ++j ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "", j );
|
|
|
|
b.append( "", 2 );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( b.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aAndB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GetKeysFromArraySecondElement : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "first", 5 );
|
|
|
|
b.append( "a", shortArray()) ;
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
int j = 1;
|
|
|
|
for ( BSONObjSetDefaultOrder::iterator i = keys.begin(); i != keys.end(); ++i, ++j ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "", 5 );
|
|
|
|
b.append( "", j );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( b.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
BSONObjBuilder k;
|
|
|
|
k.append( "first", 1 );
|
|
|
|
k.append( "a", 1 );
|
2009-02-09 19:04:32 +01:00
|
|
|
return k.obj();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GetKeysFromSecondLevelArray : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "b", shortArray() );
|
|
|
|
BSONObjBuilder a;
|
|
|
|
a.append( "a", b.done() );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( a.done(), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
int j = 1;
|
|
|
|
for ( BSONObjSetDefaultOrder::iterator i = keys.begin(); i != keys.end(); ++i, ++j ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "", j );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( b.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ParallelArraysBasic : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", shortArray() );
|
|
|
|
b.append( "b", shortArray() );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
ASSERT_EXCEPTION( id().getKeysFromObject( b.done(), keys ),
|
2009-02-06 22:56:14 +01:00
|
|
|
UserException );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aAndB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ArraySubobjectBasic : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
vector< BSONObj > elts;
|
|
|
|
for ( int i = 1; i < 4; ++i )
|
|
|
|
elts.push_back( simpleBC( i ) );
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", elts );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
int j = 1;
|
|
|
|
for ( BSONObjSetDefaultOrder::iterator i = keys.begin(); i != keys.end(); ++i, ++j ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "", j );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( b.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ArraySubobjectMultiFieldIndex : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
vector< BSONObj > elts;
|
|
|
|
for ( int i = 1; i < 4; ++i )
|
|
|
|
elts.push_back( simpleBC( i ) );
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", elts );
|
|
|
|
b.append( "d", 99 );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
int j = 1;
|
|
|
|
for ( BSONObjSetDefaultOrder::iterator i = keys.begin(); i != keys.end(); ++i, ++j ) {
|
|
|
|
BSONObjBuilder c;
|
|
|
|
c.append( "", j );
|
|
|
|
c.append( "", 99 );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( c.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
BSONObjBuilder k;
|
|
|
|
k.append( "a.b", 1 );
|
|
|
|
k.append( "d", 1 );
|
2009-02-09 19:04:32 +01:00
|
|
|
return k.obj();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ArraySubobjectSingleMissing : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
vector< BSONObj > elts;
|
|
|
|
BSONObjBuilder s;
|
|
|
|
s.append( "foo", 41 );
|
2009-02-09 19:04:32 +01:00
|
|
|
elts.push_back( s.obj() );
|
2009-01-15 16:17:11 +01:00
|
|
|
for ( int i = 1; i < 4; ++i )
|
|
|
|
elts.push_back( simpleBC( i ) );
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", elts );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
2009-08-03 20:32:23 +02:00
|
|
|
checkSize( 4, keys );
|
2009-01-15 16:17:11 +01:00
|
|
|
int j = 1;
|
2009-08-03 20:32:23 +02:00
|
|
|
BSONObjSetDefaultOrder::iterator i = keys.begin();
|
2009-08-11 08:36:38 +02:00
|
|
|
assertEquals( nullObj(), *i++ );
|
2009-08-03 20:32:23 +02:00
|
|
|
for ( ; j < 4; ++i, ++j ) {
|
2009-01-15 16:17:11 +01:00
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "", j );
|
2009-02-09 19:04:32 +01:00
|
|
|
assertEquals( b.obj(), *i );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ArraySubobjectMissing : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
vector< BSONObj > elts;
|
|
|
|
BSONObjBuilder s;
|
|
|
|
s.append( "foo", 41 );
|
|
|
|
for ( int i = 1; i < 4; ++i )
|
|
|
|
elts.push_back( s.done() );
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", elts );
|
|
|
|
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( b.done(), keys );
|
2009-08-03 20:32:23 +02:00
|
|
|
checkSize( 1, keys );
|
|
|
|
assertEquals( nullObj(), *keys.begin() );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
2009-02-23 23:26:36 +01:00
|
|
|
|
|
|
|
class MissingField : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( BSON( "b" << 1 ), keys );
|
|
|
|
checkSize( 1, keys );
|
2009-08-03 20:32:23 +02:00
|
|
|
assertEquals( nullObj(), *keys.begin() );
|
2009-02-23 23:26:36 +01:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return BSON( "a" << 1 );
|
|
|
|
}
|
|
|
|
};
|
2009-01-14 23:17:24 +01:00
|
|
|
|
2009-04-06 19:41:47 +02:00
|
|
|
class SubobjectMissing : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( fromjson( "{a:[1,2]}" ), keys );
|
2009-08-03 20:32:23 +02:00
|
|
|
checkSize( 1, keys );
|
|
|
|
assertEquals( nullObj(), *keys.begin() );
|
2009-04-06 19:41:47 +02:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-08-03 20:32:23 +02:00
|
|
|
class ArraySubelementComplex : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( fromjson( "{a:[{b:[2]}]}" ), keys );
|
|
|
|
checkSize( 1, keys );
|
|
|
|
assertEquals( BSON( "" << 2 ), *keys.begin() );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ParallelArraysComplex : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
ASSERT_EXCEPTION( id().getKeysFromObject( fromjson( "{a:[{b:[1],c:[2]}]}" ), keys ),
|
|
|
|
UserException );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return fromjson( "{'a.b':1,'a.c':1}" );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class AlternateMissing : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( fromjson( "{a:[{b:1},{c:2}]}" ), keys );
|
|
|
|
checkSize( 2, keys );
|
|
|
|
BSONObjSetDefaultOrder::iterator i = keys.begin();
|
|
|
|
{
|
|
|
|
BSONObjBuilder e;
|
|
|
|
e.append( "", 1 );
|
|
|
|
e.appendNull( "" );
|
|
|
|
assertEquals( e.obj(), *i++ );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
BSONObjBuilder e;
|
|
|
|
e.appendNull( "" );
|
|
|
|
e.append( "", 2 );
|
|
|
|
assertEquals( e.obj(), *i );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return fromjson( "{'a.b':1,'a.c':1}" );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MultiComplex : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
BSONObjSetDefaultOrder keys;
|
|
|
|
id().getKeysFromObject( fromjson( "{a:[{b:1},{b:[1,2,3]}]}" ), keys );
|
|
|
|
checkSize( 3, keys );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual BSONObj key() const {
|
|
|
|
return aDotB();
|
|
|
|
}
|
|
|
|
};
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
} // namespace IndexDetailsTests
|
|
|
|
|
|
|
|
namespace NamespaceDetailsTests {
|
2009-01-14 23:17:24 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
class Base {
|
|
|
|
public:
|
2009-05-12 21:58:26 +02:00
|
|
|
Base( const char *ns = "unittests.NamespaceDetailsTests" ) : ns_( ns ) {}
|
2009-02-18 19:42:32 +01:00
|
|
|
virtual ~Base() {
|
2009-01-15 16:17:11 +01:00
|
|
|
if ( !nsd() )
|
|
|
|
return;
|
|
|
|
string s( ns() );
|
2009-05-12 21:58:26 +02:00
|
|
|
string errmsg;
|
|
|
|
BSONObjBuilder result;
|
|
|
|
dropCollection( s, errmsg, result );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
protected:
|
|
|
|
void create() {
|
|
|
|
dblock lk;
|
|
|
|
setClient( ns() );
|
|
|
|
string err;
|
|
|
|
ASSERT( userCreateNS( ns(), fromjson( spec() ), err, false ) );
|
|
|
|
}
|
|
|
|
virtual string spec() const {
|
|
|
|
return "{\"capped\":true,\"size\":512}";
|
|
|
|
}
|
|
|
|
int nRecords() const {
|
|
|
|
int count = 0;
|
2009-02-03 05:42:34 +01:00
|
|
|
for ( DiskLoc i = nsd()->firstExtent; !i.isNull(); i = i.ext()->xnext ) {
|
|
|
|
int fileNo = i.ext()->firstRecord.a();
|
|
|
|
if ( fileNo == -1 )
|
|
|
|
continue;
|
|
|
|
for ( int j = i.ext()->firstRecord.getOfs(); j != DiskLoc::NullOfs;
|
|
|
|
j = DiskLoc( fileNo, j ).rec()->nextOfs ) {
|
2009-01-15 16:17:11 +01:00
|
|
|
++count;
|
|
|
|
}
|
2009-02-03 05:42:34 +01:00
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
ASSERT_EQUALS( count, nsd()->nrecords );
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
int nExtents() const {
|
|
|
|
int count = 0;
|
|
|
|
for ( DiskLoc i = nsd()->firstExtent; !i.isNull(); i = i.ext()->xnext )
|
|
|
|
++count;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
static int min( int a, int b ) {
|
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
|
|
|
const char *ns() const {
|
|
|
|
return ns_;
|
|
|
|
}
|
|
|
|
NamespaceDetails *nsd() const {
|
|
|
|
return nsdetails( ns() );
|
|
|
|
}
|
2009-01-31 00:43:13 +01:00
|
|
|
static BSONObj bigObj() {
|
|
|
|
string as( 187, 'a' );
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b.append( "a", as );
|
2009-02-09 19:04:32 +01:00
|
|
|
return b.obj();
|
2009-01-31 00:43:13 +01:00
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
private:
|
|
|
|
const char *ns_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Create : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
ASSERT( nsd() );
|
|
|
|
ASSERT_EQUALS( 0, nRecords() );
|
|
|
|
ASSERT( nsd()->firstExtent == nsd()->capExtent );
|
|
|
|
DiskLoc initial = DiskLoc();
|
|
|
|
initial.setInvalid();
|
|
|
|
ASSERT( initial == nsd()->capFirstNewRecord );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class SingleAlloc : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
2009-01-31 00:43:13 +01:00
|
|
|
BSONObj b = bigObj();
|
|
|
|
ASSERT( !theDataFileMgr.insert( ns(), b.objdata(), b.objsize() ).isNull() );
|
2009-01-15 16:17:11 +01:00
|
|
|
ASSERT_EQUALS( 1, nRecords() );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Realloc : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
2009-01-31 00:43:13 +01:00
|
|
|
BSONObj b = bigObj();
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
DiskLoc l[ 6 ];
|
|
|
|
for ( int i = 0; i < 6; ++i ) {
|
2009-01-31 00:43:13 +01:00
|
|
|
l[ i ] = theDataFileMgr.insert( ns(), b.objdata(), b.objsize() );
|
2009-01-15 16:17:11 +01:00
|
|
|
ASSERT( !l[ i ].isNull() );
|
|
|
|
ASSERT_EQUALS( 1 + i % 2, nRecords() );
|
|
|
|
if ( i > 1 )
|
|
|
|
ASSERT( l[ i ] == l[ i - 2 ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class TwoExtent : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
ASSERT_EQUALS( 2, nExtents() );
|
2009-01-31 00:43:13 +01:00
|
|
|
BSONObj b = bigObj();
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
DiskLoc l[ 8 ];
|
|
|
|
for ( int i = 0; i < 8; ++i ) {
|
2009-05-12 21:58:26 +02:00
|
|
|
l[ i ] = theDataFileMgr.insert( ns(), b.objdata(), b.objsize() );
|
2009-01-15 16:17:11 +01:00
|
|
|
ASSERT( !l[ i ].isNull() );
|
|
|
|
ASSERT_EQUALS( i < 2 ? i + 1 : 3 + i % 2, nRecords() );
|
|
|
|
if ( i > 3 )
|
|
|
|
ASSERT( l[ i ] == l[ i - 4 ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Too big
|
2009-01-31 04:19:12 +01:00
|
|
|
BSONObjBuilder bob;
|
|
|
|
bob.append( "a", string( 787, 'a' ) );
|
|
|
|
BSONObj bigger = bob.done();
|
|
|
|
ASSERT( theDataFileMgr.insert( ns(), bigger.objdata(), bigger.objsize() ).isNull() );
|
2009-01-15 16:17:11 +01:00
|
|
|
ASSERT_EQUALS( 0, nRecords() );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual string spec() const {
|
|
|
|
return "{\"capped\":true,\"size\":512,\"$nExtents\":2}";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Migrate : public Base {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
create();
|
|
|
|
nsd()->deletedList[ 2 ] = nsd()->deletedList[ 0 ].drec()->nextDeleted.drec()->nextDeleted;
|
|
|
|
nsd()->deletedList[ 0 ].drec()->nextDeleted.drec()->nextDeleted = DiskLoc();
|
2009-02-03 05:42:34 +01:00
|
|
|
nsd()->deletedList[ 1 ].Null();
|
2009-01-15 16:17:11 +01:00
|
|
|
NamespaceDetails *d = nsd();
|
|
|
|
zero( &d->capExtent );
|
|
|
|
zero( &d->capFirstNewRecord );
|
|
|
|
|
|
|
|
nsd();
|
|
|
|
|
|
|
|
ASSERT( nsd()->firstExtent == nsd()->capExtent );
|
|
|
|
ASSERT( nsd()->capExtent.getOfs() != 0 );
|
|
|
|
ASSERT( !nsd()->capFirstNewRecord.isValid() );
|
|
|
|
int nDeleted = 0;
|
|
|
|
for ( DiskLoc i = nsd()->deletedList[ 0 ]; !i.isNull(); i = i.drec()->nextDeleted, ++nDeleted );
|
|
|
|
ASSERT_EQUALS( 10, nDeleted );
|
|
|
|
ASSERT( nsd()->deletedList[ 1 ].isNull() );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
static void zero( DiskLoc *d ) {
|
|
|
|
memset( d, 0, sizeof( DiskLoc ) );
|
|
|
|
}
|
|
|
|
virtual string spec() const {
|
|
|
|
return "{\"capped\":true,\"size\":512,\"$nExtents\":10}";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-01-16 23:36:48 +01:00
|
|
|
// This isn't a particularly useful test, and because it doesn't clean up
|
|
|
|
// after itself, /tmp/unittest needs to be cleared after running.
|
|
|
|
// class BigCollection : public Base {
|
|
|
|
// public:
|
|
|
|
// BigCollection() : Base( "NamespaceDetailsTests_BigCollection" ) {}
|
|
|
|
// void run() {
|
|
|
|
// create();
|
|
|
|
// ASSERT_EQUALS( 2, nExtents() );
|
|
|
|
// }
|
|
|
|
// private:
|
|
|
|
// virtual string spec() const {
|
|
|
|
// // NOTE 256 added to size in _userCreateNS()
|
2009-01-31 23:27:25 +01:00
|
|
|
// long long big = MongoDataFile::maxSize() - MDFHeader::headerSize();
|
2009-01-16 23:36:48 +01:00
|
|
|
// stringstream ss;
|
|
|
|
// ss << "{\"capped\":true,\"size\":" << big << "}";
|
|
|
|
// return ss.str();
|
|
|
|
// }
|
|
|
|
// };
|
2009-01-15 16:17:11 +01:00
|
|
|
|
2009-05-04 22:00:28 +02:00
|
|
|
class Size {
|
|
|
|
public:
|
|
|
|
void run() {
|
|
|
|
ASSERT_EQUALS( 496U, sizeof( NamespaceDetails ) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
} // namespace NamespaceDetailsTests
|
|
|
|
|
2009-05-12 22:37:23 +02:00
|
|
|
class All : public Suite {
|
2009-01-15 16:17:11 +01:00
|
|
|
public:
|
|
|
|
All() {
|
|
|
|
add< IndexDetailsTests::Create >();
|
|
|
|
add< IndexDetailsTests::GetKeysFromObjectSimple >();
|
|
|
|
add< IndexDetailsTests::GetKeysFromObjectDotted >();
|
|
|
|
add< IndexDetailsTests::GetKeysFromArraySimple >();
|
|
|
|
add< IndexDetailsTests::GetKeysFromArrayFirstElement >();
|
|
|
|
add< IndexDetailsTests::GetKeysFromArraySecondElement >();
|
|
|
|
add< IndexDetailsTests::GetKeysFromSecondLevelArray >();
|
|
|
|
add< IndexDetailsTests::ParallelArraysBasic >();
|
|
|
|
add< IndexDetailsTests::ArraySubobjectBasic >();
|
|
|
|
add< IndexDetailsTests::ArraySubobjectMultiFieldIndex >();
|
|
|
|
add< IndexDetailsTests::ArraySubobjectSingleMissing >();
|
|
|
|
add< IndexDetailsTests::ArraySubobjectMissing >();
|
2009-08-03 20:32:23 +02:00
|
|
|
add< IndexDetailsTests::ArraySubelementComplex >();
|
|
|
|
add< IndexDetailsTests::ParallelArraysComplex >();
|
|
|
|
add< IndexDetailsTests::AlternateMissing >();
|
|
|
|
add< IndexDetailsTests::MultiComplex >();
|
2009-02-23 23:26:36 +01:00
|
|
|
add< IndexDetailsTests::MissingField >();
|
2009-04-06 19:41:47 +02:00
|
|
|
add< IndexDetailsTests::SubobjectMissing >();
|
2009-01-15 16:17:11 +01:00
|
|
|
add< NamespaceDetailsTests::Create >();
|
|
|
|
add< NamespaceDetailsTests::SingleAlloc >();
|
|
|
|
add< NamespaceDetailsTests::Realloc >();
|
|
|
|
add< NamespaceDetailsTests::TwoExtent >();
|
|
|
|
add< NamespaceDetailsTests::Migrate >();
|
2009-01-16 23:36:48 +01:00
|
|
|
// add< NamespaceDetailsTests::BigCollection >();
|
2009-05-04 22:00:28 +02:00
|
|
|
add< NamespaceDetailsTests::Size >();
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
};
|
2009-01-13 16:36:06 +01:00
|
|
|
} // namespace NamespaceTests
|
2008-12-11 17:07:05 +01:00
|
|
|
|
2008-12-11 21:20:28 +01:00
|
|
|
UnitTest::TestPtr namespaceTests() {
|
2008-12-29 02:28:49 +01:00
|
|
|
return UnitTest::createSuite< NamespaceTests::All >();
|
2008-12-29 14:32:59 +01:00
|
|
|
}
|