//@file chunktests.cpp : s/chunk.{h,cpp} tests
/**
* Copyright (C) 2012 10gen 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 .
*/
#include "pch.h"
#include "../s/chunk.h"
#include "mongo/db/json.h"
#include "dbtests.h"
namespace mongo {
class TestableChunkManager : public ChunkManager {
public:
void setShardKey( const BSONObj &keyPattern ) {
const_cast(_key) = ShardKeyPattern( keyPattern );
}
void setSingleChunkForShards( const vector &splitPoints ) {
ChunkMap &chunkMap = const_cast( _chunkMap );
ChunkRangeManager &chunkRanges = const_cast( _chunkRanges );
set &shards = const_cast&>( _shards );
vector mySplitPoints( splitPoints );
mySplitPoints.insert( mySplitPoints.begin(), _key.globalMin() );
mySplitPoints.push_back( _key.globalMax() );
for( unsigned i = 1; i < mySplitPoints.size(); ++i ) {
string name = str::stream() << (i-1);
Shard shard( name, name );
shards.insert( shard );
ChunkPtr chunk( new Chunk( this, mySplitPoints[ i-1 ], mySplitPoints[ i ],
shard ) );
chunkMap[ mySplitPoints[ i ] ] = chunk;
}
chunkRanges.reloadAll( chunkMap );
}
};
} // namespace mongo
namespace ChunkTests {
namespace ChunkManagerTests {
typedef mongo::TestableChunkManager ChunkManager;
class Create {
public:
void run() {
ChunkManager chunkManager;
}
};
class Base {
public:
virtual ~Base() {}
void run() {
ChunkManager chunkManager;
chunkManager.setShardKey( shardKey() );
chunkManager.setSingleChunkForShards( splitPointsVector() );
set shards;
chunkManager.getShardsForQuery( shards, query() );
BSONArrayBuilder b;
for( set::const_iterator i = shards.begin(); i != shards.end(); ++i ) {
b << i->getName();
}
ASSERT_EQUALS( expectedShardNames(), b.arr() );
}
protected:
virtual BSONObj shardKey() const { return BSON( "a" << 1 ); }
virtual BSONArray splitPoints() const { return BSONArray(); }
virtual BSONObj query() const { return BSONObj(); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "0" ); }
virtual vector splitPointsVector() const {
vector ret;
BSONArray a = splitPoints();
BSONObjIterator i( a );
while( i.more() ) {
ret.push_back( i.next().Obj().getOwned() );
}
return ret;
}
};
class EmptyQuerySingleShard : public Base {
};
class MultiShardBase : public Base {
virtual BSONArray splitPoints() const {
return BSON_ARRAY( BSON( "a" << "x" ) << BSON( "a" << "y" ) << BSON( "a" << "z" ) );
}
};
class EmptyQueryMultiShard : public MultiShardBase {
virtual BSONArray expectedShardNames() const {
return BSON_ARRAY( "0" << "1" << "2" << "3" );
}
};
class UniversalRangeMultiShard : public EmptyQueryMultiShard {
virtual BSONObj query() const { return BSON( "b" << 1 ); }
};
class EqualityRangeSingleShard : public EmptyQuerySingleShard {
virtual BSONObj query() const { return BSON( "a" << "x" ); }
};
class EqualityRangeMultiShard : public MultiShardBase {
virtual BSONObj query() const { return BSON( "a" << "y" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "2" ); }
};
class SetRangeMultiShard : public MultiShardBase {
virtual BSONObj query() const { return fromjson( "{a:{$in:['u','y']}}" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "0" << "2" ); }
};
class GTRangeMultiShard : public MultiShardBase {
virtual BSONObj query() const { return BSON( "a" << GT << "x" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "1" << "2" << "3" ); }
};
class GTERangeMultiShard : public MultiShardBase {
virtual BSONObj query() const { return BSON( "a" << GTE << "x" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "1" << "2" << "3" ); }
};
class LTRangeMultiShard : public MultiShardBase {
virtual BSONObj query() const { return BSON( "a" << LT << "y" ); }
/**
* It isn't actually necessary to return shard 2 because its lowest key is "y", which
* is excluded from the query. SERVER-4791
*/
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "0" << "1" << "2" ); }
};
class LTERangeMultiShard : public MultiShardBase {
virtual BSONObj query() const { return BSON( "a" << LTE << "y" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "0" << "1" << "2" ); }
};
class OrEqualities : public MultiShardBase {
virtual BSONObj query() const { return fromjson( "{$or:[{a:'u'},{a:'y'}]}" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "0" << "2" ); }
};
class OrEqualityInequality : public MultiShardBase {
virtual BSONObj query() const { return fromjson( "{$or:[{a:'u'},{a:{$gte:'y'}}]}" ); }
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "0" << "2" << "3" ); }
};
class OrEqualityInequalityUnhelpful : public MultiShardBase {
virtual BSONObj query() const {
return fromjson( "{$or:[{a:'u'},{a:{$gte:'zz'}},{}]}" );
}
virtual BSONArray expectedShardNames() const {
return BSON_ARRAY( "0" << "1" << "2" << "3" );
}
};
template
class Unsatisfiable : public BASE {
/**
* SERVER-4914 For now the first shard is returned for unsatisfiable queries, as some
* clients of getShardsForQuery() expect at least one shard.
*/
virtual BSONArray expectedShardNames() const {
return BSON_ARRAY( "0" ) /* BSONArray() */;
}
};
class UnsatisfiableRangeSingleShard : public Unsatisfiable {
virtual BSONObj query() const { return BSON( "a" << GT << "x" << LT << "x" ); }
};
class UnsatisfiableRangeMultiShard : public Unsatisfiable {
virtual BSONObj query() const { return BSON( "a" << GT << "x" << LT << "x" ); }
};
class EqualityThenUnsatisfiable : public Unsatisfiable {
virtual BSONObj shardKey() const { return BSON( "a" << 1 << "b" << 1 ); }
virtual BSONObj query() const { return BSON( "a" << 1 << "b" << GT << 4 << LT << 4 ); }
};
class InequalityThenUnsatisfiable : public Unsatisfiable {
virtual BSONObj shardKey() const { return BSON( "a" << 1 << "b" << 1 ); }
virtual BSONObj query() const {
return BSON( "a" << GT << 1 << "b" << GT << 4 << LT << 4 );
}
};
class OrEqualityUnsatisfiableInequality : public MultiShardBase {
virtual BSONObj query() const {
return fromjson( "{$or:[{a:'x'},{a:{$gt:'u',$lt:'u'}},{a:{$gte:'y'}}]}" );
}
virtual BSONArray expectedShardNames() const { return BSON_ARRAY( "1" << "2" << "3" ); }
};
class CompoundKeyBase : public Base {
virtual BSONObj shardKey() const {
return BSON( "a" << 1 << "b" << 1 );
}
virtual BSONArray splitPoints() const {
return BSON_ARRAY( BSON( "a" << 5 << "b" << 10 ) << BSON ( "a" << 5 << "b" << 20 ) );
}
};
class InMultiShard : public CompoundKeyBase {
virtual BSONObj query() const {
return BSON( "a" << BSON( "$in" << BSON_ARRAY( 0 << 5 << 10 ) ) <<
"b" << BSON( "$in" << BSON_ARRAY( 0 << 5 << 25 ) ) );
}
// If we were to send this query to just the shards it actually needed to hit, it would only hit shards 0 and 2
// Because of the optimization from SERVER-4745, however, we'll also hit shard 1.
virtual BSONArray expectedShardNames() const {
return BSON_ARRAY( "0" << "1" << "2" );
}
};
} // namespace ChunkManagerTests
class All : public Suite {
public:
All() : Suite( "chunk" ) {
}
void setupTests() {
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
}
} myall;
} // namespace ChunkTests