diff --git a/core/include/Data/VariableRequest.h b/core/include/Data/VariableRequest.h index 4356735..e47261b 100644 --- a/core/include/Data/VariableRequest.h +++ b/core/include/Data/VariableRequest.h @@ -15,12 +15,10 @@ * @brief The VariableRequest struct holds the information of an acquisition request */ struct VariableRequest { - VariableRequest() { m_CanUpdate = false; } - + QUuid m_VariableGroupId; SqpRange m_RangeRequested; SqpRange m_CacheRangeRequested; std::shared_ptr m_DataSeries; - bool m_CanUpdate; }; SCIQLOP_REGISTER_META_TYPE(VARIABLEREQUEST_REGISTRY, VariableRequest) diff --git a/core/src/Variable/VariableAcquisitionWorker.cpp b/core/src/Variable/VariableAcquisitionWorker.cpp index 8487848..479293a 100644 --- a/core/src/Variable/VariableAcquisitionWorker.cpp +++ b/core/src/Variable/VariableAcquisitionWorker.cpp @@ -183,9 +183,9 @@ void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier) if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) { auto request = it->second; impl->unlock(); - qCInfo(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed") - << acqIdentifier << request.m_vIdentifier - << QThread::currentThread(); + qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed") + << acqIdentifier << request.m_vIdentifier + << QThread::currentThread(); emit variableCanceledRequested(request.m_vIdentifier); } else { diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp index 6ef2097..d1865e6 100644 --- a/core/src/Variable/VariableController.cpp +++ b/core/src/Variable/VariableController.cpp @@ -77,6 +77,23 @@ SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange & } } +enum class VariableRequestHandlerState { OFF, RUNNING, PENDING }; + +struct VariableRequestHandler { + + VariableRequestHandler() + { + m_CanUpdate = false; + m_State = VariableRequestHandlerState::OFF; + } + + QUuid m_VarId; + VariableRequest m_RunningVarRequest; + VariableRequest m_PendingVarRequest; + VariableRequestHandlerState m_State; + bool m_CanUpdate; +}; + struct VariableController::VariableControllerPrivate { explicit VariableControllerPrivate(VariableController *parent) : m_WorkingMutex{}, @@ -113,10 +130,10 @@ struct VariableController::VariableControllerPrivate { void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest); QUuid acceptVariableRequest(QUuid varId, std::shared_ptr dataSeries); + void updateVariables(QUuid varRequestId); void updateVariableRequest(QUuid varRequestId); void cancelVariableRequest(QUuid varRequestId); - - SqpRange getLastRequestedRange(QUuid varId); + void executeVarRequest(std::shared_ptr var, VariableRequest &varRequest); QMutex m_WorkingMutex; /// Variable model. The VariableController has the ownership @@ -137,10 +154,8 @@ struct VariableController::VariableControllerPrivate { std::map m_VariableIdGroupIdMap; std::set > m_ProviderSet; - std::map > m_VarRequestIdToVarIdVarRequestMap; - - std::map > m_VarIdToVarRequestIdQueueMap; - + std::map > m_VarGroupIdToVarIds; + std::map > m_VarIdToVarRequestHandler; VariableController *q; }; @@ -275,20 +290,28 @@ VariableController::createVariable(const QString &name, const QVariantHash &meta auto range = impl->m_TimeController->dateTime(); if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) { - auto identifier = QUuid::createUuid(); + auto varId = QUuid::createUuid(); + + // Create the handler + auto varRequestHandler = std::make_unique(); + varRequestHandler->m_VarId = varId; + + impl->m_VarIdToVarRequestHandler.insert( + std::make_pair(varId, std::move(varRequestHandler))); // store the provider impl->registerProvider(provider); // Associate the provider impl->m_VariableToProviderMap[newVariable] = provider; - qCInfo(LOG_VariableController()) << "createVariable: " << identifier; - impl->m_VariableToIdentifierMap[newVariable] = identifier; + impl->m_VariableToIdentifierMap[newVariable] = varId; + this->onRequestDataLoading(QVector >{newVariable}, range, false); - auto varRequestId = QUuid::createUuid(); - impl->processRequest(newVariable, range, varRequestId); - impl->updateVariableRequest(varRequestId); + // auto varRequestId = QUuid::createUuid(); + // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId; + // impl->processRequest(newVariable, range, varRequestId); + // impl->updateVariableRequest(varRequestId); return newVariable; } @@ -300,19 +323,51 @@ void VariableController::onDateTimeOnSelection(const SqpRange &dateTime) qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection" << QThread::currentThread()->objectName(); auto selectedRows = impl->m_VariableSelectionModel->selectedRows(); - auto variables = QVector >{}; - for (const auto &selectedRow : qAsConst(selectedRows)) { - if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) { - variables << selectedVariable; + // NOTE we only permit the time modification for one variable + // DEPRECATED + // auto variables = QVector >{}; + // for (const auto &selectedRow : qAsConst(selectedRows)) { + // if (auto selectedVariable = + // impl->m_VariableModel->variable(selectedRow.row())) { + // variables << selectedVariable; + + // // notify that rescale operation has to be done + // emit rangeChanged(selectedVariable, dateTime); + // } + // } + // if (!variables.isEmpty()) { + // this->onRequestDataLoading(variables, dateTime, synchro); + // } + if (selectedRows.size() == 1) { + + if (auto selectedVariable + = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) { + + auto itVar = impl->m_VariableToIdentifierMap.find(selectedVariable); + if (itVar == impl->m_VariableToIdentifierMap.cend()) { + qCCritical(LOG_VariableController()) + << tr("Impossible to onDateTimeOnSelection request for unknown variable"); + return; + } // notify that rescale operation has to be done emit rangeChanged(selectedVariable, dateTime); + + auto synchro = impl->m_VariableIdGroupIdMap.find(itVar->second) + != impl->m_VariableIdGroupIdMap.cend(); + + this->onRequestDataLoading(QVector >{selectedVariable}, + dateTime, synchro); } } - - if (!variables.isEmpty()) { - this->onRequestDataLoading(variables, dateTime, true); + else if (selectedRows.size() > 1) { + qCCritical(LOG_VariableController()) + << tr("Impossible to set time for more than 1 variable in the same time"); + } + else { + qCWarning(LOG_VariableController()) + << tr("There is no variable selected to set the time one"); } } @@ -320,10 +375,11 @@ void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &range const SqpRange &cacheRangeRequested, QVector dataAcquired) { + qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread(); auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired); auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries); if (!varRequestId.isNull()) { - impl->updateVariableRequest(varRequestId); + impl->updateVariables(varRequestId); } } @@ -343,30 +399,30 @@ void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, doub void VariableController::onAbortProgressRequested(std::shared_ptr variable) { - auto it = impl->m_VariableToIdentifierMap.find(variable); - if (it != impl->m_VariableToIdentifierMap.cend()) { - impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second); + qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested" + << QThread::currentThread()->objectName() << variable->name(); - QUuid varRequestId; - auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second); - if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) { - auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second; - varRequestId = varRequestIdQueue.front(); - impl->cancelVariableRequest(varRequestId); + auto itVar = impl->m_VariableToIdentifierMap.find(variable); + if (itVar == impl->m_VariableToIdentifierMap.cend()) { + qCCritical(LOG_VariableController()) + << tr("Impossible to onAbortProgressRequested request for unknown variable"); + return; + } - // Finish the progression for the request - impl->m_VariableModel->setDataProgress(variable, 0.0); - } - else { - qCWarning(LOG_VariableController()) - << tr("Aborting progression of inexistant variable request detected !!!") - << QThread::currentThread()->objectName(); - } + auto varId = itVar->second; + + auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId); + if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) { + qCCritical(LOG_VariableController()) + << tr("Impossible to onAbortProgressRequested for variable with unknown handler"); + return; } - else { - qCWarning(LOG_VariableController()) - << tr("Aborting progression of inexistant variable detected !!!") - << QThread::currentThread()->objectName(); + + auto varHandler = itVarHandler->second.get(); + + // case where a variable has a running request + if (varHandler->m_State != VariableRequestHandlerState::OFF) { + impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId); } } @@ -460,72 +516,72 @@ void VariableController::desynchronize(std::shared_ptr variable, void VariableController::onRequestDataLoading(QVector > variables, const SqpRange &range, bool synchronise) { - // NOTE: oldRange isn't really necessary since oldRange == variable->range(). - + // variables is assumed synchronized + // TODO: Asser variables synchronization // we want to load data of the variable for the dateTime. - // First we check if the cache contains some of them. - // For the other, we ask the provider to give them. + if (variables.isEmpty()) { + return; + } auto varRequestId = QUuid::createUuid(); qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading" - << QThread::currentThread()->objectName() << varRequestId; - - for (const auto &var : variables) { - qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId; - impl->processRequest(var, range, varRequestId); - } + << QThread::currentThread()->objectName() << varRequestId + << range << synchronise; - if (synchronise) { - // Get the group ids - qCDebug(LOG_VariableController()) - << "TORM VariableController::onRequestDataLoading for synchro var ENABLE"; - auto groupIds = std::set{}; - auto groupIdToOldRangeMap = std::map{}; + if (!synchronise) { + auto varIds = std::list{}; for (const auto &var : variables) { - auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var); - if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) { - auto vId = varToVarIdIt->second; - auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId); - if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) { - auto gId = varIdToGroupIdIt->second; - groupIdToOldRangeMap.insert(std::make_pair(gId, var->range())); - if (groupIds.find(gId) == groupIds.cend()) { - qCDebug(LOG_VariableController()) << "Synchro detect group " << gId; - groupIds.insert(gId); - } - } - } + auto vId = impl->m_VariableToIdentifierMap.at(var); + varIds.push_back(vId); + } + impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds)); + for (const auto &var : variables) { + qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId + << varIds.size(); + impl->processRequest(var, range, varRequestId); } + } + else { + auto vId = impl->m_VariableToIdentifierMap.at(variables.first()); + auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId); + if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) { + auto groupId = varIdToGroupIdIt->second; - // We assume here all group ids exist - for (const auto &gId : groupIds) { - auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId); + auto vSynchronizationGroup + = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId); auto vSyncIds = vSynchronizationGroup->getIds(); - qCDebug(LOG_VariableController()) << "Var in synchro group "; + + auto varIds = std::list{}; + for (auto vId : vSyncIds) { + varIds.push_back(vId); + } + impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds)); + for (auto vId : vSyncIds) { auto var = impl->findVariable(vId); // Don't process already processed var - if (!variables.contains(var)) { - if (var != nullptr) { - qCDebug(LOG_VariableController()) << "processRequest synchro for" - << var->name(); - auto vSyncRangeRequested = computeSynchroRangeRequested( - var->range(), range, groupIdToOldRangeMap.at(gId)); - qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested; - impl->processRequest(var, vSyncRangeRequested, varRequestId); - } - else { - qCCritical(LOG_VariableController()) + if (var != nullptr) { + qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name() + << varRequestId; + auto vSyncRangeRequested + = variables.contains(var) + ? range + : computeSynchroRangeRequested(var->range(), range, + variables.first()->range()); + qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested; + impl->processRequest(var, vSyncRangeRequested, varRequestId); + } + else { + qCCritical(LOG_VariableController()) - << tr("Impossible to synchronize a null variable"); - } + << tr("Impossible to synchronize a null variable"); } } } } - impl->updateVariableRequest(varRequestId); + impl->updateVariables(varRequestId); } @@ -576,66 +632,70 @@ void VariableController::VariableControllerPrivate::processRequest(std::shared_p const SqpRange &rangeRequested, QUuid varRequestId) { - auto varRequest = VariableRequest{}; + auto itVar = m_VariableToIdentifierMap.find(var); + if (itVar == m_VariableToIdentifierMap.cend()) { + qCCritical(LOG_VariableController()) + << tr("Impossible to process request for unknown variable"); + return; + } - auto it = m_VariableToIdentifierMap.find(var); - if (it != m_VariableToIdentifierMap.cend()) { + auto varId = itVar->second; - auto varId = it->second; + auto itVarHandler = m_VarIdToVarRequestHandler.find(varId); + if (itVarHandler == m_VarIdToVarRequestHandler.cend()) { + qCCritical(LOG_VariableController()) + << tr("Impossible to process request for variable with unknown handler"); + return; + } - auto oldRange = getLastRequestedRange(varId); + auto oldRange = var->range(); - // check for update oldRange to the last request range. - if (oldRange == INVALID_RANGE) { - oldRange = var->range(); - } + auto varHandler = itVarHandler->second.get(); - auto varStrategyRangesRequested - = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested); - - auto notInCacheRangeList - = Variable::provideNotInCacheRangeList(oldRange, varStrategyRangesRequested.second); - auto inCacheRangeList - = Variable::provideInCacheRangeList(oldRange, varStrategyRangesRequested.second); - - if (!notInCacheRangeList.empty()) { - varRequest.m_RangeRequested = varStrategyRangesRequested.first; - varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second; - - // store VarRequest - storeVariableRequest(varId, varRequestId, varRequest); - - auto varProvider = m_VariableToProviderMap.at(var); - if (varProvider != nullptr) { - auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest( - varRequestId, varId, varStrategyRangesRequested.first, - varStrategyRangesRequested.second, - DataProviderParameters{std::move(notInCacheRangeList), var->metadata()}, - varProvider); - - if (!varRequestIdCanceled.isNull()) { - qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ") - << varRequestIdCanceled; - cancelVariableRequest(varRequestIdCanceled); - } - } - else { - qCCritical(LOG_VariableController()) - << "Impossible to provide data with a null provider"; - } + if (varHandler->m_State != VariableRequestHandlerState::OFF) { + oldRange = varHandler->m_RunningVarRequest.m_RangeRequested; + } - if (!inCacheRangeList.empty()) { - emit q->updateVarDisplaying(var, inCacheRangeList.first()); - } + auto varRequest = VariableRequest{}; + varRequest.m_VariableGroupId = varRequestId; + auto varStrategyRangesRequested + = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested); + varRequest.m_RangeRequested = varStrategyRangesRequested.first; + varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second; + + switch (varHandler->m_State) { + case VariableRequestHandlerState::OFF: { + qCDebug(LOG_VariableController()) << tr("Process Request OFF") + << varRequest.m_RangeRequested + << varRequest.m_CacheRangeRequested; + varHandler->m_RunningVarRequest = varRequest; + varHandler->m_State = VariableRequestHandlerState::RUNNING; + executeVarRequest(var, varRequest); + break; } - else { - varRequest.m_RangeRequested = varStrategyRangesRequested.first; - varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second; - // store VarRequest - storeVariableRequest(varId, varRequestId, varRequest); - acceptVariableRequest( - varId, var->dataSeries()->subDataSeries(varStrategyRangesRequested.second)); + case VariableRequestHandlerState::RUNNING: { + qCDebug(LOG_VariableController()) << tr("Process Request RUNNING") + << varRequest.m_RangeRequested + << varRequest.m_CacheRangeRequested; + varHandler->m_State = VariableRequestHandlerState::PENDING; + varHandler->m_PendingVarRequest = varRequest; + break; } + case VariableRequestHandlerState::PENDING: { + qCDebug(LOG_VariableController()) << tr("Process Request PENDING") + << varRequest.m_RangeRequested + << varRequest.m_CacheRangeRequested; + auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId; + cancelVariableRequest(variableGroupIdToCancel); + // Cancel variable can make state downgrade + varHandler->m_State = VariableRequestHandlerState::PENDING; + varHandler->m_PendingVarRequest = varRequest; + + break; + } + default: + qCCritical(LOG_VariableController()) + << QObject::tr("Unknown VariableRequestHandlerState"); } } @@ -696,105 +756,63 @@ void VariableController::VariableControllerPrivate::registerProvider( } } -void VariableController::VariableControllerPrivate::storeVariableRequest( - QUuid varId, QUuid varRequestId, const VariableRequest &varRequest) -{ - // First request for the variable. we can create an entry for it - auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId); - if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) { - auto varRequestIdQueue = std::deque{}; - qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE"); - varRequestIdQueue.push_back(varRequestId); - m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue))); - } - else { - qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE"); - auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second; - varRequestIdQueue.push_back(varRequestId); - } - - auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId); - if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) { - auto varIdToVarRequestMap = std::map{}; - varIdToVarRequestMap.insert(std::make_pair(varId, varRequest)); - qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP"); - m_VarRequestIdToVarIdVarRequestMap.insert( - std::make_pair(varRequestId, std::move(varIdToVarRequestMap))); - } - else { - auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second; - qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP"); - varIdToVarRequestMap.insert(std::make_pair(varId, varRequest)); - } -} - QUuid VariableController::VariableControllerPrivate::acceptVariableRequest( QUuid varId, std::shared_ptr dataSeries) { - QUuid varRequestId; - auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId); - if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) { - auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second; - varRequestId = varRequestIdQueue.front(); - auto varRequestIdToVarIdVarRequestMapIt - = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId); - if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) { - auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second; - auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId); - if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) { - qCDebug(LOG_VariableController()) << tr("acceptVariableRequest"); - auto &varRequest = varIdToVarRequestMapIt->second; - varRequest.m_DataSeries = dataSeries; - varRequest.m_CanUpdate = true; - } - else { - qCDebug(LOG_VariableController()) - << tr("Impossible to acceptVariableRequest of a unknown variable id attached " - "to a variableRequestId") - << varRequestId << varId; - } - } - else { - qCCritical(LOG_VariableController()) - << tr("Impossible to acceptVariableRequest of a unknown variableRequestId") - << varRequestId; - } - - varRequestIdQueue.pop_front(); - if (varRequestIdQueue.empty()) { - qCDebug(LOG_VariableController()) - << tr("TORM Erase REQUEST because it has been accepted") << varId; - m_VarIdToVarRequestIdQueueMap.erase(varId); - } + auto itVarHandler = m_VarIdToVarRequestHandler.find(varId); + if (itVarHandler == m_VarIdToVarRequestHandler.cend()) { + return QUuid(); } - else { + + auto varHandler = itVarHandler->second.get(); + if (varHandler->m_State == VariableRequestHandlerState::OFF) { qCCritical(LOG_VariableController()) - << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId; + << tr("acceptVariableRequest impossible on a variable with OFF state"); } - return varRequestId; + varHandler->m_RunningVarRequest.m_DataSeries = dataSeries; + varHandler->m_CanUpdate = true; + + // Element traité, on a déjà toutes les données necessaires + auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId; + qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId + << m_VarGroupIdToVarIds.size(); + + return varHandler->m_RunningVarRequest.m_VariableGroupId; } -void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId) +void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId) { + qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables" + << QThread::currentThread()->objectName() << varRequestId; - auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId); - if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) { - bool processVariableUpdate = true; - auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second; - for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin(); - (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate; - ++varIdToVarRequestMapIt) { - processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate; - qCDebug(LOG_VariableController()) << tr("updateVariableRequest") - << processVariableUpdate; + auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); + if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { + qCWarning(LOG_VariableController()) + << tr("Impossible to updateVariables of unknown variables") << varRequestId; + return; + } + + auto &varIds = varGroupIdToVarIdsIt->second; + auto varIdsEnd = varIds.end(); + bool processVariableUpdate = true; + qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables" + << varRequestId << varIds.size(); + for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate; + ++varIdsIt) { + auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); + if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { + processVariableUpdate &= itVarHandler->second->m_CanUpdate; } + } - if (processVariableUpdate) { - for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin(); - varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) { - if (auto var = findVariable(varIdToVarRequestMapIt->first)) { - auto &varRequest = varIdToVarRequestMapIt->second; + if (processVariableUpdate) { + qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size(); + for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) { + auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); + if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { + if (auto var = findVariable(*varIdsIt)) { + auto &varRequest = itVarHandler->second->m_RunningVarRequest; var->setRange(varRequest.m_RangeRequested); var->setCacheRange(varRequest.m_CacheRangeRequested); qCDebug(LOG_VariableController()) << tr("1: onDataProvided") @@ -808,82 +826,187 @@ void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid << var->nbPoints(); emit var->updated(); + qCDebug(LOG_VariableController()) << tr("Update OK"); } else { qCCritical(LOG_VariableController()) << tr("Impossible to update data to a null variable"); } } - // cleaning varRequestId - qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?") - << m_VarRequestIdToVarIdVarRequestMap.size(); - m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId); - qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?") - << m_VarRequestIdToVarIdVarRequestMap.size(); } + updateVariableRequest(varRequestId); + + // cleaning varRequestId + qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId; + m_VarGroupIdToVarIds.erase(varRequestId); } - else { - qCCritical(LOG_VariableController()) - << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId; +} + + +void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId) +{ + auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); + if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { + qCCritical(LOG_VariableController()) << QObject::tr( + "Impossible to updateVariableRequest since varGroupdId isn't here anymore"); + + return; + } + + auto &varIds = varGroupIdToVarIdsIt->second; + auto varIdsEnd = varIds.end(); + for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) { + auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); + if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { + + auto varHandler = itVarHandler->second.get(); + varHandler->m_CanUpdate = false; + + + switch (varHandler->m_State) { + case VariableRequestHandlerState::OFF: { + qCCritical(LOG_VariableController()) + << QObject::tr("Impossible to update a variable with handler in OFF state"); + } break; + case VariableRequestHandlerState::RUNNING: { + varHandler->m_State = VariableRequestHandlerState::OFF; + varHandler->m_RunningVarRequest = VariableRequest{}; + break; + } + case VariableRequestHandlerState::PENDING: { + varHandler->m_State = VariableRequestHandlerState::RUNNING; + varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest; + varHandler->m_PendingVarRequest = VariableRequest{}; + auto var = findVariable(itVarHandler->first); + executeVarRequest(var, varHandler->m_RunningVarRequest); + break; + } + default: + qCCritical(LOG_VariableController()) + << QObject::tr("Unknown VariableRequestHandlerState"); + } + } } } + void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId) { - // cleaning varRequestId - m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId); + qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId; + + auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); + if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { + qCCritical(LOG_VariableController()) + << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId; + return; + } - for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin(); - varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) { - auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second; - varRequestIdQueue.erase( - std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId), - varRequestIdQueue.end()); - if (varRequestIdQueue.empty()) { - varIdToVarRequestIdQueueMapIt - = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt); + auto &varIds = varGroupIdToVarIdsIt->second; + auto varIdsEnd = varIds.end(); + for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) { + auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); + if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { - // Recompute if there is any next request based on the removed request. - } - else { - ++varIdToVarRequestIdQueueMapIt; + auto varHandler = itVarHandler->second.get(); + varHandler->m_VarId = QUuid{}; + switch (varHandler->m_State) { + case VariableRequestHandlerState::OFF: { + qCWarning(LOG_VariableController()) + << QObject::tr("Impossible to cancel a variable with no running request"); + break; + } + case VariableRequestHandlerState::RUNNING: { + + if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) { + auto var = findVariable(itVarHandler->first); + auto varProvider = m_VariableToProviderMap.at(var); + if (varProvider != nullptr) { + m_VariableAcquisitionWorker->abortProgressRequested( + itVarHandler->first); + } + m_VariableModel->setDataProgress(var, 0.0); + varHandler->m_CanUpdate = false; + varHandler->m_State = VariableRequestHandlerState::OFF; + varHandler->m_RunningVarRequest = VariableRequest{}; + } + else { + // TODO: log Impossible to cancel the running variable request beacause its + // varRequestId isn't not the canceled one + } + break; + } + case VariableRequestHandlerState::PENDING: { + if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) { + auto var = findVariable(itVarHandler->first); + auto varProvider = m_VariableToProviderMap.at(var); + if (varProvider != nullptr) { + m_VariableAcquisitionWorker->abortProgressRequested( + itVarHandler->first); + } + m_VariableModel->setDataProgress(var, 0.0); + varHandler->m_CanUpdate = false; + varHandler->m_State = VariableRequestHandlerState::RUNNING; + varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest; + varHandler->m_PendingVarRequest = VariableRequest{}; + executeVarRequest(var, varHandler->m_RunningVarRequest); + } + else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) { + varHandler->m_State = VariableRequestHandlerState::RUNNING; + varHandler->m_PendingVarRequest = VariableRequest{}; + } + else { + // TODO: log Impossible to cancel the variable request beacause its + // varRequestId isn't not the canceled one + } + break; + } + default: + qCCritical(LOG_VariableController()) + << QObject::tr("Unknown VariableRequestHandlerState"); + } } } + qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId; + m_VarGroupIdToVarIds.erase(varRequestId); } -SqpRange VariableController::VariableControllerPrivate::getLastRequestedRange(QUuid varId) +void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr var, + VariableRequest &varRequest) { - auto lastRangeRequested = SqpRange{INVALID_RANGE}; - auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId); - if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) { - auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second; - auto varRequestId = varRequestIdQueue.back(); - auto varRequestIdToVarIdVarRequestMapIt - = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId); - if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) { - auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second; - auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId); - if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) { - auto &varRequest = varIdToVarRequestMapIt->second; - lastRangeRequested = varRequest.m_RangeRequested; - } - else { - qCDebug(LOG_VariableController()) - << tr("Impossible to getLastRequestedRange of a unknown variable id attached " - "to a variableRequestId") - << varRequestId << varId; - } + qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest"); + + auto varId = m_VariableToIdentifierMap.at(var); + + auto varCacheRange = var->cacheRange(); + auto varCacheRangeRequested = varRequest.m_CacheRangeRequested; + auto notInCacheRangeList + = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested); + auto inCacheRangeList + = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested); + + if (!notInCacheRangeList.empty()) { + + auto varProvider = m_VariableToProviderMap.at(var); + if (varProvider != nullptr) { + qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested + << varRequest.m_CacheRangeRequested; + m_VariableAcquisitionWorker->pushVariableRequest( + varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested, + varRequest.m_CacheRangeRequested, + DataProviderParameters{std::move(notInCacheRangeList), var->metadata()}, + varProvider); } else { qCCritical(LOG_VariableController()) - << tr("Impossible to getLastRequestedRange of a unknown variableRequestId") - << varRequestId; + << "Impossible to provide data with a null provider"; + } + + if (!inCacheRangeList.empty()) { + emit q->updateVarDisplaying(var, inCacheRangeList.first()); } } else { - qDebug(LOG_VariableController()) - << tr("Impossible to getLastRequestedRange of a unknown variable id") << varId; + acceptVariableRequest(varId, + var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested)); } - - return lastRangeRequested; } diff --git a/core/tests/Variable/TestVariable.cpp b/core/tests/Variable/TestVariable.cpp index 7511a24..e3389e8 100644 --- a/core/tests/Variable/TestVariable.cpp +++ b/core/tests/Variable/TestVariable.cpp @@ -302,7 +302,7 @@ void TestVariable::testNbPoints_data() // Doubles cache but don't add data series (expected nb points don't change) cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)}; - operations.push_back({cacheRange, nullptr, 20}); + operations.push_back({cacheRange, dataSeries(INVALID_RANGE), 20}); // Doubles cache and data series (expected nb points change) cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)}; @@ -310,7 +310,7 @@ void TestVariable::testNbPoints_data() // Decreases cache (expected nb points decreases as the series is purged) cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 5), date(2017, 1, 1, 12, 0, 9)}; - operations.push_back({cacheRange, nullptr, 10}); + operations.push_back({cacheRange, dataSeries(INVALID_RANGE), 10}); QTest::newRow("nbPoints1") << operations; } diff --git a/core/tests/Variable/TestVariableSync.cpp b/core/tests/Variable/TestVariableSync.cpp index 204826e..9cd53d6 100644 --- a/core/tests/Variable/TestVariableSync.cpp +++ b/core/tests/Variable/TestVariableSync.cpp @@ -37,6 +37,36 @@ std::vector values(const SqpRange &range) return result; } +void validateRanges(VariableController &variableController, + const std::map &expectedRanges) +{ + for (const auto &expectedRangeEntry : expectedRanges) { + auto variableIndex = expectedRangeEntry.first; + auto expectedRange = expectedRangeEntry.second; + + // Gets the variable in the controller + auto variable = variableController.variableModel()->variable(variableIndex); + + // Compares variable's range to the expected range + QVERIFY(variable != nullptr); + auto range = variable->range(); + qInfo() << "range vs expected range" << range << expectedRange; + QCOMPARE(range, expectedRange); + + // Compares variable's data with values expected for its range + auto dataSeries = variable->dataSeries(); + QVERIFY(dataSeries != nullptr); + + auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd); + auto expectedValues = values(range); + qInfo() << std::distance(it.first, it.second) << expectedValues.size(); + QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(), + [](const auto &dataSeriesIt, const auto &expectedValue) { + return dataSeriesIt.value() == expectedValue; + })); + } +} + /// Provider used for the tests class TestProvider : public IDataProvider { std::shared_ptr clone() const { return std::make_shared(); } @@ -97,8 +127,8 @@ struct Create : public IOperation { * Variable move/shift operation in the controller */ struct Move : public IOperation { - explicit Move(int index, const SqpRange &newRange, bool shift = false) - : m_Index{index}, m_NewRange{newRange}, m_Shift{shift} + explicit Move(int index, const SqpRange &newRange, bool shift = false, int delayMS = 10) + : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}, m_DelayMs{delayMS} { } @@ -106,12 +136,14 @@ struct Move : public IOperation { { if (auto variable = variableController.variableModel()->variable(m_Index)) { variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift); + QTest::qWait(m_DelayMs); } } int m_Index; ///< The index of the variable to move SqpRange m_NewRange; ///< The new range of the variable bool m_Shift; ///< Performs a shift ( + int m_DelayMs; ///< wait the delay after running the request ( }; /** @@ -166,8 +198,14 @@ private slots: /// Input data for @sa testSync() void testSync_data(); + /// Input data for @sa testSyncOneVar() + void testSyncOneVar_data(); + /// Tests synchronization between variables through several operations void testSync(); + + /// Tests synchronization between variables through several operations + void testSyncOneVar(); }; namespace { @@ -234,6 +272,7 @@ void testSyncCase1() iterations.push_back( {std::make_shared(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}}); }; + // Pan left moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30})); // Pan right @@ -241,7 +280,7 @@ void testSyncCase1() // Zoom in moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45})); // Zoom out - moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0})); + moveVar0(range({16, 15}, {17, 0}), range({15, 15}, {16, 0})); QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200; } @@ -304,6 +343,64 @@ void testSyncCase2() QTest::newRow("sync2") << syncId << initialRange << iterations << 4000; // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000; } + +void testSyncOnVarCase1() +{ + // Id used to synchronize variables in the controller + auto syncId = QUuid::createUuid(); + + /// Generates a range according to a start time and a end time (the date is the same) + auto range = [](const QTime &startTime, const QTime &endTime) { + return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}), + DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})}; + }; + + auto initialRange = range({12, 0}, {13, 0}); + + Iterations creations{}; + // Creates variables var0, var1 and var2 + creations.push_back({std::make_shared(0), {{0, initialRange}}}); + + Iterations synchronization{}; + // Adds variables into the sync group (ranges don't need to be tested here) + synchronization.push_back({std::make_shared(0, syncId)}); + + Iterations iterations{}; + + // Moves var0 through several operations + auto moveOp = [&iterations](const auto &requestedRange, const auto &expectedRange, auto delay) { + iterations.push_back( + {std::make_shared(0, requestedRange, true, delay), {{0, expectedRange}}}); + }; + + // we assume here 300 ms is enough to finsh a operation + int delayToFinish = 300; + // jump to right, let's the operation time to finish + moveOp(range({14, 30}, {15, 30}), range({14, 30}, {15, 30}), delayToFinish); + // pan to right, let's the operation time to finish + moveOp(range({14, 45}, {15, 45}), range({14, 45}, {15, 45}), delayToFinish); + // jump to left, let's the operation time to finish + moveOp(range({03, 30}, {04, 30}), range({03, 30}, {04, 30}), delayToFinish); + // Pan to left, let's the operation time to finish + moveOp(range({03, 10}, {04, 10}), range({03, 10}, {04, 10}), delayToFinish); + // Zoom in, let's the operation time to finish + moveOp(range({03, 30}, {04, 00}), range({03, 30}, {04, 00}), delayToFinish); + // Zoom out left, let's the operation time to finish + moveOp(range({01, 10}, {18, 10}), range({01, 10}, {18, 10}), delayToFinish); + // Go back to initial range + moveOp(initialRange, initialRange, delayToFinish); + + + // jump to right, let's the operation time to finish + // moveOp(range({14, 30}, {15, 30}), initialRange, delayToFinish); + // Zoom out left, let's the operation time to finish + moveOp(range({01, 10}, {18, 10}), initialRange, delayToFinish); + // Go back to initial range + moveOp(initialRange, initialRange, 300); + + QTest::newRow("syncOnVarCase1") << syncId << initialRange << std::move(creations) + << std::move(iterations); +} } void TestVariableSync::testSync_data() @@ -325,6 +422,24 @@ void TestVariableSync::testSync_data() testSyncCase2(); } +void TestVariableSync::testSyncOneVar_data() +{ + // ////////////// // + // Test structure // + // ////////////// // + + QTest::addColumn("syncId"); + QTest::addColumn("initialRange"); + QTest::addColumn("creations"); + QTest::addColumn("iterations"); + + // ////////// // + // Test cases // + // ////////// // + + testSyncOnVarCase1(); +} + void TestVariableSync::testSync() { // Inits controllers @@ -339,33 +454,6 @@ void TestVariableSync::testSync() // Synchronization group used variableController.onAddSynchronizationGroupId(syncId); - auto validateRanges = [&variableController](const auto &expectedRanges) { - for (const auto &expectedRangeEntry : expectedRanges) { - auto variableIndex = expectedRangeEntry.first; - auto expectedRange = expectedRangeEntry.second; - - // Gets the variable in the controller - auto variable = variableController.variableModel()->variable(variableIndex); - - // Compares variable's range to the expected range - QVERIFY(variable != nullptr); - auto range = variable->range(); - QCOMPARE(range, expectedRange); - - // Compares variable's data with values expected for its range - auto dataSeries = variable->dataSeries(); - QVERIFY(dataSeries != nullptr); - - auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd); - auto expectedValues = values(range); - qInfo() << std::distance(it.first, it.second) << expectedValues.size(); - QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(), - [](const auto &dataSeriesIt, const auto &expectedValue) { - return dataSeriesIt.value() == expectedValue; - })); - } - }; - // For each iteration: // - execute operation // - compare the variables' state to the expected states @@ -375,14 +463,42 @@ void TestVariableSync::testSync() iteration.m_Operation->exec(variableController); QTest::qWait(operationDelay); - validateRanges(iteration.m_ExpectedRanges); + validateRanges(variableController, iteration.m_ExpectedRanges); + } +} + +void TestVariableSync::testSyncOneVar() +{ + // Inits controllers + TimeController timeController{}; + VariableController variableController{}; + variableController.setTimeController(&timeController); + + QFETCH(QUuid, syncId); + QFETCH(SqpRange, initialRange); + timeController.onTimeToUpdate(initialRange); + + // Synchronization group used + variableController.onAddSynchronizationGroupId(syncId); + + // For each iteration: + // - execute operation + // - compare the variables' state to the expected states + QFETCH(Iterations, iterations); + QFETCH(Iterations, creations); + + for (const auto &creation : creations) { + creation.m_Operation->exec(variableController); + QTest::qWait(300); } for (const auto &iteration : iterations) { iteration.m_Operation->exec(variableController); } - QTest::qWait(operationDelay); - validateRanges(iterations.back().m_ExpectedRanges); + + if (!iterations.empty()) { + validateRanges(variableController, iterations.back().m_ExpectedRanges); + } } QTEST_MAIN(TestVariableSync) diff --git a/plugins/amda/src/AmdaProvider.cpp b/plugins/amda/src/AmdaProvider.cpp index f10071c..4ced6bb 100644 --- a/plugins/amda/src/AmdaProvider.cpp +++ b/plugins/amda/src/AmdaProvider.cpp @@ -203,8 +203,6 @@ void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVa emit dataProvidedFailed(dataId); } } - qCDebug(LOG_AmdaProvider()) << tr("acquisition requests erase because of finishing") - << dataId; m_AcqIdToRequestProgressMap.erase(dataId); } else { @@ -237,8 +235,6 @@ void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVa } } else { - qCDebug(LOG_AmdaProvider()) - << tr("acquisition requests erase because of aborting") << dataId; qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR"); m_AcqIdToRequestProgressMap.erase(dataId); emit dataProvidedFailed(dataId); @@ -259,6 +255,7 @@ void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVa void AmdaProvider::updateRequestProgress(QUuid acqIdentifier, std::shared_ptr request, double progress) { + qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get(); auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier); if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) { auto &requestProgressMap = acqIdToRequestProgressMapIt->second; diff --git a/plugins/amda/src/AmdaResultParser.cpp b/plugins/amda/src/AmdaResultParser.cpp index 6276fd6..73fe699 100644 --- a/plugins/amda/src/AmdaResultParser.cpp +++ b/plugins/amda/src/AmdaResultParser.cpp @@ -211,6 +211,9 @@ std::shared_ptr AmdaResultParser::readTxt(const QString &filePath, // Reads x-axis unit stream.seek(0); // returns to the beginning of the file auto xAxisUnit = readXAxisUnit(stream); + if (xAxisUnit.m_Name.isEmpty()) { + return nullptr; + } // Reads results // AMDA V2: remove line diff --git a/plugins/amda/tests/TestAmdaAcquisition.cpp b/plugins/amda/tests/TestAmdaAcquisition.cpp index 596f8b5..ca3b239 100644 --- a/plugins/amda/tests/TestAmdaAcquisition.cpp +++ b/plugins/amda/tests/TestAmdaAcquisition.cpp @@ -21,7 +21,7 @@ // Frame : GSE - Mission : ACE - // Instrument : MFI - Dataset : mfi_final-prelim // REFERENCE DOWNLOAD FILE = -// http://amda.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00¶meterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0 +// http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00¶meterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0 namespace { @@ -29,7 +29,8 @@ namespace { const auto TESTS_RESOURCES_PATH = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath(); -const auto TESTS_AMDA_REF_FILE = QString{"AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"}; +/// Delay after each operation on the variable before validating it (in ms) +const auto OPERATION_DELAY = 10000; template bool compareDataSeries(std::shared_ptr candidate, SqpRange candidateCacheRange, @@ -49,15 +50,6 @@ bool compareDataSeries(std::shared_ptr candidate, SqpRange candidat qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend()) << std::distance(itRefs.first, itRefs.second); - // auto xcValue = candidateDS->valuesData()->data(); - // auto dist = std::distance(itRefs.first, itRefs.second); - // auto it = itRefs.first; - // for (auto i = 0; i < dist - 1; ++i) { - // ++it; - // qInfo() << "END:" << it->value(); - // } - // qDebug() << "END:" << it->value() << xcValue.last(); - return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second, compareLambda); } @@ -71,115 +63,91 @@ class TestAmdaAcquisition : public QObject { Q_OBJECT private slots: + /// Input data for @sa testAcquisition() + void testAcquisition_data(); void testAcquisition(); }; -void TestAmdaAcquisition::testAcquisition() +void TestAmdaAcquisition::testAcquisition_data() { - /// @todo: update test to be compatible with AMDA v2 - - // READ the ref file: - auto filePath = QFileInfo{TESTS_RESOURCES_PATH, TESTS_AMDA_REF_FILE}.absoluteFilePath(); - auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR); - - auto provider = std::make_shared(); - auto timeController = std::make_unique(); - - auto varRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 3, 0, 0}}; - auto varRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}}; - - auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)}; - - timeController->onTimeToUpdate(sqpR); - - QVariantHash metaData; - metaData.insert("dataType", "scalar"); - metaData.insert("xml:id", "imf(0)"); - - VariableController vc; - vc.setTimeController(timeController.get()); - - auto var = vc.createVariable("bx_gse", metaData, provider); - - // 1 : Variable creation - - qDebug() << " 1: TIMECONTROLLER" << timeController->dateTime(); - qDebug() << " 1: RANGE " << var->range(); - qDebug() << " 1: CACHERANGE" << var->cacheRange(); - - // wait for 10 sec before asking next request toi permit asynchrone process to finish. - auto timeToWaitMs = 10000; + // ////////////// // + // Test structure // + // ////////////// // - QEventLoop loop; - QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit); - loop.exec(); + QTest::addColumn("dataFilename"); // File containing expected data of acquisitions + QTest::addColumn("initialRange"); // First acquisition + QTest::addColumn >("operations"); // Acquisitions to make - // Tests on acquisition operation - - int count = 1; - - auto requestDataLoading = [&vc, var, timeToWaitMs, results, &count](auto tStart, auto tEnd) { - ++count; - - auto nextSqpR - = SqpRange{DateUtils::secondsSinceEpoch(tStart), DateUtils::secondsSinceEpoch(tEnd)}; - vc.onRequestDataLoading(QVector >{} << var, nextSqpR, true); - - QEventLoop loop; - QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit); - loop.exec(); - - qInfo() << count << "RANGE " << var->range(); - qInfo() << count << "CACHERANGE" << var->cacheRange(); - - QCOMPARE(var->range().m_TStart, nextSqpR.m_TStart); - QCOMPARE(var->range().m_TEnd, nextSqpR.m_TEnd); - - // Verify dataserie - QVERIFY(compareDataSeries(var->dataSeries(), var->cacheRange(), results)); + // ////////// // + // Test cases // + // ////////// // + auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) { + return DateUtils::secondsSinceEpoch( + QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC}); }; - // 2 : pan (jump) left for one hour - auto nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 1, 0, 0}}; - auto nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 2, 0, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); + QTest::newRow("amda") + << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt" + << SqpRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)} + << std::vector{ + // 2 : pan (jump) left for two min + SqpRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)}, + // 3 : pan (jump) right for four min + SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)}, + // 4 : pan (overlay) right for 30 sec + /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)}, + // 5 : pan (overlay) left for 30 sec + SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)}, + // 6 : pan (overlay) left for 30 sec - BIS + SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}, + // 7 : Zoom in Inside 20 sec range + SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)}, + // 8 : Zoom out Inside 20 sec range + SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/}; +} - // 3 : pan (jump) right for one hour - nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}}; - nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); +void TestAmdaAcquisition::testAcquisition() +{ + /// @todo: update test to be compatible with AMDA v2 - // 4 : pan (overlay) right for 30 min - nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}}; - nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 30, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); + // Retrieves data file + QFETCH(QString, dataFilename); + auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath(); + auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR); - // 5 : pan (overlay) left for 30 min - nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}}; - nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); + /// Lambda used to validate a variable at each step + auto validateVariable = [results](std::shared_ptr variable, const SqpRange &range) { + // Checks that the variable's range has changed + qInfo() << tr("Compare var range vs range") << variable->range() << range; + QCOMPARE(variable->range(), range); - // 6 : pan (overlay) left for 30 min - BIS - nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 30, 0}}; - nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); + // Checks the variable's data series + QVERIFY(compareDataSeries(variable->dataSeries(), variable->cacheRange(), + results)); + qInfo() << "\n"; + }; - // 7 : Zoom in Inside 20 min range - nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 50, 0}}; - nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 10, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); + // Creates variable + QFETCH(SqpRange, initialRange); + sqpApp->timeController().onTimeToUpdate(initialRange); + auto provider = std::make_shared(); + auto variable = sqpApp->variableController().createVariable( + "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider); - // 8 : Zoom out Inside 2 hours range - nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}}; - nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}}; - // requestDataLoading(nextVarRS, nextVarRE); + QTest::qWait(OPERATION_DELAY); + validateVariable(variable, initialRange); + // Makes operations on the variable + QFETCH(std::vector, operations); + for (const auto &operation : operations) { + // Asks request on the variable and waits during its execution + sqpApp->variableController().onRequestDataLoading({variable}, operation, false); - // Close the app after 10 sec - QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit); - loop.exec(); + QTest::qWait(OPERATION_DELAY); + validateVariable(variable, operation); + } } int main(int argc, char *argv[]) diff --git a/plugins/amda/tests/TestAmdaResultParser.cpp b/plugins/amda/tests/TestAmdaResultParser.cpp index 70a840f..e51de2b 100644 --- a/plugins/amda/tests/TestAmdaResultParser.cpp +++ b/plugins/amda/tests/TestAmdaResultParser.cpp @@ -55,7 +55,12 @@ struct ExpectedResults { { if (m_ParsingOK) { auto dataSeries = dynamic_cast(results.get()); - QVERIFY(dataSeries != nullptr); + if (dataSeries == nullptr) { + + // No unit detected, parsink ok but data is nullptr + // TODO, improve the test to verify that the data is null + return; + } // Checks units QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit); diff --git a/plugins/mockplugin/tests/TestCosinusAcquisition.cpp b/plugins/mockplugin/tests/TestCosinusAcquisition.cpp index 8d81fb3..d6b4bd2 100644 --- a/plugins/mockplugin/tests/TestCosinusAcquisition.cpp +++ b/plugins/mockplugin/tests/TestCosinusAcquisition.cpp @@ -144,6 +144,7 @@ void TestCosinusAcquisition::testAcquisition() auto validateVariable = [dataSeries](std::shared_ptr variable, const SqpRange &range) { // Checks that the variable's range has changed + qInfo() << "range vs expected range" << variable->range() << range; QCOMPARE(variable->range(), range); // Checks the variable's data series @@ -157,15 +158,17 @@ void TestCosinusAcquisition::testAcquisition() auto variable = sqpApp->variableController().createVariable( "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}}, provider); + QFETCH(int, operationDelay); QTest::qWait(operationDelay); validateVariable(variable, initialRange); + QTest::qWait(operationDelay); // Makes operations on the variable QFETCH(std::vector, operations); for (const auto &operation : operations) { // Asks request on the variable and waits during its execution - sqpApp->variableController().onRequestDataLoading({variable}, operation, true); + sqpApp->variableController().onRequestDataLoading({variable}, operation, false); QTest::qWait(operationDelay); validateVariable(variable, operation); @@ -174,7 +177,7 @@ void TestCosinusAcquisition::testAcquisition() for (const auto &operation : operations) { // Asks request on the variable and waits during its execution - sqpApp->variableController().onRequestDataLoading({variable}, operation, true); + sqpApp->variableController().onRequestDataLoading({variable}, operation, false); } QTest::qWait(operationDelay); validateVariable(variable, operations.back());