/**
 * @tags : [ hashed ] 
 */

// from server 2326 - make sure that sharding only works with unique indices

s = new ShardingTest( "shard_index", 2, 0, 1 )

// Regenerate fully because of SERVER-2782
for ( var i = 0; i < 19; i++ ) {
        
    var coll = s.admin._mongo.getDB( "test" ).getCollection( "foo" + i )
    coll.drop()

    var bulk = coll.initializeUnorderedBulkOp();
    for ( var j = 0; j < 300; j++ ) {
        bulk.insert({ num: j, x: 1 });
    }
    assert.writeOK(bulk.execute());

    if(i == 0) s.adminCommand( { enablesharding : "" + coll._db } );

    print("\n\n\n\n\nTest # " + i)
    
    if ( i == 0 ) {

        // Unique index exists, but not the right one.
        coll.ensureIndex( { num : 1 }, { unique : true } )
        coll.ensureIndex( { x : 1 } )

        passed = false
        try {
            s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } )
            passed = true
        } catch (e) {
            print( e )
        }
        assert( !passed, "Should not shard collection when another unique index exists!")

    }
    if ( i == 1 ) {
        
        // Unique index exists as prefix, also index exists
        coll.ensureIndex( { x : 1 } )
        coll.ensureIndex( { x : 1, num : 1 }, { unique : true } )
        
        try{
            s.adminCommand({ shardcollection : "" + coll, key : { x : 1 } })
        }
        catch(e){
            print(e)
            assert( false, "Should be able to shard non-unique index without unique option.")
        }
        
    }
    if ( i == 2 ) {
        // Non-unique index exists as prefix, also index exists.  No unique index.
        coll.ensureIndex( { x : 1 } )
        coll.ensureIndex( { x : 1, num : 1 } )

        passed = false;
        try{
            s.adminCommand({ shardcollection : "" + coll, key : { x : 1 } })
            passed = true;

        }
        catch( e ){
            print(e)
            assert( !passed, "Should be able to shard collection with no unique index if unique not specified.")
        }
    }
    if ( i == 3 ) {

        // Unique index exists as prefix, also unique index exists
        coll.ensureIndex( { num : 1 }, { unique : true })
        coll.ensureIndex( { num : 1 , x : 1 }, { unique : true } )

        try{
            s.adminCommand({ shardcollection : "" + coll, key : { num : 1 }, unique : true })
        }
        catch( e ){
            print(e)
            assert( false, "Should be able to shard collection with unique prefix index.")
        }

    }
    if ( i == 4 ) {

        // Unique index exists as id, also unique prefix index exists
        coll.ensureIndex( { _id : 1, num : 1 }, { unique : true } )

        try{
            s.adminCommand({ shardcollection : "" + coll, key : { _id : 1 }, unique : true })
        }
        catch( e ){
            print(e)
            assert( false, "Should be able to shard collection with unique id index.")
        }
        
    }
    if ( i == 5 ) {

        // Unique index exists as id, also unique prefix index exists
        coll.ensureIndex( { _id : 1, num : 1 }, { unique : true } )

        try{
            s.adminCommand({ shardcollection : "" + coll, key : { _id : 1, num : 1 }, unique : true })
        }
        catch( e ){
            print(e)
            assert( false, "Should be able to shard collection with unique combination id index.")
        }
        
    }
    if ( i == 6 ) {

        coll.remove({})
        
        // Unique index does not exist, also unique prefix index exists
        coll.ensureIndex( { num : 1, _id : 1 }, { unique : true } )

        try{
            s.adminCommand({ shardcollection : "" + coll, key : { num : 1 }, unique : true })
        }
        catch( e ){
            print(e)
            assert( false, "Should be able to shard collection with no unique index but with a unique prefix index.")
        }
        
        printjson( coll.getIndexes() )
        
        // Make sure the index created is unique!
        assert.eq( 1, coll.getIndexes().filter( function(z) { return friendlyEqual( z.key, { num : 1 } ) && z.unique; } ).length );
        
    }
    if ( i == 7 ) {
        coll.remove({})

        // No index exists

        try{
            assert.eq( coll.find().itcount(), 0 )
            s.adminCommand({ shardcollection : "" + coll, key : { num : 1 } })
        }
        catch( e ){
            print(e)
            assert( false, "Should be able to shard collection with no index on shard key.")
        }
    }
    if ( i == 8 ) {
        coll.remove({})

        // No index exists

        passed = false
        try{
            assert.eq( coll.find().itcount(), 0 )
            s.adminCommand({ shardcollection : "" + coll, key : { num : 1 }, unique : true })
            passed = true
        }
        catch( e ){
            print(e)
        }
        assert( passed, "Should be able to shard collection with unique flag but with no unique index on shard key, if coll empty.")
        
        printjson( coll.getIndexes() )
        
        // Make sure the index created is unique!
        assert.eq( 1, coll.getIndexes().filter( function(z) { return friendlyEqual( z.key, { num : 1 } ) && z.unique; } ).length );
    }
    if ( i == 9 ) {

        // Unique index exists on a different field as well
        coll.ensureIndex( { num : 1 }, { unique : true } )
        coll.ensureIndex( { x : 1 } )

        passed = false
        try {
            s.adminCommand( { shardcollection : "" + coll, key : { x : 1 } } )
            passed = true
        } catch (e) {
            print( e )
        }
        assert( !passed, "Should not shard collection when another unique index exists!" )
    }
    if ( i == 10 ){

        //try sharding non-empty collection without any index
        passed = false;
        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } );
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( !passed , "Should not be able to shard without index");

        //now add containing index and try sharding by prefix
        coll.ensureIndex( {num : 1, x : 1} );

        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } );
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( passed , "Should be able to shard collection with prefix of existing index");

        printjson( coll.getIndexes() );

        //make sure no extra index is created
        assert.eq( 2, coll.getIndexes().length );
    }
    if ( i == 11 ){
        coll.remove({})

        //empty collection with useful index. check new index not created
        coll.ensureIndex( {num : 1, x : 1} );

        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } );
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( passed , "Should be able to shard collection with prefix of existing index");

        printjson( coll.getIndexes() );

        //make sure no extra index is created
        assert.eq( 2, coll.getIndexes().length );
    }
    if ( i == 12 ){

        //check multikey values for x make index unusable for shard key
        coll.save({num : 100 , x : [2,3] });
        coll.ensureIndex( {num : 1, x : 1} );

        passed = false;
        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } );
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( !passed , "Should not be able to shard collection with mulikey index");
    }
    if ( i == 13 ){

        coll.save({ num : [100, 200], x : 10});
        coll.ensureIndex( { num : 1, x : 1} );

        passed = false;
        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } );
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( !passed , "Should not be able to shard collection with mulikey index");

    }
    if ( i == 14 ){

        coll.save({ num : 100, x : 10, y : [1,2]});
        coll.ensureIndex( { num : 1, x : 1, y : 1} );

        passed = false;
        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : 1 } } );
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( !passed , "Should not be able to shard collection with mulikey index");

    }
    if ( i == 15 ) {

        // try sharding with a hashed index
        coll.ensureIndex( { num : "hashed"} );

        try{
            s.adminCommand( { shardcollection : "" + coll, key : { num : "hashed" } } );
        }
        catch( e ){
            print(e);
            assert( false, "Should be able to shard collection with hashed index.");
        }
    }
    if ( i == 16 ) {

        // create hashed index, but try to declare it unique when sharding
        coll.ensureIndex( { num : "hashed"} )

        passed = false;
        try{
            s.adminCommand({ shardcollection : "" + coll, key : { num : "hashed" }, unique : true});
            passed = true;
        }
        catch( e ){
            print(e);
        }
        assert( !passed , "Should not be able to declare hashed shard key unique.");

    }
    if ( i == 17 ) {

        // create hashed index, but unrelated unique index present
        coll.ensureIndex( { x : "hashed" } );
        coll.ensureIndex( { num : 1 }, { unique : true} );

        passed = false;
        try {
            s.adminCommand( { shardcollection : "" + coll, key : { x : "hashed" } } );
            passed = true;
        }
        catch (e) {
            print( e );
        }
        assert( !passed, "Should not be able to shard on hashed index with another unique index" );

    }
    if ( i == 18 ) {

        // create hashed index, and a regular unique index exists on same field
        coll.ensureIndex( { num : "hashed" } );
        coll.ensureIndex( { num : 1 }, { unique : true } );

        try{
            s.adminCommand({ shardcollection : "" + coll, key : { num : "hashed" } } );
        }
        catch( e ){
            print(e);
            assert( false, "Should be able to shard coll with hashed and regular unique index");
        }
    }
}

s.stop();
