bool Balancer::_shouldIBalance( DBClientBase& conn ){ BSONObj x = conn.findOne( ShardNS::settings , BSON( "_id" << "balancer" ) ); log(2) << "balancer: " << x << endl; if ( ! x.isEmpty() ){ if ( x["who"].String() == _myid ){ log(2) << "balancer: i'm the current balancer" << endl; return true; } BSONObj other = conn.findOne( ShardNS::mongos , x["who"].wrap( "_id" ) ); massert( 13125 , (string)"can't find mongos: " + x["who"].String() , ! other.isEmpty() ); int secsSincePing = (int)(( jsTime() - other["ping"].Date() ) / 1000 ); log(2) << "current balancer is: " << other << " ping delay(secs): " << secsSincePing << endl; if ( secsSincePing < ( 60 * 10 ) ){ return false; } log() << "balancer: going to take over" << endl; // we want to take over, so fall through to below } // Taking over means replacing 'who' with this balancer's address. Note that // to avoid any races, we use a compare-and-set strategy relying on the // incarnation of the previous balancer (the key 'x'). OID incarnation; incarnation.init(); BSONObjBuilder updateQuery; updateQuery.append( "_id" , "balancer" ); if ( x["x"].type() ) updateQuery.append( x["x"] ); else updateQuery.append( "x" , BSON( "$exists" << false ) ); conn.update( ShardNS::settings , updateQuery.obj() , BSON( "$set" << BSON( "who" << _myid << "x" << incarnation ) ) , true ); // If another balancer beats this one to the punch, the following query will see // the incarnation for that other guy. x = conn.findOne( ShardNS::settings , BSON( "_id" << "balancer" ) ); log() << "balancer: after update: " << x << endl; return _myid == x["who"].String() && incarnation == x["x"].OID(); }
/* **************************************************************************** * * mongoUpdateCsubNewNotification_fail - */ TEST(mongoOntimeintervalOperations, mongoUpdateCsubNewNotification_fail) { HttpStatusCode ms; /* Prepare mocks */ TimerMock* timerMock = new TimerMock(); ON_CALL(*timerMock, getCurrentTime()) .WillByDefault(Return(1360232700)); setTimer(timerMock); /* Forge the parameters */ std::string subId = "51307b66f481db11bf869999"; std::string err; /* Prepare database */ prepareDatabase(); /* Do operation */ ms = mongoUpdateCsubNewNotification(subId, &err); /* Check results */ EXPECT_EQ(SccOk, ms); /* Check that database is as expected (untouched) */ DBClientBase* connection = getMongoConnection(); BSONObj sub1 = connection->findOne(SUBSCRIBECONTEXT_COLL, BSON("_id" << OID("51307b66f481db11bf860001"))); BSONObj sub2 = connection->findOne(SUBSCRIBECONTEXT_COLL, BSON("_id" << OID("51307b66f481db11bf860002"))); EXPECT_EQ(20000000, sub1.getIntField("lastNotification")); EXPECT_EQ(20, sub1.getIntField("count")); EXPECT_EQ(30000000, sub2.getIntField("lastNotification")); EXPECT_EQ(30, sub2.getIntField("count")); /* Release mocks */ delete timerMock; }
/* **************************************************************************** * * collectionFindOne - */ extern bool collectionFindOne ( const std::string& col, const BSONObj& q, BSONObj* doc, std::string* err ) { TIME_STAT_MONGO_READ_WAIT_START(); DBClientBase* connection = getMongoConnection(); if (connection == NULL) { TIME_STAT_MONGO_READ_WAIT_STOP(); LM_E(("Fatal Error (null DB connection)")); *err = "null DB connection"; return false; } LM_T(LmtMongo, ("findOne() in '%s' collection: '%s'", col.c_str(), q.toString().c_str())); try { *doc = connection->findOne(col.c_str(), q); releaseMongoConnection(connection); TIME_STAT_MONGO_READ_WAIT_STOP(); LM_I(("Database Operation Successful (findOne: %s)", q.toString().c_str())); } catch (const std::exception &e) { releaseMongoConnection(connection); TIME_STAT_MONGO_READ_WAIT_STOP(); std::string msg = std::string("collection: ") + col.c_str() + " - findOne(): " + q.toString() + " - exception: " + e.what(); *err = "Database Error (" + msg + ")"; LM_E((err->c_str())); return false; } catch (...) { releaseMongoConnection(connection); TIME_STAT_MONGO_READ_WAIT_STOP(); std::string msg = std::string("collection: ") + col.c_str() + " - findOne(): " + q.toString() + " - exception: generic"; *err = "Database Error (" + msg + ")"; LM_E((err->c_str())); return false; } return true; }
/* **************************************************************************** * * mongoUpdateCsubNewNotification_dbfail - */ TEST(mongoOntimeintervalOperations, mongoUpdateCsubNewNotification_dbfail) { HttpStatusCode ms; /* Prepare mock */ const DBException e = DBException("boom!!", 33); DBClientConnectionMock* connectionMock = new DBClientConnectionMock(); ON_CALL(*connectionMock, update("utest.csubs",_,_,_,_,_)) .WillByDefault(Throw(e)); TimerMock* timerMock = new TimerMock(); ON_CALL(*timerMock, getCurrentTime()) .WillByDefault(Return(1360232700)); setTimer(timerMock); /* Forge the parameters */ std::string subId = "51307b66f481db11bf860001"; std::string err; /* Set MongoDB connection (prepare database first with the "actual" connection object) * Note that we preserve the "actual" connection for future database checking */ prepareDatabase(); DBClientBase* connectionDb = getMongoConnection(); setMongoConnectionForUnitTest(connectionMock); /* Do operation */ ms = mongoUpdateCsubNewNotification(subId, &err); /* Check results */ EXPECT_EQ(SccReceiverInternalError, ms); EXPECT_EQ("Database Error (collection: utest.csubs " "- update(): <{ _id: ObjectId('51307b66f481db11bf860001') },{ $set: { lastNotification: 1360232700 }, $inc: { count: 1 } }> " "- exception: boom!!)", err); /* Check that database is as expected (untouched) */ // Sleeping a little to "give mongod time to process its input". usleep(1000); BSONObj sub1 = connectionDb->findOne(SUBSCRIBECONTEXT_COLL, BSON("_id" << OID("51307b66f481db11bf860001"))); BSONObj sub2 = connectionDb->findOne(SUBSCRIBECONTEXT_COLL, BSON("_id" << OID("51307b66f481db11bf860002"))); EXPECT_EQ(20000000, sub1.getIntField("lastNotification")); EXPECT_EQ(20, sub1.getIntField("count")); EXPECT_EQ(30000000, sub2.getIntField("lastNotification")); EXPECT_EQ(30, sub2.getIntField("count")); /* Restore real DB connection */ setMongoConnectionForUnitTest(connectionDb); /* Release mocks */ delete timerMock; delete connectionMock; }
/* **************************************************************************** * * mongoGetFwdRegId - */ std::string mongoGetFwdRegId(const std::string& regId, const std::string& tenant) { DBClientBase* connection = NULL; std::string retVal = ""; bool reqSemTaken = false; reqSemTake(__FUNCTION__, "Mongo Get Forward RegId", SemReadOp, &reqSemTaken); LM_T(LmtMongo, ("Mongo Get Forward RegId")); try { LM_T(LmtMongo, ("findOne() in '%s' collection doc _id '%s'", getRegistrationsCollectionName(tenant).c_str(), regId.c_str())); BSONObj doc; connection = getMongoConnection(); doc = connection->findOne(getRegistrationsCollectionName(tenant).c_str(), BSON("_id" << OID(regId))); releaseMongoConnection(connection); LM_T(LmtMongo, ("reg doc: '%s'", doc.toString().c_str())); retVal = STR_FIELD(doc, REG_FWS_REGID); LM_I(("Database Operation Successful (findOne _id: %s)", regId.c_str())); } catch (const DBException &e) { // // FIXME: probably we can do something apart from printing the error, but currently // we haven't a use case for that // releaseMongoConnection(connection); LM_E(("Database Error ('findOne tenant=%s, id=%s', '%s')", tenant.c_str(), regId.c_str(), e.what())); } catch (...) { // // FIXME: probably we can do something apart from printing the error, but currently // we haven't a use case for that // releaseMongoConnection(connection); LM_E(("Database Error ('findOne tenant=%s, id=%s', 'generic exception')", tenant.c_str(), regId.c_str())); } reqSemGive(__FUNCTION__, "Mongo Get Forward RegId", reqSemTaken); return retVal; }
/* **************************************************************************** * * unsubscribe - */ TEST(mongoUnsubscribeContext, unsubscribe) { HttpStatusCode ms; UnsubscribeContextRequest req; UnsubscribeContextResponse res; /* Prepare mock */ NotifierMock* notifierMock = new NotifierMock(); EXPECT_CALL(*notifierMock, destroyOntimeIntervalThreads("51307b66f481db11bf860001")) .Times(1); EXPECT_CALL(*notifierMock, sendNotifyContextRequest(_,_,_,_)) .Times(0); EXPECT_CALL(*notifierMock, createIntervalThread(_,_,_)) .Times(0); setNotifier(notifierMock); /* Forge the request (from "inside" to "outside") */ req.subscriptionId.set("51307b66f481db11bf860001"); /* Prepare database */ prepareDatabase(); /* Invoke the function in mongoBackend library */ ms = mongoUnsubscribeContext(&req, &res); /* Check response is as expected */ EXPECT_EQ(SccOk, ms); EXPECT_EQ("51307b66f481db11bf860001", res.subscriptionId.get()); EXPECT_EQ(SccOk, res.statusCode.code); EXPECT_EQ("OK", res.statusCode.reasonPhrase); EXPECT_EQ(0, res.statusCode.details.size()); /* Check database (one document, but not the deleted one) */ DBClientBase* connection = getMongoConnection(); ASSERT_EQ(1, connection->count(SUBSCRIBECONTEXT_COLL, BSONObj())); BSONObj sub = connection->findOne(SUBSCRIBECONTEXT_COLL, BSON("_id" << OID("51307b66f481db11bf860002"))); EXPECT_EQ("51307b66f481db11bf860002", sub.getField("_id").OID().str()); /* Release connection */ mongoDisconnect(); /* Release mock */ delete notifierMock; }
/* **************************************************************************** * * mongoUnsubscribeContext - */ HttpStatusCode mongoUnsubscribeContext(UnsubscribeContextRequest* requestP, UnsubscribeContextResponse* responseP, const std::string& tenant) { bool reqSemTaken; BSONObj sub; DBClientBase* connection = NULL; reqSemTake(__FUNCTION__, "ngsi10 unsubscribe request", SemWriteOp, &reqSemTaken); LM_T(LmtMongo, ("Unsubscribe Context")); /* No matter if success or failure, the subscriptionId in the response is always the one * in the request */ responseP->subscriptionId = requestP->subscriptionId; if (responseP->subscriptionId.get() == "") { responseP->statusCode.fill(SccContextElementNotFound); LM_W(("Bad Input (no subscriptionId)")); return SccOk; } LM_T(LmtMongo, ("findOne() in '%s' collection _id '%s'}", getSubscribeContextCollectionName(tenant).c_str(), requestP->subscriptionId.get().c_str())); /* Look for document */ connection = getMongoConnection(); try { OID id = OID(requestP->subscriptionId.get()); sub = connection->findOne(getSubscribeContextCollectionName(tenant).c_str(), BSON("_id" << id)); releaseMongoConnection(connection); LM_I(("Database Operation Successful (findOne _id: %s)", id.toString().c_str())); } catch (const AssertionException &e) { releaseMongoConnection(connection); reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request (mongo assertion exception)", reqSemTaken); // // This happens when OID format is wrong // FIXME: this checking should be done at parsing stage, without progressing to // mongoBackend. By the moment we can live this here, but we should remove in the future // (old issue #95) // responseP->statusCode.fill(SccContextElementNotFound); LM_W(("Bad Input (invalid OID format)")); return SccOk; } catch (const DBException &e) { releaseMongoConnection(connection); reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request (mongo db exception)", reqSemTaken); responseP->statusCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - findOne() _id: " + requestP->subscriptionId.get() + " - exception: " + e.what()); LM_E(("Database Error (%s)", responseP->statusCode.details.c_str())); return SccOk; } catch (...) { releaseMongoConnection(connection); reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request (mongo generic exception)", reqSemTaken); responseP->statusCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - findOne() _id: " + requestP->subscriptionId.get() + " - exception: " + "generic"); LM_E(("Database Error (%s)", responseP->statusCode.details.c_str())); return SccOk; } if (sub.isEmpty()) { reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request (no subscriptions found)", reqSemTaken); responseP->statusCode.fill(SccContextElementNotFound, std::string("subscriptionId: /") + requestP->subscriptionId.get() + "/"); return SccOk; } /* Remove document in MongoDB */ // FIXME: I will prefer to do the find and remove in a single operation. Is the some similar // to findAndModify for this? LM_T(LmtMongo, ("remove() in '%s' collection _id '%s'}", getSubscribeContextCollectionName(tenant).c_str(), requestP->subscriptionId.get().c_str())); connection = getMongoConnection(); try { connection->remove(getSubscribeContextCollectionName(tenant).c_str(), BSON("_id" << OID(requestP->subscriptionId.get()))); releaseMongoConnection(connection); LM_I(("Database Operation Successful (remove _id: %s)", requestP->subscriptionId.get().c_str())); } catch (const DBException &e) { releaseMongoConnection(connection); reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request (mongo db exception)", reqSemTaken); responseP->statusCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - remove() _id: " + requestP->subscriptionId.get().c_str() + " - exception: " + e.what()); LM_E(("Database Error (%s)", responseP->statusCode.details.c_str())); return SccOk; } catch (...) { releaseMongoConnection(connection); reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request (mongo generic exception)", reqSemTaken); responseP->statusCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - remove() _id: " + requestP->subscriptionId.get().c_str() + " - exception: " + "generic"); LM_E(("Database Error (%s)", responseP->statusCode.details.c_str())); return SccOk; } /* Destroy any previous ONTIMEINTERVAL thread */ getNotifier()->destroyOntimeIntervalThreads(requestP->subscriptionId.get()); responseP->statusCode.fill(SccOk); reqSemGive(__FUNCTION__, "ngsi10 unsubscribe request", reqSemTaken); // // Removing subscription from cache // subCache->remove(tenant, "", requestP->subscriptionId.get()); return SccOk; }
/* **************************************************************************** * * mongoUpdateContextSubscription - */ HttpStatusCode mongoUpdateContextSubscription(UpdateContextSubscriptionRequest* requestP, UpdateContextSubscriptionResponse* responseP, Format inFormat, const std::string& tenant) { reqSemTake(__FUNCTION__, "ngsi10 update subscription request"); LM_T(LmtMongo, ("Update Context Subscription")); DBClientBase* connection = getMongoConnection(); /* Look for document */ BSONObj sub; try { OID id = OID(requestP->subscriptionId.get()); mongoSemTake(__FUNCTION__, "findOne in SubscribeContextCollection"); sub = connection->findOne(getSubscribeContextCollectionName(tenant).c_str(), BSON("_id" << id)); mongoSemGive(__FUNCTION__, "findOne in SubscribeContextCollection"); LM_I(("Database Operation Successful (findOne _id: %s)", id.toString().c_str())); } catch (const AssertionException &e) { /* This happens when OID format is wrong */ // FIXME P4: this checking should be done at the parsing stage, without progressing to // mongoBackend. For the moment we can leave this here, but we should remove it in the future // (old issue #95) mongoSemGive(__FUNCTION__, "findOne in SubscribeContextCollection (mongo assertion exception)"); reqSemGive(__FUNCTION__, "ngsi10 update subscription request (mongo assertion exception)"); responseP->subscribeError.errorCode.fill(SccContextElementNotFound); LM_W(("Bad Input (invalid OID format)")); return SccOk; } catch (const DBException &e) { mongoSemGive(__FUNCTION__, "findOne in SubscribeContextCollection (mongo db exception)"); reqSemGive(__FUNCTION__, "ngsi10 update subscription request (mongo db exception)"); responseP->subscribeError.errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - findOne() _id: " + requestP->subscriptionId.get() + " - exception: " + e.what()); LM_E(("Database Error (%s)", responseP->subscribeError.errorCode.details.c_str())); return SccOk; } catch (...) { mongoSemGive(__FUNCTION__, "findOne in SubscribeContextCollection (mongo generic exception)"); reqSemGive(__FUNCTION__, "ngsi10 update subscription request (mongo generic exception)"); responseP->subscribeError.errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - findOne() _id: " + requestP->subscriptionId.get() + " - exception: " + "generic"); LM_E(("Database Error (%s)", responseP->subscribeError.errorCode.details.c_str())); return SccOk; } if (sub.isEmpty()) { responseP->subscribeError.errorCode.fill(SccContextElementNotFound); reqSemGive(__FUNCTION__, "ngsi10 update subscription request (no subscriptions found)"); return SccOk; } /* We start with an empty BSONObjBuilder and process requestP for all the fields that can * be updated. I don't like too much this strategy (I would have preferred to start with * a copy of the original document, then modify as neded, but this doesn't seem to be easy * using the API provide by the Mongo C++ driver) * * FIXME: a better implementation strategy could be doing an findAndModify() query to do the * update, so detecting if the document was not found, instead of using findOne() + update() * with $set operation. One operations to MongoDb. vs two operations. */ BSONObjBuilder newSub; /* Entities, attribute list and reference are not updatable, so they are appended directly */ newSub.appendArray(CSUB_ENTITIES, sub.getField(CSUB_ENTITIES).Obj()); newSub.appendArray(CSUB_ATTRS, sub.getField(CSUB_ATTRS).Obj()); newSub.append(CSUB_REFERENCE, STR_FIELD(sub, CSUB_REFERENCE)); /* Duration update */ if (requestP->duration.isEmpty()) { newSub.append(CSUB_EXPIRATION, sub.getField(CSUB_EXPIRATION).numberLong()); } else { long long expiration = getCurrentTime() + requestP->duration.parse(); newSub.append(CSUB_EXPIRATION, expiration); LM_T(LmtMongo, ("New subscription expiration: %l", expiration)); } /* Restriction update */ // FIXME: Restrictions not implemented yet /* Throttling update */ if (!requestP->throttling.isEmpty()) { /* Throttling equal to 0 removes throttling */ long long throttling = requestP->throttling.parse(); if (throttling != 0) { newSub.append(CSUB_THROTTLING, throttling); } } else { /* The hasField check is needed due to Throttling could not be present in the original doc */ if (sub.hasField(CSUB_THROTTLING)) { newSub.append(CSUB_THROTTLING, sub.getField(CSUB_THROTTLING).numberLong()); } } /* Notify conditions */ bool notificationDone = false; if (requestP->notifyConditionVector.size() == 0) { newSub.appendArray(CSUB_CONDITIONS, sub.getField(CSUB_CONDITIONS).embeddedObject()); } else { /* Destroy any previous ONTIMEINTERVAL thread */ getNotifier()->destroyOntimeIntervalThreads(requestP->subscriptionId.get()); /* Build conditions array (including side-effect notifications and threads creation) * In order to do so, we have to create and EntityIdVector and AttributeList from sub * document, given the processConditionVector() signature */ EntityIdVector enV = subToEntityIdVector(sub); AttributeList attrL = subToAttributeList(sub); BSONArray conds = processConditionVector(&requestP->notifyConditionVector, enV, attrL, requestP->subscriptionId.get(), C_STR_FIELD(sub, CSUB_REFERENCE), ¬ificationDone, inFormat, tenant); newSub.appendArray(CSUB_CONDITIONS, conds); /* Remove EntityIdVector and AttributeList dynamic memory */ enV.release(); attrL.release(); } int count = sub.hasField(CSUB_COUNT) ? sub.getIntField(CSUB_COUNT) : 0; /* Last notification */ if (notificationDone) { newSub.append(CSUB_LASTNOTIFICATION, getCurrentTime()); newSub.append(CSUB_COUNT, count + 1); } else { /* The hasField check is needed due to lastNotification/count could not be present in the original doc */ if (sub.hasField(CSUB_LASTNOTIFICATION)) { newSub.append(CSUB_LASTNOTIFICATION, sub.getIntField(CSUB_LASTNOTIFICATION)); } if (sub.hasField(CSUB_COUNT)) { newSub.append(CSUB_COUNT, count); } } /* Adding format to use in notifications */ newSub.append(CSUB_FORMAT, std::string(formatToString(inFormat))); /* Update document in MongoDB */ BSONObj update = newSub.obj(); try { LM_T(LmtMongo, ("update() in '%s' collection _id '%s': %s}", getSubscribeContextCollectionName(tenant).c_str(), requestP->subscriptionId.get().c_str(), update.toString().c_str())); mongoSemTake(__FUNCTION__, "update in SubscribeContextCollection"); connection->update(getSubscribeContextCollectionName(tenant).c_str(), BSON("_id" << OID(requestP->subscriptionId.get())), update); mongoSemGive(__FUNCTION__, "update in SubscribeContextCollection"); LM_I(("Database Operation Successful (update _id: %s, %s)", requestP->subscriptionId.get().c_str(), update.toString().c_str())); } catch (const DBException &e) { mongoSemGive(__FUNCTION__, "update in SubscribeContextCollection (mongo db exception)"); reqSemGive(__FUNCTION__, "ngsi10 update subscription request (mongo db exception)"); responseP->subscribeError.errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - update() _id: " + requestP->subscriptionId.get().c_str() + " - update() doc: " + update.toString() + " - exception: " + e.what()); LM_E(("Database Error (%s)", responseP->subscribeError.errorCode.details.c_str())); return SccOk; } catch (...) { mongoSemGive(__FUNCTION__, "update in SubscribeContextCollection (mongo generic exception)"); reqSemGive(__FUNCTION__, "ngsi10 update subscription request (mongo generic exception)"); responseP->subscribeError.errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getSubscribeContextCollectionName(tenant).c_str() + " - update() _id: " + requestP->subscriptionId.get().c_str() + " - update() doc: " + update.toString() + " - exception: " + "generic"); LM_E(("Database Error (%s)", responseP->subscribeError.errorCode.details.c_str())); return SccOk; } /* Duration and throttling are optional parameters, they are only added in the case they * was used for update */ if (!requestP->duration.isEmpty()) { responseP->subscribeResponse.duration = requestP->duration; } if (!requestP->throttling.isEmpty()) { responseP->subscribeResponse.throttling = requestP->throttling; } responseP->subscribeResponse.subscriptionId = requestP->subscriptionId; reqSemGive(__FUNCTION__, "ngsi10 update subscription request"); return SccOk; }
/* **************************************************************************** * * createEntity - */ TEST(mongoNotifyContextRequest, createEntity) { HttpStatusCode ms; NotifyContextRequest req; NotifyContextResponse res; /* Prepare database */ prepareDatabase(); /* Forge the request */ ContextElementResponse cer; req.subscriptionId.set("51307b66f481db11bf860001"); req.originator.set("localhost"); cer.contextElement.entityId.fill("E10", "T10", "false"); ContextAttribute ca("A1", "TA1", "new_val"); cer.contextElement.contextAttributeVector.push_back(&ca); cer.statusCode.fill(SccOk); req.contextElementResponseVector.push_back(&cer); /* Prepare mock */ TimerMock* timerMock = new TimerMock(); ON_CALL(*timerMock, getCurrentTime()) .WillByDefault(Return(1360232700)); setTimer(timerMock); /* Invoke the function in mongoBackend library */ ms = mongoNotifyContext(&req, &res); /* Check response is as expected */ EXPECT_EQ(SccOk, ms); EXPECT_EQ(SccOk, res.responseCode.code); EXPECT_EQ("OK", res.responseCode.reasonPhrase); EXPECT_EQ(0, res.responseCode.details.size()); /* Check that every involved collection at MongoDB is as expected */ /* Note we are using EXPECT_STREQ() for some cases, as Mongo Driver returns const char*, not string * objects (see http://code.google.com/p/googletest/wiki/Primer#String_Comparison) */ DBClientBase* connection = getMongoConnection(); /* entities collection */ BSONObj ent; std::vector<BSONElement> attrs; ASSERT_EQ(6, connection->count(ENTITIES_COLL, BSONObj())); ent = connection->findOne(ENTITIES_COLL, BSON("_id.id" << "E1" << "_id.type" << "T1")); EXPECT_STREQ("E1", C_STR_FIELD(ent.getObjectField("_id"), "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent.getObjectField("_id"), "type")); EXPECT_FALSE(ent.hasField("modDate")); attrs = ent.getField("attrs").Array(); ASSERT_EQ(2, attrs.size()); BSONObj a1 = getAttr(attrs, "A1", "TA1"); BSONObj a2 = getAttr(attrs, "A2", "TA2"); EXPECT_STREQ("A1", C_STR_FIELD(a1, "name")); EXPECT_STREQ("TA1",C_STR_FIELD(a1, "type")); EXPECT_STREQ("val1", C_STR_FIELD(a1, "value")); EXPECT_FALSE(a1.hasField("modDate")); EXPECT_STREQ("A2", C_STR_FIELD(a2, "name")); EXPECT_STREQ("TA2", C_STR_FIELD(a2, "type")); EXPECT_FALSE(a2.hasField("value")); EXPECT_FALSE(a2.hasField("modDate")); ent = connection->findOne(ENTITIES_COLL, BSON("_id.id" << "E2" << "_id.type" << "T2")); EXPECT_STREQ("E2", C_STR_FIELD(ent.getObjectField("_id"), "id")); EXPECT_STREQ("T2", C_STR_FIELD(ent.getObjectField("_id"), "type")); EXPECT_FALSE(ent.hasField("modDate")); attrs = ent.getField("attrs").Array(); ASSERT_EQ(2, attrs.size()); BSONObj a3 = getAttr(attrs, "A3", "TA3"); BSONObj a4 = getAttr(attrs, "A4", "TA4"); EXPECT_STREQ("A3", C_STR_FIELD(a3, "name")); EXPECT_STREQ("TA3", C_STR_FIELD(a3, "type")); EXPECT_STREQ("val3", C_STR_FIELD(a3, "value")); EXPECT_FALSE(a3.hasField("modDate")); EXPECT_STREQ("A4", C_STR_FIELD(a4, "name")); EXPECT_STREQ("TA4", C_STR_FIELD(a4, "type")); EXPECT_FALSE(a4.hasField("value")); EXPECT_FALSE(a4.hasField("modDate")); ent = connection->findOne(ENTITIES_COLL, BSON("_id.id" << "E3" << "_id.type" << "T3")); EXPECT_STREQ("E3", C_STR_FIELD(ent.getObjectField("_id"), "id")); EXPECT_STREQ("T3", C_STR_FIELD(ent.getObjectField("_id"), "type")); EXPECT_FALSE(ent.hasField("modDate")); attrs = ent.getField("attrs").Array(); ASSERT_EQ(2, attrs.size()); BSONObj a5 = getAttr(attrs, "A5", "TA5"); BSONObj a6 = getAttr(attrs, "A6", "TA6"); EXPECT_STREQ("A5", C_STR_FIELD(a5, "name")); EXPECT_STREQ("TA5", C_STR_FIELD(a5, "type")); EXPECT_STREQ("val5", C_STR_FIELD(a5, "value")); EXPECT_FALSE(a5.hasField("modDate")); EXPECT_STREQ("A6", C_STR_FIELD(a6, "name")); EXPECT_STREQ("TA6", C_STR_FIELD(a6, "type")); EXPECT_FALSE(a6.hasField("value")); EXPECT_FALSE(a6.hasField("modDate")); ent = connection->findOne(ENTITIES_COLL, BSON("_id.id" << "E1" << "_id.type" << "T1bis")); EXPECT_STREQ("E1", C_STR_FIELD(ent.getObjectField("_id"), "id")); EXPECT_STREQ("T1bis", C_STR_FIELD(ent.getObjectField("_id"), "type")); EXPECT_FALSE(ent.hasField("modDate")); attrs = ent.getField("attrs").Array(); ASSERT_EQ(1, attrs.size()); a1 = getAttr(attrs, "A1", "TA1"); EXPECT_STREQ("A1", C_STR_FIELD(a1, "name")); EXPECT_STREQ("TA1",C_STR_FIELD(a1, "type")); EXPECT_STREQ("val1bis2", C_STR_FIELD(a1, "value")); EXPECT_FALSE(a1.hasField("modDate")); ent = connection->findOne(ENTITIES_COLL, BSON("_id.id" << "E10" << "_id.type" << "T10")); EXPECT_STREQ("E10", C_STR_FIELD(ent.getObjectField("_id"), "id")); EXPECT_STREQ("T10", C_STR_FIELD(ent.getObjectField("_id"), "type")); EXPECT_TRUE(ent.hasField("creDate")); EXPECT_TRUE(ent.hasField("modDate")); attrs = ent.getField("attrs").Array(); ASSERT_EQ(1, attrs.size()); a1 = getAttr(attrs, "A1", "TA1"); EXPECT_STREQ("A1", C_STR_FIELD(a1, "name")); EXPECT_STREQ("TA1",C_STR_FIELD(a1, "type")); EXPECT_STREQ("new_val", C_STR_FIELD(a1, "value")); EXPECT_TRUE(a1.hasField("creDate")); EXPECT_TRUE(a1.hasField("modDate")); /* Note "_id.type: {$exists: false}" is a way for querying for entities without type */ ent = connection->findOne(ENTITIES_COLL, BSON("_id.id" << "E1" << "_id.type" << BSON("$exists" << false))); EXPECT_STREQ("E1", C_STR_FIELD(ent.getObjectField("_id"), "id")); EXPECT_FALSE(ent.getObjectField("_id").hasField("type")); EXPECT_FALSE(ent.hasField("modDate")); attrs = ent.getField("attrs").Array(); ASSERT_EQ(2, attrs.size()); a1 = getAttr(attrs, "A1", "TA1"); a2 = getAttr(attrs, "A2", "TA2"); EXPECT_STREQ("A1", C_STR_FIELD(a1, "name")); EXPECT_STREQ("TA1",C_STR_FIELD(a1, "type")); EXPECT_STREQ("val1-nt", C_STR_FIELD(a1, "value")); EXPECT_FALSE(a1.hasField("modDate")); EXPECT_STREQ("A2", C_STR_FIELD(a2, "name")); EXPECT_STREQ("TA2", C_STR_FIELD(a2, "type")); EXPECT_FALSE(a2.hasField("value")); EXPECT_FALSE(a2.hasField("modDate")); /* Release connection */ mongoDisconnect(); /* Release mock */ delete timerMock; }
/* **************************************************************************** * * MongoDbFindOneFail - */ TEST(mongoRegisterContext_update, MongoDbFindOneFail) { HttpStatusCode ms; RegisterContextRequest req; RegisterContextResponse res; utInit(); /* Prepare mock */ const DBException e = DBException("boom!!", 33); DBClientConnectionMock* connectionMock = new DBClientConnectionMock(); ON_CALL(*connectionMock, findOne("utest.registrations",_,_,_)) .WillByDefault(Throw(e)); /* Forge the request (from "inside" to "outside") */ EntityId en("E1", "T1"); ContextRegistrationAttribute cra("A1", "TA1", "true"); ContextRegistration cr; cr.entityIdVector.push_back(&en); cr.contextRegistrationAttributeVector.push_back(&cra); cr.providingApplication.set("http://newurl.com"); req.contextRegistrationVector.push_back(&cr); req.registrationId.set("51307b66f481db11bf860001"); req.duration.set("PT1M"); /* Prepare database */ prepareDatabase(); /* Set MongoDB connection mock (preserving "actual" connection for later use) */ DBClientBase* connectionDb = getMongoConnection(); setMongoConnectionForUnitTest(connectionMock); /* Invoke the function in mongoBackend library */ ms = mongoRegisterContext(&req, &res, uriParams); /* Check response is as expected */ EXPECT_EQ(SccOk, ms); EXPECT_TRUE(res.duration.isEmpty()); EXPECT_TRUE(res.registrationId.isEmpty()); EXPECT_EQ(SccReceiverInternalError, res.errorCode.code); EXPECT_EQ("Internal Server Error", res.errorCode.reasonPhrase); EXPECT_EQ("Database Error (collection: utest.registrations " "- findOne(): { _id: ObjectId('51307b66f481db11bf860001'), servicePath: \"/\" } " "- exception: boom!!)", res.errorCode.details); /* Restore real DB connection */ setMongoConnectionForUnitTest(connectionDb); /* Release mock */ delete connectionMock; /* Check that every involved collection at MongoDB is as expected */ /* Note we are using EXPECT_STREQ() for some cases, as Mongo Driver returns const char*, not string * objects (see http://code.google.com/p/googletest/wiki/Primer#String_Comparison) */ /* registrations collection: */ ASSERT_EQ(2, connectionDb->count(REGISTRATIONS_COLL, BSONObj())); BSONObj reg, contextRegistration, ent0, attr0, attr1, attr2; std::vector<BSONElement> contextRegistrationV, entities, attrs; /* reg #1 (untouched) */ reg = connectionDb->findOne(REGISTRATIONS_COLL, BSON("_id" << OID("51307b66f481db11bf860001"))); EXPECT_EQ("51307b66f481db11bf860001", reg.getField("_id").OID().toString()); EXPECT_EQ(10000000, reg.getIntField("expiration")); contextRegistrationV = reg.getField("contextRegistration").Array(); ASSERT_EQ(1, contextRegistrationV.size()); contextRegistration = contextRegistrationV[0].embeddedObject(); EXPECT_STREQ("http://cr1.com", C_STR_FIELD(contextRegistration, "providingApplication")); entities = contextRegistration.getField("entities").Array(); ASSERT_EQ(1, entities.size()); ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); attrs = contextRegistration.getField("attrs").Array(); ASSERT_EQ(3, attrs.size()); attr0 = attrs[0].embeddedObject(); attr1 = attrs[1].embeddedObject(); attr2 = attrs[2].embeddedObject(); EXPECT_STREQ("A1", C_STR_FIELD(attr0, "name")); EXPECT_STREQ("TA1", C_STR_FIELD(attr0, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr0, "isDomain")); EXPECT_STREQ("A2", C_STR_FIELD(attr1, "name")); EXPECT_STREQ("TA2", C_STR_FIELD(attr1, "type")); EXPECT_STREQ("false", C_STR_FIELD(attr1, "isDomain")); EXPECT_STREQ("A3", C_STR_FIELD(attr2, "name")); EXPECT_STREQ("TA3", C_STR_FIELD(attr2, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr2, "isDomain")); /* reg #2 (untouched) */ reg = connectionDb->findOne(REGISTRATIONS_COLL, BSON("_id" << OID("51307b66f481db11bf860002"))); EXPECT_EQ("51307b66f481db11bf860002", reg.getField("_id").OID().toString()); EXPECT_EQ(20000000, reg.getIntField("expiration")); contextRegistrationV = reg.getField("contextRegistration").Array(); ASSERT_EQ(2, contextRegistrationV.size()); contextRegistration = contextRegistrationV[0].embeddedObject(); EXPECT_STREQ("http://cr1.com", C_STR_FIELD(contextRegistration, "providingApplication")); entities = contextRegistration.getField("entities").Array(); ASSERT_EQ(1, entities.size()); ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); attrs = contextRegistration.getField("attrs").Array(); ASSERT_EQ(1, attrs.size()); attr0 = attrs[0].embeddedObject(); EXPECT_STREQ("A1", C_STR_FIELD(attr0, "name")); EXPECT_STREQ("TA1", C_STR_FIELD(attr0, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr0, "isDomain")); contextRegistration = contextRegistrationV[1].embeddedObject(); EXPECT_STREQ("http://cr2.com", C_STR_FIELD(contextRegistration, "providingApplication")); entities = contextRegistration.getField("entities").Array(); ASSERT_EQ(1, entities.size()); ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); attrs = contextRegistration.getField("attrs").Array(); ASSERT_EQ(1, attrs.size()); attr0 = attrs[0].embeddedObject(); EXPECT_STREQ("A1", C_STR_FIELD(attr0, "name")); EXPECT_STREQ("TA1", C_STR_FIELD(attr0, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr0, "isDomain")); utExit(); }
/* **************************************************************************** * * updateWrongIdNoHex - * * FIXME P3: check that we cover this case in the proper place, e.g. check() in the pre-mongoBackend layers, before permanent removal */ TEST(DISABLED_mongoRegisterContext_update, updateWrongIdNoHex) { HttpStatusCode ms; RegisterContextRequest req; RegisterContextResponse res; utInit(); /* Forge the request (from "inside" to "outside") */ EntityId en("E1", "T1"); ContextRegistrationAttribute cra("A1", "TA1", "true"); ContextRegistration cr; cr.entityIdVector.push_back(&en); cr.contextRegistrationAttributeVector.push_back(&cra); cr.providingApplication.set("http://newurl.com"); req.contextRegistrationVector.push_back(&cr); req.registrationId.set("51307b66f481db11bf8600XX"); req.duration.set("PT1M"); /* Prepare database */ prepareDatabase(); /* Invoke the function in mongoBackend library */ ms = mongoRegisterContext(&req, &res, uriParams); /* Check that every involved collection at MongoDB is as expected */ /* Note we are using EXPECT_STREQ() for some cases, as Mongo Driver returns const char*, not string * objects (see http://code.google.com/p/googletest/wiki/Primer#String_Comparison) */ DBClientBase* connection = getMongoConnection(); /* registrations collection: */ ASSERT_EQ(2, connection->count(REGISTRATIONS_COLL, BSONObj())); BSONObj reg, contextRegistration, ent0, attr0, attr1, attr2; std::vector<BSONElement> contextRegistrationV, entities, attrs; /* reg #1 (untouched) */ reg = connection->findOne(REGISTRATIONS_COLL, BSON("_id" << OID("51307b66f481db11bf860001"))); EXPECT_EQ("51307b66f481db11bf860001", reg.getField("_id").OID().toString()); EXPECT_EQ(10000000, reg.getIntField("expiration")); contextRegistrationV = reg.getField("contextRegistration").Array(); ASSERT_EQ(1, contextRegistrationV.size()); contextRegistration = contextRegistrationV[0].embeddedObject(); EXPECT_STREQ("http://cr1.com", C_STR_FIELD(contextRegistration, "providingApplication")); entities = contextRegistration.getField("entities").Array(); ASSERT_EQ(1, entities.size()); ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); attrs = contextRegistration.getField("attrs").Array(); ASSERT_EQ(3, attrs.size()); attr0 = attrs[0].embeddedObject(); attr1 = attrs[1].embeddedObject(); attr2 = attrs[2].embeddedObject(); EXPECT_STREQ("A1", C_STR_FIELD(attr0, "name")); EXPECT_STREQ("TA1", C_STR_FIELD(attr0, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr0, "isDomain")); EXPECT_STREQ("A2", C_STR_FIELD(attr1, "name")); EXPECT_STREQ("TA2", C_STR_FIELD(attr1, "type")); EXPECT_STREQ("false", C_STR_FIELD(attr1, "isDomain")); EXPECT_STREQ("A3", C_STR_FIELD(attr2, "name")); EXPECT_STREQ("TA3", C_STR_FIELD(attr2, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr2, "isDomain")); /* reg #2 (untouched) */ reg = connection->findOne(REGISTRATIONS_COLL, BSON("_id" << OID("51307b66f481db11bf860002"))); EXPECT_EQ("51307b66f481db11bf860002", reg.getField("_id").OID().toString()); EXPECT_EQ(20000000, reg.getIntField("expiration")); contextRegistrationV = reg.getField("contextRegistration").Array(); ASSERT_EQ(2, contextRegistrationV.size()); contextRegistration = contextRegistrationV[0].embeddedObject(); EXPECT_STREQ("http://cr1.com", C_STR_FIELD(contextRegistration, "providingApplication")); entities = contextRegistration.getField("entities").Array(); ASSERT_EQ(1, entities.size()); ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); attrs = contextRegistration.getField("attrs").Array(); ASSERT_EQ(1, attrs.size()); attr0 = attrs[0].embeddedObject(); EXPECT_STREQ("A1", C_STR_FIELD(attr0, "name")); EXPECT_STREQ("TA1", C_STR_FIELD(attr0, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr0, "isDomain")); contextRegistration = contextRegistrationV[1].embeddedObject(); EXPECT_STREQ("http://cr2.com", C_STR_FIELD(contextRegistration, "providingApplication")); entities = contextRegistration.getField("entities").Array(); ASSERT_EQ(1, entities.size()); ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); attrs = contextRegistration.getField("attrs").Array(); ASSERT_EQ(1, attrs.size()); attr0 = attrs[0].embeddedObject(); EXPECT_STREQ("A1", C_STR_FIELD(attr0, "name")); EXPECT_STREQ("TA1", C_STR_FIELD(attr0, "type")); EXPECT_STREQ("true", C_STR_FIELD(attr0, "isDomain")); /* Check response is as expected */ EXPECT_EQ(SccOk, ms); EXPECT_EQ(0, res.duration.get().size()); EXPECT_EQ("51307b66f481db11bf8600XX", res.registrationId.get()); EXPECT_EQ(SccContextElementNotFound, res.errorCode.code); EXPECT_EQ("Registration Not Found", res.errorCode.reasonPhrase); EXPECT_EQ(0, res.errorCode.details.size()); utExit(); }
void ShardChunkManager::_init( const string& configServer , const string& ns , const string& shardName, ShardChunkManagerPtr oldManager ) { // have to get a connection to the config db // special case if I'm the configdb since I'm locked and if I connect to myself // its a deadlock scoped_ptr<ScopedDbConnection> scoped; scoped_ptr<DBDirectClient> direct; DBClientBase * conn; if ( configServer.empty() ) { direct.reset( new DBDirectClient() ); conn = direct.get(); } else { scoped.reset( ScopedDbConnection::getInternalScopedDbConnection( configServer, 30.0 ) ); conn = scoped->get(); } // get this collection's sharding key BSONObj collectionDoc = conn->findOne( "config.collections", BSON( "_id" << ns ) ); if( collectionDoc.isEmpty() ){ warning() << ns << " does not exist as a sharded collection" << endl; return; } if( collectionDoc["dropped"].Bool() ){ warning() << ns << " was dropped. Re-shard collection first." << endl; return; } _fillCollectionKey( collectionDoc ); map<string,ShardChunkVersion> versionMap; versionMap[ shardName ] = _version; _collVersion = ShardChunkVersion( 0, OID() ); // Check to see if we have an old ShardChunkManager to use if( oldManager && oldManager->_collVersion.isSet() ){ versionMap[ shardName ] = oldManager->_version; _collVersion = oldManager->_collVersion; // TODO: This could be made more efficient if copying not required, but not as // frequently reloaded as in mongos. _chunksMap = oldManager->_chunksMap; LOG(2) << "loading new chunks for collection " << ns << " using old chunk manager w/ version " << _collVersion << " and " << _chunksMap.size() << " chunks" << endl; } // Attach our config diff tracker to our range map and versions SCMConfigDiffTracker differ( shardName ); differ.attach( ns, _chunksMap, _collVersion, versionMap ); // Need to do the query ourselves, since we may use direct conns to the db Query query = differ.configDiffQuery(); auto_ptr<DBClientCursor> cursor = conn->query( "config.chunks" , query ); uassert( 16181, str::stream() << "could not initialize cursor to config server chunks collection for ns " << ns, cursor.get() ); // Diff tracker should *always* find at least one chunk if collection exists int diffsApplied = differ.calculateConfigDiff( *cursor ); if( diffsApplied > 0 ){ LOG(2) << "loaded " << diffsApplied << " chunks into new chunk manager for " << ns << " with version " << _collVersion << endl; // Save the new version of this shard _version = versionMap[ shardName ]; _fillRanges(); } else if( diffsApplied == 0 ){ // No chunks were found for the ns warning() << "no chunks found when reloading " << ns << ", previous version was " << _collVersion << endl; _version = ShardChunkVersion( 0, OID() ); _collVersion = ShardChunkVersion( 0, OID() ); _chunksMap.clear(); } else{ // TODO: make this impossible by making sure we don't migrate / split on this shard during the // reload // No chunks were found for the ns warning() << "invalid chunks found when reloading " << ns << ", previous version was " << _collVersion << ", this should be rare" << endl; // Handle the same way as a connectivity error, for now // TODO: handle inline uassert( 16229, str::stream() << "could not initialize cursor to config server chunks collection for ns " << ns, cursor.get() ); } if ( scoped.get() ) scoped->done(); if ( _chunksMap.empty() ) log() << "no chunk for collection " << ns << " on shard " << shardName << endl; }
/* **************************************************************************** * * mongoRegisterContext - */ HttpStatusCode mongoRegisterContext(RegisterContextRequest* requestP, RegisterContextResponse* responseP, const std::string& tenant) { reqSemTake(__FUNCTION__, "ngsi9 register request"); LM_T(LmtMongo, ("Register Context Request")); DBClientBase* connection = getMongoConnection(); /* Check if new registration */ if (requestP->registrationId.isEmpty()) { HttpStatusCode result = processRegisterContext(requestP, responseP, NULL, tenant); reqSemGive(__FUNCTION__, "ngsi9 register request"); return result; } /* It is not a new registration, so it should be an update */ BSONObj reg; OID id; try { id = OID(requestP->registrationId.get()); mongoSemTake(__FUNCTION__, "findOne from RegistrationsCollection"); reg = connection->findOne(getRegistrationsCollectionName(tenant).c_str(), BSON("_id" << id)); mongoSemGive(__FUNCTION__, "findOne from RegistrationsCollection"); LM_I(("Database Operation Successful (findOne _id: %s)", id.toString().c_str())); } catch (const AssertionException &e) { mongoSemGive(__FUNCTION__, "findOne from RegistrationsCollection (AssertionException)"); reqSemGive(__FUNCTION__, "ngsi9 register request"); /* This happens when OID format is wrong */ // FIXME: this checking should be done at parsing stage, without progressing to // mongoBackend. By the moment we can live this here, but we should remove in the future responseP->errorCode.fill(SccContextElementNotFound); responseP->registrationId = requestP->registrationId; ++noOfRegistrationUpdateErrors; LM_W(("Bad Input (invalid OID format)")); return SccOk; } catch (const DBException &e) { mongoSemGive(__FUNCTION__, "findOne from RegistrationsCollection (DBException)"); reqSemGive(__FUNCTION__, "ngsi9 register request"); responseP->errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getRegistrationsCollectionName(tenant).c_str() + " - findOne() _id: " + requestP->registrationId.get() + " - exception: " + e.what()); ++noOfRegistrationUpdateErrors; LM_E(("Database Error (%s)", responseP->errorCode.details.c_str())); return SccOk; } catch (...) { mongoSemGive(__FUNCTION__, "findOne from RegistrationsCollection (Generic Exception)"); reqSemGive(__FUNCTION__, "ngsi9 register request"); responseP->errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getRegistrationsCollectionName(tenant).c_str() + " - findOne() _id: " + requestP->registrationId.get() + " - exception: " + "generic"); ++noOfRegistrationUpdateErrors; LM_E(("Database Error (%s)", responseP->errorCode.details.c_str())); return SccOk; } if (reg.isEmpty()) { reqSemGive(__FUNCTION__, "ngsi9 register request (no registrations found)"); responseP->errorCode.fill(SccContextElementNotFound, std::string("registration id: /") + requestP->registrationId.get() + "/"); responseP->registrationId = requestP->registrationId; ++noOfRegistrationUpdateErrors; return SccOk; } HttpStatusCode result = processRegisterContext(requestP, responseP, &id, tenant); reqSemGive(__FUNCTION__, "ngsi9 register request"); return result; }
/* **************************************************************************** * * createSubscriptionNotCustomOK - */ TEST(mongoCreateSubscriptions, createSubscriptionNotCustomOK) { OrionError oe; utInit(); /* Forge input subscription */ Subscription sub; sub.description = "this is the sub"; sub.expires = 1360236300; sub.status = "active"; sub.throttling = 5; sub.attrsFormat = NGSI_V2_NORMALIZED; EntID en1("E1", "", "T1"); EntID en2("", "E.*", "T2"); sub.subject.entities.push_back(en1); sub.subject.entities.push_back(en2); sub.subject.condition.attributes.push_back("A"); sub.subject.condition.attributes.push_back("B"); sub.subject.condition.expression.q = "temperature<=20"; sub.subject.condition.expression.coords = "-40.4,-3.5;0,0"; sub.subject.condition.expression.georel = "coveredBy"; sub.subject.condition.expression.geometry = "box"; sub.notification.attributes.push_back("C"); sub.notification.attributes.push_back("D"); sub.notification.httpInfo.url = "http://foo.bar"; sub.notification.httpInfo.custom = false; /* Invoke the function in mongoBackend library */ std::string result = mongoCreateSubscription(sub, &oe, "", servicePathVector, "", ""); /* Check response is as expected */ EXPECT_EQ(SccNone, oe.code); EXPECT_EQ("", oe.reasonPhrase); EXPECT_EQ("", oe.details); DBClientBase* connection = getMongoConnection(); ASSERT_EQ(1, connection->count(SUBSCRIBECONTEXT_COLL, BSONObj())); BSONObj doc = connection->findOne(SUBSCRIBECONTEXT_COLL, BSONObj()); EXPECT_EQ(result, doc.getField("_id").OID().toString()); EXPECT_EQ(1360236300, doc.getIntField("expiration")); EXPECT_FALSE(doc.hasField("lastNotification")); EXPECT_EQ(5, doc.getIntField("throttling")); EXPECT_STREQ("http://foo.bar", C_STR_FIELD(doc, "reference")); EXPECT_STREQ("normalized", C_STR_FIELD(doc, "format")); EXPECT_STREQ("this is the sub", C_STR_FIELD(doc, "description")); EXPECT_STREQ("active", C_STR_FIELD(doc, "status")); EXPECT_FALSE(doc.getBoolField("custom")); BSONObj expression = doc.getField("expression").embeddedObject(); EXPECT_STREQ("temperature<=20", C_STR_FIELD(expression, "q")); EXPECT_STREQ("-40.4,-3.5;0,0", C_STR_FIELD(expression, "coords")); EXPECT_STREQ("coveredBy", C_STR_FIELD(expression, "georel")); EXPECT_STREQ("box", C_STR_FIELD(expression, "geometry")); std::vector<BSONElement> entities = doc.getField("entities").Array(); ASSERT_EQ(2, entities.size()); BSONObj ent0 = entities[0].embeddedObject(); EXPECT_STREQ("E1", C_STR_FIELD(ent0, "id")); EXPECT_STREQ("T1", C_STR_FIELD(ent0, "type")); EXPECT_STREQ("false", C_STR_FIELD(ent0, "isPattern")); BSONObj ent1 = entities[1].embeddedObject(); EXPECT_STREQ("E.*", C_STR_FIELD(ent1, "id")); EXPECT_STREQ("T2", C_STR_FIELD(ent1, "type")); EXPECT_STREQ("true", C_STR_FIELD(ent1, "isPattern")); std::vector<BSONElement> attrs = doc.getField("attrs").Array(); EXPECT_EQ(2, attrs.size()); EXPECT_EQ("C", attrs[0].String()); EXPECT_EQ("D", attrs[1].String()); std::vector<BSONElement> conds = doc.getField("conditions").Array(); ASSERT_EQ(1, conds.size()); BSONObj cond0 = conds[0].embeddedObject(); EXPECT_STREQ("ONCHANGE", C_STR_FIELD(cond0, "type")); std::vector<BSONElement> condValues = cond0.getField("value").Array(); ASSERT_EQ(2, condValues.size()); EXPECT_EQ("A", condValues[0].String()); EXPECT_EQ("B", condValues[1].String()); utExit(); }