TEST(CollectionOptions, NExtentsNumberLimits) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{$nExtents: 'a'}")));
    ASSERT_EQ(options.initialNumExtents, 0);

    ASSERT_OK(options.parse(fromjson("{$nExtents: '-1'}")));
    ASSERT_EQ(options.initialNumExtents, 0);

    ASSERT_OK(options.parse(fromjson("{$nExtents: '-9999999999999999999999999999999999'}")));
    ASSERT_EQ(options.initialNumExtents, 0);

    ASSERT_OK(options.parse(fromjson("{$nExtents: 9999999999999999999999999999999}")));
    ASSERT_EQ(options.initialNumExtents, LLONG_MAX);
}
TEST(CollectionOptions, MaxNumberLimits) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{max: 'a'}")));
    ASSERT_EQ(options.cappedMaxDocs, 0);

    ASSERT_OK(options.parse(fromjson("{max: '-1'}")));
    ASSERT_EQ(options.cappedMaxDocs, 0);

    ASSERT_OK(options.parse(fromjson("{max: '-9999999999999999999999999999999999'}")));
    ASSERT_EQ(options.cappedMaxDocs, 0);

    ASSERT_OK(options.parse(fromjson("{max: 99999999999999999999999999999}")));
    ASSERT_EQ(options.cappedMaxDocs, 0);
}
TEST(CollectionOptions, Validator) {
    CollectionOptions options;

    ASSERT_NOT_OK(options.parse(fromjson("{validator: 'notAnObject'}")));

    ASSERT_OK(options.parse(fromjson("{validator: {a: 1}}")));
    ASSERT_BSONOBJ_EQ(options.validator, fromjson("{a: 1}"));

    options.validator = fromjson("{b: 1}");
    ASSERT_BSONOBJ_EQ(options.toBSON()["validator"].Obj(), fromjson("{b: 1}"));

    CollectionOptions defaultOptions;
    ASSERT_BSONOBJ_EQ(defaultOptions.validator, BSONObj());
    ASSERT(!defaultOptions.toBSON()["validator"]);
}
TEST(CollectionOptions, CollationFieldNotDumpedToBSONWhenOmitted) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{validator: {a: 1}}")));
    ASSERT_TRUE(options.collation.isEmpty());
    BSONObj asBSON = options.toBSON();
    ASSERT_FALSE(asBSON["collation"]);
}
TEST(CollectionOptions, IgnoreMaxWrongType) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{capped: true, size: 1024, max: ''}")));
    ASSERT_EQUALS(options.capped, true);
    ASSERT_EQUALS(options.cappedSize, 1024);
    ASSERT_EQUALS(options.cappedMaxDocs, 0);
}
TEST(CollectionOptions, ResetClearsCollationField) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{collation: {locale: 'en'}}")));
    ASSERT_FALSE(options.collation.isEmpty());
    options.reset();
    ASSERT_TRUE(options.collation.isEmpty());
}
TEST(CollectionOptions, CollationFieldParsesCorrectly) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{collation: {locale: 'en'}}")));
    ASSERT_EQ(options.collation, fromjson("{locale: 'en'}"));
    ASSERT_TRUE(options.isValid());
    ASSERT_OK(options.validate());
}
TEST(CollectionOptions, ParseEngineField) {
    CollectionOptions opts;
    ASSERT_OK(opts.parse(fromjson(
        "{unknownField: 1, "
        "storageEngine: {storageEngine1: {x: 1, y: 2}, storageEngine2: {a: 1, b:2}}}")));
    checkRoundTrip(opts);

    // Unrecognized field should not be present in BSON representation.
    BSONObj obj = opts.toBSON();
    ASSERT_FALSE(obj.hasField("unknownField"));

    // Check "storageEngine" field.
    ASSERT_TRUE(obj.hasField("storageEngine"));
    ASSERT_TRUE(obj.getField("storageEngine").isABSONObj());
    BSONObj storageEngine = obj.getObjectField("storageEngine");

    // Check individual storage storageEngine fields.
    ASSERT_TRUE(storageEngine.getField("storageEngine1").isABSONObj());
    BSONObj storageEngine1 = storageEngine.getObjectField("storageEngine1");
    ASSERT_EQUALS(1, storageEngine1.getIntField("x"));
    ASSERT_EQUALS(2, storageEngine1.getIntField("y"));

    ASSERT_TRUE(storageEngine.getField("storageEngine2").isABSONObj());
    BSONObj storageEngine2 = storageEngine.getObjectField("storageEngine2");
    ASSERT_EQUALS(1, storageEngine2.getIntField("a"));
    ASSERT_EQUALS(2, storageEngine2.getIntField("b"));
}
TEST(CollectionOptions, SizeNumberLimits) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{size: 'a'}")));
    ASSERT_EQ(options.cappedSize, 0);


    ASSERT_OK(options.parse(fromjson("{size: '-1'}")));
    ASSERT_EQ(options.cappedSize, 0);

    ASSERT_OK(options.parse(fromjson("{size: '-9999999999999999999999999999999'}")));
    ASSERT_EQ(options.cappedSize, 0);

    // The test for size is redundant since size returns a status that's not ok if it's larger
    // than a petabyte, which is smaller than LLONG_MAX anyways. We test that here.
    ASSERT_NOT_OK(options.parse(fromjson("{size: 9999999999999999}")));
}
TEST(CollectionOptions, CreateOptionIgnoredIfNotFirst) {
    CollectionOptions options;
    auto status = options.parse(fromjson("{capped: true, create: 1, size: 1024}"));
    ASSERT_OK(status);
    ASSERT_EQ(options.capped, true);
    ASSERT_EQ(options.cappedSize, 1024L);
}
    CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions( OperationContext* txn,
                                                                        const StringData& ns ) const {
        if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) {
            return CollectionOptions();
        }

        RecordStoreV1Base* rs = _getNamespaceRecordStore();
        invariant( rs );

        scoped_ptr<RecordIterator> it( rs->getIterator(txn) );
        while ( !it->isEOF() ) {
            DiskLoc loc = it->getNext();
            BSONObj entry = it->dataFor( loc ).toBson();
            BSONElement name = entry["name"];
            if ( name.type() == String && name.String() == ns ) {
                CollectionOptions options;
                if ( entry["options"].isABSONObj() ) {
                    Status status = options.parse( entry["options"].Obj() );
                    fassert( 18523, status );
                }
                return options;
            }
        }

        return CollectionOptions();
    }
