/* ****************************************************************************
*
* mongoGetContextElementResponses_fail -
*/
TEST(mongoOntimeintervalOperations, mongoGetContextElementResponses_fail)
{
    HttpStatusCode ms;

    /* Forge the parameters */
    EntityIdVector enV;
    EntityId en("E5", "T", "false");
    enV.push_back(&en);
    AttributeList attrL;
    attrL.push_back("A1");
    attrL.push_back("A2");
    attrL.push_back("A3");
    attrL.push_back("A4");
    ContextElementResponseVector cerV;
    std::string err;

    /* Prepare database */
    prepareDatabase();

    /* Do operation */
    ms = mongoGetContextElementResponses(enV, attrL, &cerV, &err);

    /* Check results */
    EXPECT_EQ(SccOk, ms);
    ASSERT_EQ(0, cerV.size());
}
コード例 #2
0
/* ****************************************************************************
*
* mongoGetContextElementResponses -
*
* This function is basically a wrapper of mongoBackend internal entitiesQuery() function
*/
HttpStatusCode mongoGetContextElementResponses(const EntityIdVector& enV, const AttributeList& attrL, ContextElementResponseVector* cerV, std::string* err, const std::string& tenant)
{
    bool reqSemTaken;

    reqSemTake(__FUNCTION__, "get context-element responses", SemReadOp, &reqSemTaken);
    LM_T(LmtMongo, ("Get Notify Context Request operation"));

    // FIXME P10: we are using dummy scope by the moment, until subscription scopes get implemented
    // FIXME P10: we are using an empty service path vector until service paths get implemented for subscriptions
    ContextElementResponseVector rawCerV;
    std::vector<std::string> servicePath;
    Restriction res;
    if (!entitiesQuery(enV, attrL, res, &rawCerV, err, true, tenant, servicePath))
    {
        reqSemGive(__FUNCTION__, "get context-element responses (no entities found)", reqSemTaken);
        rawCerV.release();
        return SccOk;
    }

    /* Prune "not found" CERs */
    pruneContextElements(rawCerV, cerV);
    rawCerV.release();

    reqSemGive(__FUNCTION__, "get context-element responses", reqSemTaken);
    return SccOk;
}
コード例 #3
0
/* ****************************************************************************
*
* fillContextProviders -
*
* Looks in the elements of the CER vector passed as argument, searching for a suitable CPr in the CRR
* vector passed as argument. If a suitable CPr is found, it is added to the CER (and the 'found' field
* is changed to true)
*
*/
void fillContextProviders(ContextElementResponseVector& cerV, ContextRegistrationResponseVector& crrV)
{
  for (unsigned int ix = 0; ix < cerV.size(); ++ix)
  {
    fillContextProviders(cerV.get(ix), crrV);
  }
}
コード例 #4
0
/* ****************************************************************************
*
* someContextElementNotFound -
*
* Returns true if some attribute with 'found' set to 'false' is found in the CER vector passed
* as argument
*
*/
bool someContextElementNotFound(ContextElementResponseVector& cerV)
{
  for (unsigned int ix = 0; ix < cerV.size(); ++ix)
  {
    if (someContextElementNotFound(*cerV.get(ix)))
    {
      return true;
    }
  }
  return false;
}
コード例 #5
0
/* ****************************************************************************
*
* present -
*
* Just to exercise the code, nothing to be expected here ...
*/
TEST(ContextElementResponseVector, present)
{
  ContextElementResponseVector  cerv;
  ContextElementResponse        cer;

  utInit();

  cer.contextElement.entityId.id         = "ID";
  cer.contextElement.entityId.type       = "Type";
  cer.contextElement.entityId.isPattern  = "false";
  cer.statusCode.fill(SccOk, "details");
  cerv.push_back(&cer);

  cerv.present("");

  utExit();
}
コード例 #6
0
/* ****************************************************************************
*
* ContextElementResponseVector::fill - 
*/
void ContextElementResponseVector::fill(ContextElementResponseVector& cerV)
{
  for (unsigned int ix = 0; ix < cerV.size(); ++ix)
  {
    ContextElementResponse* cerP = new ContextElementResponse(cerV[ix]);

    push_back(cerP);
  }
}
コード例 #7
0
/* ****************************************************************************
*
* render - 
*
*/
TEST(ContextElementResponseVector, render)
{
  ContextElementResponseVector  cerv;
  ContextElementResponse        cer;
  std::string                   out;
  ConnectionInfo                ci(JSON);

  utInit();

  out = cerv.render(&ci, UpdateContextElement, "");
  EXPECT_STREQ("", out.c_str());

  cer.contextElement.entityId.id         = "ID";
  cer.contextElement.entityId.type       = "Type";
  cer.contextElement.entityId.isPattern  = "false";
  cer.statusCode.fill(SccOk, "details");

  utExit();
}
コード例 #8
0
/* ****************************************************************************
*
* addContextProviderEntity -
*
*/
void addContextProviderEntity(ContextElementResponseVector& cerV, EntityId* enP, ProvidingApplication pa)
{
  for (unsigned int ix = 0; ix < cerV.size(); ++ix)
  {
    if (cerV.get(ix)->contextElement.entityId.id == enP->id && cerV.get(ix)->contextElement.entityId.type == enP->type)
    {
      cerV.get(ix)->contextElement.providingApplicationList.push_back(pa);
      return;    /* by construction, no more than one CER with the same entity information should exist in the CERV) */
    }
  }

  /* Reached this point, it means that the cerV doesn't contain a proper CER, so we create it */
  ContextElementResponse* cerP            = new ContextElementResponse();
  cerP->contextElement.entityId.id        = enP->id;
  cerP->contextElement.entityId.type      = enP->type;
  cerP->contextElement.entityId.isPattern = "false";
  cerP->contextElement.providingApplicationList.push_back(pa);

  cerP->statusCode.fill(SccOk);
  cerV.push_back(cerP);

}
コード例 #9
0
/* ****************************************************************************
*
* equalContextElementResponseVector -
*/
static bool equalContextElementResponseVector
(
  ContextElementResponseVector cerExpectedV,
  ContextElementResponseVector cerArgV
)
{
  /* Check vector size */
  if (cerExpectedV.size() != cerArgV.size())
  {
    LM_M(("different sizes: expected %d, actual %d", cerExpectedV.size(), cerArgV.size()));
    return false;
  }

  /* Check that every entity in 'cerArgV' is in 'cerExpectedV'. Order doesn't matter */
  for (unsigned int ix = 0; ix < cerArgV.size(); ++ix)
  {
    bool entityMatch = false;

    for (unsigned int jx = 0; jx < cerExpectedV.size(); ++jx)
    {
      ContextElementResponse* cerArg      = cerArgV[ix];
      ContextElementResponse* cerExpected = cerExpectedV[jx];

      EntityId enExpected(cerExpected->entity.id, cerExpected->entity.type);
      EntityId enArg(cerArg->entity.id, cerArg->entity.type);

      if (!equalEntity(enExpected, enArg))
      {
        LM_M(("entity doesn't match in ContextElementResponseVector comparison, continue ..."));
        continue; /* loop in jx */
      }

      /* If there aren't attributes to check, then early exits the loop */
      if (cerExpected->entity.attributeVector.size() == 0)
      {
        LM_M(("entity (without attributes) matches in ContextElementResponseVector comparison, check next one..."));
        entityMatch = true;
        break; /* loop in jx */
      }

      if (equalContextAttributeVector(cerExpected->entity.attributeVector, cerArg->entity.attributeVector))
      {
        LM_M(("entity (with attributes) matches in ContextElementResponseVector comparison, check next one..."));
        entityMatch = true;
        break; /* loop in jx */
      }
    }

    if (!entityMatch)
    {
      LM_M(("after checking everything, entity doesn't match in ContextElementResponseVector comparison"));
      return false;
    }
  }

  LM_M(("ContextElementResponseVector comparison ok"));
  return true;
}
コード例 #10
0
/* ****************************************************************************
*
* addContextProviderAttribute -
*
* The limitReached parameter is to prevent the addition of new entities, which is needed in the case of the pagination
* limit has been reached with local entities.
*
*/
void addContextProviderAttribute
(
  ContextElementResponseVector&   cerV,
  EntityId*                       enP,
  ContextRegistrationAttribute*   craP,
  const ProvidingApplication&     pa,
  bool                            limitReached
)
{
  for (unsigned int ix = 0; ix < cerV.size(); ++ix)
  {
    if ((cerV.get(ix)->contextElement.entityId.id != enP->id) ||
        (cerV.get(ix)->contextElement.entityId.type != enP->type))
    {
     continue;
    }

    for (unsigned int jx = 0; jx < cerV.get(ix)->contextElement.contextAttributeVector.size(); ++jx)
    {
      std::string attrName = cerV.get(ix)->contextElement.contextAttributeVector.get(jx)->name;
      if (attrName == craP->name)
      {
        /* In this case, the attribute has been already found in local database. CPr is unnecessary */
        return;
      }
    }
    /* Reached this point, no attribute was found, so adding it with corresponding CPr info */
    ContextAttribute* caP = new ContextAttribute(craP->name, "", "");
    caP->providingApplication = pa;
    cerV.get(ix)->contextElement.contextAttributeVector.push_back(caP);
    return;

  }

  if (!limitReached)
  {
    /* Reached this point, it means that the cerV doesn't contain a proper CER, so we create it */
    ContextElementResponse* cerP            = new ContextElementResponse();
    cerP->contextElement.entityId.id        = enP->id;
    cerP->contextElement.entityId.type      = enP->type;
    cerP->contextElement.entityId.isPattern = "false";

    cerP->statusCode.fill(SccOk);

    ContextAttribute* caP = new ContextAttribute(craP->name, "", "");
    caP->providingApplication = pa;
    cerP->contextElement.contextAttributeVector.push_back(caP);

    cerV.push_back(cerP);
  }
}
コード例 #11
0
/* ****************************************************************************
*
* foundAndNotFoundAttributeSeparation - 
*
* Examine the response from mongo to find out what has really happened ...
*
*/
static void foundAndNotFoundAttributeSeparation(UpdateContextResponse* upcrsP, UpdateContextRequest* upcrP, ConnectionInfo* ciP)
{
  ContextElementResponseVector  notFoundV;

  for (unsigned int cerIx = 0; cerIx < upcrsP->contextElementResponseVector.size(); ++cerIx)
  {
    ContextElementResponse* cerP = upcrsP->contextElementResponseVector[cerIx];

    //
    // All attributes with found == false?
    //
    int noOfFounds    = 0;
    int noOfNotFounds = 0;
    for (unsigned int aIx = 0; aIx < cerP->contextElement.contextAttributeVector.size(); ++aIx)
    {
      if (cerP->contextElement.contextAttributeVector[aIx]->found == true)
      {
        ++noOfFounds;
      }
      else
      {
        ++noOfNotFounds;
      }
    }

    //
    // Now, if we have ONLY FOUNDS, then things stay the way they are, one response with '200 OK'
    // If we have ONLY NOT-FOUNDS, the we have one response with '404 Not Found'
    // If we have a mix, then we need to add a response for the not founds, with '404 Not Found'
    //
    if ((noOfFounds == 0) && (noOfNotFounds > 0))
    {
      if ((cerP->statusCode.code == SccOk) || (cerP->statusCode.code == SccNone))
      {
        cerP->statusCode.fill(SccContextElementNotFound, cerP->contextElement.entityId.id);
      }
    }
    else if ((noOfFounds > 0) && (noOfNotFounds > 0))
    {
      // Adding a ContextElementResponse for the 'Not-Founds'

      ContextElementResponse* notFoundCerP = new ContextElementResponse(&cerP->contextElement.entityId, NULL);

      //
      // Filling in StatusCode (SccContextElementNotFound) for NotFound
      //
      notFoundCerP->statusCode.fill(SccContextElementNotFound, cerP->contextElement.entityId.id);

      //
      // Setting StatusCode to OK for Found
      //
      cerP->statusCode.fill(SccOk);

      //
      // And, pushing to NotFound-vector 
      //
      notFoundV.push_back(notFoundCerP);


      // Now moving the not-founds to notFoundCerP
      std::vector<ContextAttribute*>::iterator iter;
      for (iter = cerP->contextElement.contextAttributeVector.vec.begin(); iter < cerP->contextElement.contextAttributeVector.vec.end();)
      {
        if ((*iter)->found == false)
        {
          // 1. Push to notFoundCerP
          notFoundCerP->contextElement.contextAttributeVector.push_back(*iter);

          // 2. remove from cerP
          iter = cerP->contextElement.contextAttributeVector.vec.erase(iter);
        }
        else
        {
          ++iter;
        }
      }
    }

    //
    // Add EntityId::id to StatusCode::details if 404, but only if StatusCode::details is empty
    //
    if ((cerP->statusCode.code == SccContextElementNotFound) && (cerP->statusCode.details == ""))
    {
      cerP->statusCode.details = cerP->contextElement.entityId.id;
    }
  }

  //
  // Now add the contextElementResponses for 404 Not Found
  //
  if (notFoundV.size() != 0)
  {
    for (unsigned int ix = 0; ix < notFoundV.size(); ++ix)
    {
      upcrsP->contextElementResponseVector.push_back(notFoundV[ix]);
    }
  }


  //
  // If nothing at all in response vector, mark as not found (but not if DELETE request)
  //
  if (ciP->method != "DELETE")
  {
    if (upcrsP->contextElementResponseVector.size() == 0)
    {
      if (upcrsP->errorCode.code == SccOk)
      {
        upcrsP->errorCode.fill(SccContextElementNotFound, upcrP->contextElementVector[0]->entityId.id);
      }
    }
  }

  
  //
  // Add entityId::id to details if Not Found and only one element in response.
  // And, if 0 elements in response, take entityId::id from the request.
  //
  if (upcrsP->errorCode.code == SccContextElementNotFound)
  {
    if (upcrsP->contextElementResponseVector.size() == 1)
    {
      upcrsP->errorCode.details = upcrsP->contextElementResponseVector[0]->contextElement.entityId.id;
    }
    else if (upcrsP->contextElementResponseVector.size() == 0)
    {
      upcrsP->errorCode.details = upcrP->contextElementVector[0]->entityId.id;
    }
  }
}
/* ****************************************************************************
*
* mongoGetContextElementResponses_pattern -
*/
TEST(mongoOntimeintervalOperations, mongoGetContextElementResponses_pattern)
{
    HttpStatusCode ms;

    /* Forge the parameters */
    EntityIdVector enV;
    EntityId en("E[1-2]", "T", "true");
    enV.push_back(&en);
    AttributeList attrL;
    attrL.push_back("A1");
    attrL.push_back("A2");
    attrL.push_back("A3");
    attrL.push_back("A4");
    ContextElementResponseVector cerV;
    std::string err;

    /* Prepare database */
    prepareDatabase();

    /* Do operation */
    ms = mongoGetContextElementResponses(enV, attrL, &cerV, &err);

    /* Check results */
    EXPECT_EQ(SccOk, ms);
    ASSERT_EQ(2, cerV.size());
    ContextElementResponse cer0 = *cerV[0];
    ContextElementResponse cer1 = *cerV[1];
    ContextAttribute ca0, ca1, ca2, ca3;

    /* Context Element Response #1 */
    EXPECT_EQ(SccOk, cer0.statusCode.code);
    EXPECT_EQ("OK", cer0.statusCode.reasonPhrase);
    EXPECT_EQ(0, cer0.statusCode.details.length());
    EXPECT_EQ("E1", cer0.contextElement.entityId.id);
    EXPECT_EQ("T", cer0.contextElement.entityId.type);
    EXPECT_EQ("false", cer0.contextElement.entityId.isPattern);
    ASSERT_EQ(3, cer0.contextElement.contextAttributeVector.size());
    ca0 = *cer0.contextElement.contextAttributeVector[0];
    ca1 = *cer0.contextElement.contextAttributeVector[1];
    ca2 = *cer0.contextElement.contextAttributeVector[2];
    EXPECT_EQ("A1", ca0.name);
    EXPECT_EQ("TA1", ca0.type);
    EXPECT_EQ("X", ca0.stringValue);
    EXPECT_EQ("A2", ca1.name);
    EXPECT_EQ("TA2", ca1.type);
    EXPECT_EQ("Z", ca1.stringValue);
    EXPECT_EQ("A3", ca2.name);
    EXPECT_EQ("TA3", ca2.type);
    EXPECT_EQ("W", ca2.stringValue);

    /* Context Element Response #2 */
    EXPECT_EQ(SccOk, cer1.statusCode.code);
    EXPECT_EQ("OK", cer1.statusCode.reasonPhrase);
    EXPECT_EQ(0, cer1.statusCode.details.length());
    EXPECT_EQ("E2", cer1.contextElement.entityId.id);
    EXPECT_EQ("T", cer1.contextElement.entityId.type);
    EXPECT_EQ("false", cer1.contextElement.entityId.isPattern);
    ASSERT_EQ(2, cer1.contextElement.contextAttributeVector.size());
    ca0 = *cer1.contextElement.contextAttributeVector[0];
    ca1 = *cer1.contextElement.contextAttributeVector[1];
    EXPECT_EQ("A1", ca0.name);
    EXPECT_EQ("TA1", ca0.type);
    EXPECT_EQ("S", ca0.stringValue);
    EXPECT_EQ("A4", ca1.name);
    EXPECT_EQ("TA4", ca1.type);
    EXPECT_EQ("T", ca1.stringValue);

    EXPECT_EQ(0, err.length());
}
コード例 #13
0
/* ****************************************************************************
*
* mongoQueryContext - 
*
* NOTE
*   If the in/out-parameter countP is non-NULL then the number of matching entities
*   must be returned in *countP.
*
*   This replaces the 'uriParams[URI_PARAM_PAGINATION_DETAILS]' way of passing this information.
*   The old method was one-way, using the new method 
*/
HttpStatusCode mongoQueryContext
(
  QueryContextRequest*                 requestP,
  QueryContextResponse*                responseP,
  const std::string&                   tenant,
  const std::vector<std::string>&      servicePathV,
  std::map<std::string, std::string>&  uriParams,
  long long*                           countP
)
{
    int         offset         = atoi(uriParams[URI_PARAM_PAGINATION_OFFSET].c_str());
    int         limit          = atoi(uriParams[URI_PARAM_PAGINATION_LIMIT].c_str());
    std::string detailsString  = uriParams[URI_PARAM_PAGINATION_DETAILS];
    bool        details        = (strcasecmp("on", detailsString.c_str()) == 0)? true : false;

    LM_T(LmtMongo, ("QueryContext Request"));    
    LM_T(LmtPagination, ("Offset: %d, Limit: %d, Details: %s", offset, limit, (details == true)? "true" : "false"));

    /* FIXME: restriction not supported for the moment */
    if (!requestP->restriction.attributeExpression.isEmpty())
    {
      LM_W(("Bad Input (restriction found, but restrictions are not supported by mongo backend)"));
    }

    std::string err;
    bool        ok;
    bool        limitReached = false;
    bool        reqSemTaken;

    ContextElementResponseVector rawCerV;    
    reqSemTake(__FUNCTION__, "ngsi10 query request", SemReadOp, &reqSemTaken);
    ok = entitiesQuery(requestP->entityIdVector,
                       requestP->attributeList,
                       requestP->restriction,
                       &rawCerV,
                       &err,
                       true,
                       tenant,
                       servicePathV,
                       offset,
                       limit,
                       &limitReached,
                       countP);

    if (!ok)
    {
        responseP->errorCode.fill(SccReceiverInternalError, err);
        rawCerV.release();
        reqSemGive(__FUNCTION__, "ngsi10 query request", reqSemTaken);
        return SccOk;
    }

    ContextRegistrationResponseVector crrV;

    /* In the case of empty response, if only generic processing is needed */
    if (rawCerV.size() == 0)
    {
      if (registrationsQuery(requestP->entityIdVector, requestP->attributeList, &crrV, &err, tenant, servicePathV, 0, 0, false))
      {
        if (crrV.size() > 0)
        {
          processGenericEntities(requestP->entityIdVector, rawCerV, crrV, limitReached);
        }
      }
      else
      {
        /* Different from errors in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */
        LM_E(("Database Error (%s)", err.c_str()));
      }
      crrV.release();
    }

    /* First CPr lookup (in the case some CER is not found): looking in E-A registrations */
    if (someContextElementNotFound(rawCerV))
    {
      if (registrationsQuery(requestP->entityIdVector, requestP->attributeList, &crrV, &err, tenant, servicePathV, 0, 0, false))
      {
        if (crrV.size() > 0)
        {
          fillContextProviders(rawCerV, crrV);
          processGenericEntities(requestP->entityIdVector, rawCerV, crrV, limitReached);
        }
      }
      else
      {
        /* Different from errors in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */
        LM_E(("Database Error (%s)", err.c_str()));
      }
      crrV.release();
    }

    /* Second CPr lookup (in the case some element stills not being found): looking in E-<null> registrations */
    AttributeList attrNullList;
    if (someContextElementNotFound(rawCerV))
    {
      if (registrationsQuery(requestP->entityIdVector, attrNullList, &crrV, &err, tenant, servicePathV, 0, 0, false))
      {
        if (crrV.size() > 0)
        {
          fillContextProviders(rawCerV, crrV);
        }
      }
      else
      {
        /* Different from errors in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */
        LM_E(("Database Error (%s)", err.c_str()));
      }
      crrV.release();
    }

    /* Special case: request with <null> attributes. In that case, entitiesQuery() may have captured some local attribute, but
     * the list need to be completed. Note that in the case of having this request someContextElementNotFound() is always false
     * so we efficient not invoking registrationQuery() too much times */
    if (requestP->attributeList.size() == 0)
    {
      if (registrationsQuery(requestP->entityIdVector, requestP->attributeList, &crrV, &err, tenant, servicePathV, 0, 0, false))
      {
        if (crrV.size() > 0)
        {
          addContextProviders(rawCerV, crrV, limitReached);
        }
      }
      else
      {
        /* Different from fails in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */
        LM_E(("Database Error (%s)", err.c_str()));
      }
      crrV.release();
    }

    /* Prune "not found" CERs */
    pruneContextElements(rawCerV, &responseP->contextElementResponseVector);

    /* Pagination stuff */
    if (responseP->contextElementResponseVector.size() == 0)
    {

      // If the query has an empty response, we have to fill in the status code part in the response.
      //
      // However, if the response was empty due to a too high pagination offset,
      // and if the user has asked for 'details' (as URI parameter, then the response should include information about
      // the number of hits without pagination.
      //

      if ((countP != NULL) && (*countP > 0) && (offset >= *countP))
      {
        char details[256];

        snprintf(details, sizeof(details), "Number of matching entities: %lld. Offset is %d", *countP, offset);
        responseP->errorCode.fill(SccContextElementNotFound, details);
      }
      else
      {
        responseP->errorCode.fill(SccContextElementNotFound);
      }
    }
    else if (countP != NULL)
    {
      //
      // If all was OK, but the details URI param was set to 'on', then the responses error code details
      // 'must' contain the total count of hits.
      //

      char details[64];

      snprintf(details, sizeof(details), "Count: %lld", *countP);
      responseP->errorCode.fill(SccOk, details);
    }

    rawCerV.release();
    
    reqSemGive(__FUNCTION__, "ngsi10 query request", reqSemTaken);
    return SccOk;
}