// Tests that updates can't change immutable fields (used in sharded system)
var st = new ShardingTest({shards : 2,
                           mongos : 1,
                           verbose : 0,
                           other : {separateConfig : 1}})
st.stopBalancer();

var mongos = st.s;
var config = mongos.getDB("config");
var coll = mongos.getCollection(jsTestName() + ".coll1");
var shard0 = st.shard0;

printjson(config.adminCommand({enableSharding : coll.getDB() + ""}))
printjson(config.adminCommand({shardCollection : "" + coll, key : {a : 1}}))

var getDirectShardedConn = function( st, collName ) {

    var shardConnWithVersion = new Mongo( st.shard0.host );

    var mockServerId = new ObjectId();
    var configConnStr = st._configDB;

    var maxChunk = st.s0.getCollection( "config.chunks" )
                   .find({ ns : collName }).sort({ lastmod : -1 }).next();
    
    var ssvInitCmd = { setShardVersion : collName, 
                       configdb : configConnStr, 
                       serverID : mockServerId,
                       version : maxChunk.lastmod,
                       versionEpoch : maxChunk.lastmodEpoch };
    
    printjson( ssvInitCmd );

    assert.commandWorked( shardConnWithVersion.getDB( "admin" ).runCommand( ssvInitCmd ) );
    
    return shardConnWithVersion;
}

var shard0Coll = getDirectShardedConn(st, coll.getFullName()).getCollection(coll.getFullName());

// No shard key
shard0Coll.remove({})
assert.writeError(shard0Coll.save({ _id: 3 }));

// Full shard key in save
assert.writeOK(shard0Coll.save({ _id: 1, a: 1 }));

// Full shard key on replacement (basically the same as above)
shard0Coll.remove({})
assert.writeOK(shard0Coll.update({ _id: 1 }, { a: 1 }, true));

// Full shard key after $set
shard0Coll.remove({})
assert.writeOK(shard0Coll.update({ _id: 1 }, { $set: { a: 1 }}, true));

// Update existing doc (replacement), same shard key value
assert.writeOK(shard0Coll.update({ _id: 1 }, { a: 1 }));

//Update existing doc ($set), same shard key value
assert.writeOK(shard0Coll.update({ _id: 1 }, { $set: { a: 1 }}));

// Error due to mutating the shard key (replacement)
assert.writeError(shard0Coll.update({ _id: 1 }, { b: 1 }));

// Error due to mutating the shard key ($set)
assert.writeError(shard0Coll.update({ _id: 1 }, { $unset: { a: 1 }}));

// Error due to removing all the embedded fields.
shard0Coll.remove({})

assert.writeOK(shard0Coll.save({ _id: 2, a: { c: 1, b: 1 }}));

assert.writeError(shard0Coll.update({}, { $unset: { "a.c": 1 }}));
assert.writeError(shard0Coll.update({}, { $unset: { "a.b": 1, "a.c": 1 }}));

jsTest.log("DONE!"); // distinguishes shutdown failures
st.stop();