TEST(CollectionOptions, ResetStorageEngineField) {
    CollectionOptions opts;
    ASSERT_OK(opts.parse(fromjson("{storageEngine: {storageEngine1: {x: 1}}}")));
    checkRoundTrip(opts);

    CollectionOptions defaultOpts;
    ASSERT_TRUE(defaultOpts.storageEngine.isEmpty());
}
TEST(CollectionOptions, ParseUUID) {
    CollectionOptions options;
    CollectionUUID uuid = CollectionUUID::gen();

    // Check required parse failures
    ASSERT_FALSE(options.uuid);
    ASSERT_NOT_OK(options.parse(uuid.toBSON()));
    ASSERT_NOT_OK(options.parse(BSON("uuid" << 1)));
    ASSERT_NOT_OK(options.parse(BSON("uuid" << 1), CollectionOptions::parseForStorage));
    ASSERT_FALSE(options.uuid);

    // Check successful parse and roundtrip.
    ASSERT_OK(options.parse(uuid.toBSON(), CollectionOptions::parseForStorage));
    ASSERT(options.uuid.get() == uuid);

    // Check that a collection options containing a UUID passes validation.
    ASSERT_OK(options.validateForStorage());
}
TEST(CollectionOptions, CappedSizeRoundsUpForAlignment) {
    const long long kUnalignedCappedSize = 1000;
    const long long kAlignedCappedSize = 1024;
    CollectionOptions options;

    // Check size rounds up to multiple of alignment.
    ASSERT_OK(options.parse(BSON("capped" << true << "size" << kUnalignedCappedSize)));
    ASSERT_EQUALS(options.capped, true);
    ASSERT_EQUALS(options.cappedSize, kAlignedCappedSize);
    ASSERT_EQUALS(options.cappedMaxDocs, 0);
}
Exemple #15
0
    /** { ..., capped: true, size: ..., max: ... }
     * @param createDefaultIndexes - if false, defers id (and other) index creation.
     * @return true if successful
    */
    Status userCreateNS( OperationContext* txn,
                         Database* db,
                         StringData ns,
                         BSONObj options,
                         bool logForReplication,
                         bool createDefaultIndexes ) {

        invariant( db );

        LOG(1) << "create collection " << ns << ' ' << options;

        if ( !NamespaceString::validCollectionComponent(ns) )
            return Status( ErrorCodes::InvalidNamespace,
                           str::stream() << "invalid ns: " << ns );

        Collection* collection = db->getCollection( ns );

        if ( collection )
            return Status( ErrorCodes::NamespaceExists,
                           "collection already exists" );

        CollectionOptions collectionOptions;
        Status status = collectionOptions.parse(options);
        if ( !status.isOK() )
            return status;

        status = validateStorageOptions(collectionOptions.storageEngine,
                                        &StorageEngine::Factory::validateCollectionStorageOptions);
        if ( !status.isOK() )
            return status;

        invariant( db->createCollection( txn, ns, collectionOptions, true, createDefaultIndexes ) );

        if ( logForReplication ) {
            if ( options.getField( "create" ).eoo() ) {
                BSONObjBuilder b;
                b << "create" << nsToCollectionSubstring( ns );
                b.appendElements( options );
                options = b.obj();
            }
            string logNs = nsToDatabase(ns) + ".$cmd";
            repl::logOp(txn, "c", logNs.c_str(), options);
        }

        return Status::OK();
    }
CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions(OperationContext* txn,
                                                                   RecordId rid) const {
    CollectionOptions options;

    if (rid.isNull()) {
        return options;
    }

    RecordStoreV1Base* rs = _getNamespaceRecordStore();
    invariant(rs);

    RecordData data;
    invariant(rs->findRecord(txn, rid, &data));

    if (data.releaseToBson()["options"].isABSONObj()) {
        Status status = options.parse(data.releaseToBson()["options"].Obj());
        fassert(18523, status);
    }
    return options;
}
TEST(CollectionOptions, ViewParsesCorrectlyWithoutPipeline) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{viewOn: 'c'}")));
    ASSERT_EQ(options.viewOn, "c");
    ASSERT_BSONOBJ_EQ(options.pipeline, BSONObj());
}
TEST(CollectionOptions, CollationFieldParsesCorrectly) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{collation: {locale: 'en'}}")));
    ASSERT_BSONOBJ_EQ(options.collation, fromjson("{locale: 'en'}"));
    ASSERT_OK(options.validateForStorage());
}
TEST(CollectionOptions, ParsedCollationObjShouldBeOwned) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{collation: {locale: 'en'}}")));
    ASSERT_BSONOBJ_EQ(options.collation, fromjson("{locale: 'en'}"));
    ASSERT_TRUE(options.collation.isOwned());
}
TEST(CollectionOptions, CollationFieldLeftEmptyWhenOmitted) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{validator: {a: 1}}")));
    ASSERT_TRUE(options.collation.isEmpty());
}
TEST(CollectionOptions, WriteConcernWhitelistedOptionIgnored) {
    CollectionOptions options;
    auto status = options.parse(fromjson("{writeConcern: 1}"));
    ASSERT_OK(status);
}
TEST(CollectionOptions, MaxTimeMSWhitelistedOptionIgnored) {
    CollectionOptions options;
    auto status = options.parse(fromjson("{maxTimeMS: 1}"));
    ASSERT_OK(status);
}
TEST(CollectionOptions, DuplicateCreateOptionIgnoredIfCreateOptionNotFirst) {
    CollectionOptions options;
    auto status =
        options.parse(BSON("capped" << true << "create" << 1 << "create" << 1 << "size" << 1024));
    ASSERT_OK(status);
}
TEST(CollectionOptions, DuplicateCreateOptionIgnoredIfCreateOptionFirst) {
    CollectionOptions options;
    auto status = options.parse(BSON("create" << 1 << "create" << 1));
    ASSERT_OK(status);
}
TEST(CollectionOptions, UnknownOptionRejectedIfCreateOptionNotPresent) {
    CollectionOptions options;
    auto status = options.parse(fromjson("{invalidOption: 1}"));
    ASSERT_NOT_OK(status);
    ASSERT_EQ(status.code(), ErrorCodes::InvalidOptions);
}
TEST(CollectionOptions, UnknownOptionIgnoredIfCreateOptionPresent) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{invalidOption: 1, create: 1}")));
}
TEST(CollectionOptions, ViewParsesCorrectly) {
    CollectionOptions options;
    ASSERT_OK(options.parse(fromjson("{viewOn: 'c', pipeline: [{$match: {}}]}")));
    ASSERT_EQ(options.viewOn, "c");
    ASSERT_BSONOBJ_EQ(options.pipeline, fromjson("[{$match: {}}]"));
}
TEST(CollectionOptions, CreateOptionIgnoredIfFirst) {
    CollectionOptions options;
    auto status = options.parse(fromjson("{create: 1}"));
    ASSERT_OK(status);
}
TEST(CollectionOptions, UnknownTopLevelOptionFailsToParse) {
    CollectionOptions options;
    auto status = options.parse(fromjson("{invalidOption: 1}"));
    ASSERT_NOT_OK(status);
    ASSERT_EQ(status.code(), ErrorCodes::InvalidOptions);
}
TEST(CollectionOptions, PipelineFieldRequiresViewOn) {
    CollectionOptions options;
    ASSERT_NOT_OK(options.parse(fromjson("{pipeline: [{$match: {}}]}")));
}