##// END OF EJS Templates
Merge pull request 312 from SciQLop-fork develop...
perrinel -
r836:764a72d1e238 merge
parent child
Show More
@@ -1,28 +1,26
1 #ifndef SCIQLOP_VARIABLEREQUEST_H
1 #ifndef SCIQLOP_VARIABLEREQUEST_H
2 #define SCIQLOP_VARIABLEREQUEST_H
2 #define SCIQLOP_VARIABLEREQUEST_H
3
3
4 #include <QObject>
4 #include <QObject>
5
5
6 #include <QUuid>
6 #include <QUuid>
7
7
8 #include <Common/MetaTypes.h>
8 #include <Common/MetaTypes.h>
9 #include <Data/IDataSeries.h>
9 #include <Data/IDataSeries.h>
10 #include <Data/SqpRange.h>
10 #include <Data/SqpRange.h>
11
11
12 #include <memory>
12 #include <memory>
13
13
14 /**
14 /**
15 * @brief The VariableRequest struct holds the information of an acquisition request
15 * @brief The VariableRequest struct holds the information of an acquisition request
16 */
16 */
17 struct VariableRequest {
17 struct VariableRequest {
18 VariableRequest() { m_CanUpdate = false; }
18 QUuid m_VariableGroupId;
19
20 SqpRange m_RangeRequested;
19 SqpRange m_RangeRequested;
21 SqpRange m_CacheRangeRequested;
20 SqpRange m_CacheRangeRequested;
22 std::shared_ptr<IDataSeries> m_DataSeries;
21 std::shared_ptr<IDataSeries> m_DataSeries;
23 bool m_CanUpdate;
24 };
22 };
25
23
26 SCIQLOP_REGISTER_META_TYPE(VARIABLEREQUEST_REGISTRY, VariableRequest)
24 SCIQLOP_REGISTER_META_TYPE(VARIABLEREQUEST_REGISTRY, VariableRequest)
27
25
28 #endif // SCIQLOP_VARIABLEREQUEST_H
26 #endif // SCIQLOP_VARIABLEREQUEST_H
@@ -1,416 +1,416
1 #include "Variable/VariableAcquisitionWorker.h"
1 #include "Variable/VariableAcquisitionWorker.h"
2
2
3 #include "Variable/Variable.h"
3 #include "Variable/Variable.h"
4
4
5 #include <Data/AcquisitionRequest.h>
5 #include <Data/AcquisitionRequest.h>
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <unordered_map>
8 #include <unordered_map>
9 #include <utility>
9 #include <utility>
10
10
11 #include <QMutex>
11 #include <QMutex>
12 #include <QReadWriteLock>
12 #include <QReadWriteLock>
13 #include <QThread>
13 #include <QThread>
14
14
15 #include <cmath>
15 #include <cmath>
16
16
17 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
17 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
18
18
19 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
19 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
20
20
21 explicit VariableAcquisitionWorkerPrivate(VariableAcquisitionWorker *parent)
21 explicit VariableAcquisitionWorkerPrivate(VariableAcquisitionWorker *parent)
22 : m_Lock{QReadWriteLock::Recursive}, q{parent}
22 : m_Lock{QReadWriteLock::Recursive}, q{parent}
23 {
23 {
24 }
24 }
25
25
26 void lockRead() { m_Lock.lockForRead(); }
26 void lockRead() { m_Lock.lockForRead(); }
27 void lockWrite() { m_Lock.lockForWrite(); }
27 void lockWrite() { m_Lock.lockForWrite(); }
28 void unlock() { m_Lock.unlock(); }
28 void unlock() { m_Lock.unlock(); }
29
29
30 void removeVariableRequest(QUuid vIdentifier);
30 void removeVariableRequest(QUuid vIdentifier);
31
31
32 /// Remove the current request and execute the next one if exist
32 /// Remove the current request and execute the next one if exist
33 void updateToNextRequest(QUuid vIdentifier);
33 void updateToNextRequest(QUuid vIdentifier);
34
34
35 /// Remove and/or abort all AcqRequest in link with varRequestId
35 /// Remove and/or abort all AcqRequest in link with varRequestId
36 void cancelVarRequest(QUuid varRequestId);
36 void cancelVarRequest(QUuid varRequestId);
37 void removeAcqRequest(QUuid acqRequestId);
37 void removeAcqRequest(QUuid acqRequestId);
38
38
39 QMutex m_WorkingMutex;
39 QMutex m_WorkingMutex;
40 QReadWriteLock m_Lock;
40 QReadWriteLock m_Lock;
41
41
42 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
42 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
43 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
43 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
44 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
44 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
45 VariableAcquisitionWorker *q;
45 VariableAcquisitionWorker *q;
46 };
46 };
47
47
48
48
49 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
49 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
50 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
50 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
51 {
51 {
52 }
52 }
53
53
54 VariableAcquisitionWorker::~VariableAcquisitionWorker()
54 VariableAcquisitionWorker::~VariableAcquisitionWorker()
55 {
55 {
56 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
56 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
57 << QThread::currentThread();
57 << QThread::currentThread();
58 this->waitForFinish();
58 this->waitForFinish();
59 }
59 }
60
60
61
61
62 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
62 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
63 SqpRange rangeRequested,
63 SqpRange rangeRequested,
64 SqpRange cacheRangeRequested,
64 SqpRange cacheRangeRequested,
65 DataProviderParameters parameters,
65 DataProviderParameters parameters,
66 std::shared_ptr<IDataProvider> provider)
66 std::shared_ptr<IDataProvider> provider)
67 {
67 {
68 qCDebug(LOG_VariableAcquisitionWorker())
68 qCDebug(LOG_VariableAcquisitionWorker())
69 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
69 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
70 auto varRequestIdCanceled = QUuid();
70 auto varRequestIdCanceled = QUuid();
71
71
72 // Request creation
72 // Request creation
73 auto acqRequest = AcquisitionRequest{};
73 auto acqRequest = AcquisitionRequest{};
74 qCDebug(LOG_VariableAcquisitionWorker()) << tr("PushVariableRequest ") << vIdentifier
74 qCDebug(LOG_VariableAcquisitionWorker()) << tr("PushVariableRequest ") << vIdentifier
75 << varRequestId;
75 << varRequestId;
76 acqRequest.m_VarRequestId = varRequestId;
76 acqRequest.m_VarRequestId = varRequestId;
77 acqRequest.m_vIdentifier = vIdentifier;
77 acqRequest.m_vIdentifier = vIdentifier;
78 acqRequest.m_DataProviderParameters = parameters;
78 acqRequest.m_DataProviderParameters = parameters;
79 acqRequest.m_RangeRequested = rangeRequested;
79 acqRequest.m_RangeRequested = rangeRequested;
80 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
80 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
81 acqRequest.m_Size = parameters.m_Times.size();
81 acqRequest.m_Size = parameters.m_Times.size();
82 acqRequest.m_Provider = provider;
82 acqRequest.m_Provider = provider;
83
83
84
84
85 // Register request
85 // Register request
86 impl->lockWrite();
86 impl->lockWrite();
87 impl->m_AcqIdentifierToAcqRequestMap.insert(
87 impl->m_AcqIdentifierToAcqRequestMap.insert(
88 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
88 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
89
89
90 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
90 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
91 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
91 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
92 // A current request already exists, we can replace the next one
92 // A current request already exists, we can replace the next one
93 auto oldAcqId = it->second.second;
93 auto oldAcqId = it->second.second;
94 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(oldAcqId);
94 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(oldAcqId);
95 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
95 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
96 auto oldAcqRequest = acqIdentifierToAcqRequestMapIt->second;
96 auto oldAcqRequest = acqIdentifierToAcqRequestMapIt->second;
97 varRequestIdCanceled = oldAcqRequest.m_VarRequestId;
97 varRequestIdCanceled = oldAcqRequest.m_VarRequestId;
98 }
98 }
99
99
100 it->second.second = acqRequest.m_AcqIdentifier;
100 it->second.second = acqRequest.m_AcqIdentifier;
101 impl->unlock();
101 impl->unlock();
102
102
103 // remove old acqIdentifier from the worker
103 // remove old acqIdentifier from the worker
104 impl->cancelVarRequest(varRequestIdCanceled);
104 impl->cancelVarRequest(varRequestIdCanceled);
105 // impl->m_AcqIdentifierToAcqRequestMap.erase(oldAcqId);
105 // impl->m_AcqIdentifierToAcqRequestMap.erase(oldAcqId);
106 }
106 }
107 else {
107 else {
108 // First request for the variable, it must be stored and executed
108 // First request for the variable, it must be stored and executed
109 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
109 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
110 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
110 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
111 impl->unlock();
111 impl->unlock();
112
112
113 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
113 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
114 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
114 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
115 }
115 }
116
116
117 return varRequestIdCanceled;
117 return varRequestIdCanceled;
118 }
118 }
119
119
120 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
120 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
121 {
121 {
122 impl->lockRead();
122 impl->lockRead();
123
123
124 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
124 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
125 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
125 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
126 auto currentAcqId = it->second.first;
126 auto currentAcqId = it->second.first;
127
127
128 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
128 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
129 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
129 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
130 auto request = it->second;
130 auto request = it->second;
131 impl->unlock();
131 impl->unlock();
132
132
133 // Remove the current request from the worker
133 // Remove the current request from the worker
134 impl->updateToNextRequest(vIdentifier);
134 impl->updateToNextRequest(vIdentifier);
135
135
136 // notify the request aborting to the provider
136 // notify the request aborting to the provider
137 request.m_Provider->requestDataAborting(currentAcqId);
137 request.m_Provider->requestDataAborting(currentAcqId);
138 }
138 }
139 else {
139 else {
140 impl->unlock();
140 impl->unlock();
141 qCWarning(LOG_VariableAcquisitionWorker())
141 qCWarning(LOG_VariableAcquisitionWorker())
142 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
142 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
143 }
143 }
144 }
144 }
145 else {
145 else {
146 impl->unlock();
146 impl->unlock();
147 }
147 }
148 }
148 }
149
149
150 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
150 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
151 double progress)
151 double progress)
152 {
152 {
153 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
153 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
154 << acqIdentifier << progress;
154 << acqIdentifier << progress;
155 impl->lockRead();
155 impl->lockRead();
156 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
156 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
157 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
157 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
158 auto currentPartSize = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
158 auto currentPartSize = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
159
159
160 auto currentPartProgress
160 auto currentPartProgress
161 = std::isnan(progress) ? 0.0 : (progress * currentPartSize) / 100.0;
161 = std::isnan(progress) ? 0.0 : (progress * currentPartSize) / 100.0;
162 auto currentAlreadyProgress = aIdToARit->second.m_Progression * currentPartSize;
162 auto currentAlreadyProgress = aIdToARit->second.m_Progression * currentPartSize;
163
163
164 auto finalProgression = currentAlreadyProgress + currentPartProgress;
164 auto finalProgression = currentAlreadyProgress + currentPartProgress;
165 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
165 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
166 qCDebug(LOG_VariableAcquisitionWorker())
166 qCDebug(LOG_VariableAcquisitionWorker())
167 << tr("TORM: onVariableRetrieveDataInProgress ")
167 << tr("TORM: onVariableRetrieveDataInProgress ")
168 << QThread::currentThread()->objectName() << aIdToARit->second.m_vIdentifier
168 << QThread::currentThread()->objectName() << aIdToARit->second.m_vIdentifier
169 << currentPartSize << currentAlreadyProgress << currentPartProgress << finalProgression;
169 << currentPartSize << currentAlreadyProgress << currentPartProgress << finalProgression;
170 if (finalProgression == 100.0) {
170 if (finalProgression == 100.0) {
171 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
171 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
172 }
172 }
173 }
173 }
174 impl->unlock();
174 impl->unlock();
175 }
175 }
176
176
177 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
177 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
178 {
178 {
179 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
179 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
180 << QThread::currentThread();
180 << QThread::currentThread();
181 impl->lockRead();
181 impl->lockRead();
182 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
182 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
183 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
183 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
184 auto request = it->second;
184 auto request = it->second;
185 impl->unlock();
185 impl->unlock();
186 qCInfo(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
186 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
187 << acqIdentifier << request.m_vIdentifier
187 << acqIdentifier << request.m_vIdentifier
188 << QThread::currentThread();
188 << QThread::currentThread();
189 emit variableCanceledRequested(request.m_vIdentifier);
189 emit variableCanceledRequested(request.m_vIdentifier);
190 }
190 }
191 else {
191 else {
192 impl->unlock();
192 impl->unlock();
193 // TODO log no acqIdentifier recognized
193 // TODO log no acqIdentifier recognized
194 }
194 }
195 }
195 }
196
196
197 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
197 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
198 std::shared_ptr<IDataSeries> dataSeries,
198 std::shared_ptr<IDataSeries> dataSeries,
199 SqpRange dataRangeAcquired)
199 SqpRange dataRangeAcquired)
200 {
200 {
201 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
201 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
202 << acqIdentifier << dataRangeAcquired;
202 << acqIdentifier << dataRangeAcquired;
203 impl->lockWrite();
203 impl->lockWrite();
204 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
204 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
205 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
205 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
206 // Store the result
206 // Store the result
207 auto dataPacket = AcquisitionDataPacket{};
207 auto dataPacket = AcquisitionDataPacket{};
208 dataPacket.m_Range = dataRangeAcquired;
208 dataPacket.m_Range = dataRangeAcquired;
209 dataPacket.m_DateSeries = dataSeries;
209 dataPacket.m_DateSeries = dataSeries;
210
210
211 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
211 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
212 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
212 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
213 // A current request result already exists, we can update it
213 // A current request result already exists, we can update it
214 aIdToADPVit->second.push_back(dataPacket);
214 aIdToADPVit->second.push_back(dataPacket);
215 }
215 }
216 else {
216 else {
217 // First request result for the variable, it must be stored
217 // First request result for the variable, it must be stored
218 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
218 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
219 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
219 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
220 }
220 }
221
221
222
222
223 // Decrement the counter of the request
223 // Decrement the counter of the request
224 auto &acqRequest = aIdToARit->second;
224 auto &acqRequest = aIdToARit->second;
225 acqRequest.m_Progression = acqRequest.m_Progression + 1;
225 acqRequest.m_Progression = acqRequest.m_Progression + 1;
226
226
227 // if the counter is 0, we can return data then run the next request if it exists and
227 // if the counter is 0, we can return data then run the next request if it exists and
228 // removed the finished request
228 // removed the finished request
229 if (acqRequest.m_Size == acqRequest.m_Progression) {
229 if (acqRequest.m_Size == acqRequest.m_Progression) {
230 auto varId = acqRequest.m_vIdentifier;
230 auto varId = acqRequest.m_vIdentifier;
231 auto rangeRequested = acqRequest.m_RangeRequested;
231 auto rangeRequested = acqRequest.m_RangeRequested;
232 auto cacheRangeRequested = acqRequest.m_CacheRangeRequested;
232 auto cacheRangeRequested = acqRequest.m_CacheRangeRequested;
233 // Return the data
233 // Return the data
234 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
234 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
235 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
235 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
236 emit dataProvided(varId, rangeRequested, cacheRangeRequested, aIdToADPVit->second);
236 emit dataProvided(varId, rangeRequested, cacheRangeRequested, aIdToADPVit->second);
237 }
237 }
238 impl->unlock();
238 impl->unlock();
239
239
240 // Update to the next request
240 // Update to the next request
241 impl->updateToNextRequest(acqRequest.m_vIdentifier);
241 impl->updateToNextRequest(acqRequest.m_vIdentifier);
242 }
242 }
243 else {
243 else {
244 impl->unlock();
244 impl->unlock();
245 }
245 }
246 }
246 }
247 else {
247 else {
248 impl->unlock();
248 impl->unlock();
249 qCWarning(LOG_VariableAcquisitionWorker())
249 qCWarning(LOG_VariableAcquisitionWorker())
250 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
250 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
251 }
251 }
252 }
252 }
253
253
254 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
254 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
255 {
255 {
256 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
256 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
257 impl->lockRead();
257 impl->lockRead();
258 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
258 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
259 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
259 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
260 auto request = it->second;
260 auto request = it->second;
261 impl->unlock();
261 impl->unlock();
262 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
262 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
263 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
263 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
264 }
264 }
265 else {
265 else {
266 impl->unlock();
266 impl->unlock();
267 // TODO log no acqIdentifier recognized
267 // TODO log no acqIdentifier recognized
268 }
268 }
269 }
269 }
270
270
271 void VariableAcquisitionWorker::initialize()
271 void VariableAcquisitionWorker::initialize()
272 {
272 {
273 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
273 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
274 << QThread::currentThread();
274 << QThread::currentThread();
275 impl->m_WorkingMutex.lock();
275 impl->m_WorkingMutex.lock();
276 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
276 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
277 }
277 }
278
278
279 void VariableAcquisitionWorker::finalize()
279 void VariableAcquisitionWorker::finalize()
280 {
280 {
281 impl->m_WorkingMutex.unlock();
281 impl->m_WorkingMutex.unlock();
282 }
282 }
283
283
284 void VariableAcquisitionWorker::waitForFinish()
284 void VariableAcquisitionWorker::waitForFinish()
285 {
285 {
286 QMutexLocker locker{&impl->m_WorkingMutex};
286 QMutexLocker locker{&impl->m_WorkingMutex};
287 }
287 }
288
288
289 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
289 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
290 QUuid vIdentifier)
290 QUuid vIdentifier)
291 {
291 {
292 lockWrite();
292 lockWrite();
293 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
293 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
294
294
295 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
295 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
296 // A current request already exists, we can replace the next one
296 // A current request already exists, we can replace the next one
297
297
298 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
298 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
299 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
299 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
300
300
301 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
301 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
302 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
302 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
303 }
303 }
304 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
304 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
305 unlock();
305 unlock();
306 }
306 }
307
307
308 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::updateToNextRequest(
308 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::updateToNextRequest(
309 QUuid vIdentifier)
309 QUuid vIdentifier)
310 {
310 {
311 lockRead();
311 lockRead();
312 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
312 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
313 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
313 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
314 if (it->second.second.isNull()) {
314 if (it->second.second.isNull()) {
315 unlock();
315 unlock();
316 // There is no next request, we can remove the variable request
316 // There is no next request, we can remove the variable request
317 removeVariableRequest(vIdentifier);
317 removeVariableRequest(vIdentifier);
318 }
318 }
319 else {
319 else {
320 auto acqIdentifierToRemove = it->second.first;
320 auto acqIdentifierToRemove = it->second.first;
321 // Move the next request to the current request
321 // Move the next request to the current request
322 auto nextRequestId = it->second.second;
322 auto nextRequestId = it->second.second;
323 it->second.first = nextRequestId;
323 it->second.first = nextRequestId;
324 it->second.second = QUuid();
324 it->second.second = QUuid();
325 unlock();
325 unlock();
326 // Remove AcquisitionRequest and results;
326 // Remove AcquisitionRequest and results;
327 lockWrite();
327 lockWrite();
328 m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
328 m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
329 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
329 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
330 unlock();
330 unlock();
331 // Execute the current request
331 // Execute the current request
332 QMetaObject::invokeMethod(q, "onExecuteRequest", Qt::QueuedConnection,
332 QMetaObject::invokeMethod(q, "onExecuteRequest", Qt::QueuedConnection,
333 Q_ARG(QUuid, nextRequestId));
333 Q_ARG(QUuid, nextRequestId));
334 }
334 }
335 }
335 }
336 else {
336 else {
337 unlock();
337 unlock();
338 qCCritical(LOG_VariableAcquisitionWorker())
338 qCCritical(LOG_VariableAcquisitionWorker())
339 << tr("Impossible to execute the acquisition on an unfound variable ");
339 << tr("Impossible to execute the acquisition on an unfound variable ");
340 }
340 }
341 }
341 }
342
342
343 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::cancelVarRequest(
343 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::cancelVarRequest(
344 QUuid varRequestId)
344 QUuid varRequestId)
345 {
345 {
346 qCDebug(LOG_VariableAcquisitionWorker())
346 qCDebug(LOG_VariableAcquisitionWorker())
347 << "VariableAcquisitionWorkerPrivate::cancelVarRequest 0";
347 << "VariableAcquisitionWorkerPrivate::cancelVarRequest 0";
348 lockRead();
348 lockRead();
349 // get all AcqIdentifier in link with varRequestId
349 // get all AcqIdentifier in link with varRequestId
350 QVector<QUuid> acqIdsToRm;
350 QVector<QUuid> acqIdsToRm;
351 auto cend = m_AcqIdentifierToAcqRequestMap.cend();
351 auto cend = m_AcqIdentifierToAcqRequestMap.cend();
352 for (auto it = m_AcqIdentifierToAcqRequestMap.cbegin(); it != cend; ++it) {
352 for (auto it = m_AcqIdentifierToAcqRequestMap.cbegin(); it != cend; ++it) {
353 if (it->second.m_VarRequestId == varRequestId) {
353 if (it->second.m_VarRequestId == varRequestId) {
354 acqIdsToRm << it->first;
354 acqIdsToRm << it->first;
355 }
355 }
356 }
356 }
357 unlock();
357 unlock();
358 // run aborting or removing of acqIdsToRm
358 // run aborting or removing of acqIdsToRm
359
359
360 for (auto acqId : acqIdsToRm) {
360 for (auto acqId : acqIdsToRm) {
361 removeAcqRequest(acqId);
361 removeAcqRequest(acqId);
362 }
362 }
363 qCDebug(LOG_VariableAcquisitionWorker())
363 qCDebug(LOG_VariableAcquisitionWorker())
364 << "VariableAcquisitionWorkerPrivate::cancelVarRequest end";
364 << "VariableAcquisitionWorkerPrivate::cancelVarRequest end";
365 }
365 }
366
366
367 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeAcqRequest(
367 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeAcqRequest(
368 QUuid acqRequestId)
368 QUuid acqRequestId)
369 {
369 {
370 qCDebug(LOG_VariableAcquisitionWorker())
370 qCDebug(LOG_VariableAcquisitionWorker())
371 << "VariableAcquisitionWorkerPrivate::removeAcqRequest";
371 << "VariableAcquisitionWorkerPrivate::removeAcqRequest";
372 QUuid vIdentifier;
372 QUuid vIdentifier;
373 std::shared_ptr<IDataProvider> provider;
373 std::shared_ptr<IDataProvider> provider;
374 lockRead();
374 lockRead();
375 auto acqIt = m_AcqIdentifierToAcqRequestMap.find(acqRequestId);
375 auto acqIt = m_AcqIdentifierToAcqRequestMap.find(acqRequestId);
376 if (acqIt != m_AcqIdentifierToAcqRequestMap.cend()) {
376 if (acqIt != m_AcqIdentifierToAcqRequestMap.cend()) {
377 vIdentifier = acqIt->second.m_vIdentifier;
377 vIdentifier = acqIt->second.m_vIdentifier;
378 provider = acqIt->second.m_Provider;
378 provider = acqIt->second.m_Provider;
379
379
380 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
380 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
381 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
381 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
382 if (it->second.first == acqRequestId) {
382 if (it->second.first == acqRequestId) {
383 // acqRequest is currently running -> let's aborting it
383 // acqRequest is currently running -> let's aborting it
384 unlock();
384 unlock();
385
385
386 // Remove the current request from the worker
386 // Remove the current request from the worker
387 updateToNextRequest(vIdentifier);
387 updateToNextRequest(vIdentifier);
388
388
389 // notify the request aborting to the provider
389 // notify the request aborting to the provider
390 provider->requestDataAborting(acqRequestId);
390 provider->requestDataAborting(acqRequestId);
391 }
391 }
392 else if (it->second.second == acqRequestId) {
392 else if (it->second.second == acqRequestId) {
393 it->second.second = QUuid();
393 it->second.second = QUuid();
394 unlock();
394 unlock();
395 }
395 }
396 else {
396 else {
397 unlock();
397 unlock();
398 }
398 }
399 }
399 }
400 else {
400 else {
401 unlock();
401 unlock();
402 }
402 }
403 }
403 }
404 else {
404 else {
405 unlock();
405 unlock();
406 }
406 }
407
407
408 lockWrite();
408 lockWrite();
409
409
410 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqRequestId);
410 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqRequestId);
411 m_AcqIdentifierToAcqRequestMap.erase(acqRequestId);
411 m_AcqIdentifierToAcqRequestMap.erase(acqRequestId);
412
412
413 unlock();
413 unlock();
414 qCDebug(LOG_VariableAcquisitionWorker())
414 qCDebug(LOG_VariableAcquisitionWorker())
415 << "VariableAcquisitionWorkerPrivate::removeAcqRequest END";
415 << "VariableAcquisitionWorkerPrivate::removeAcqRequest END";
416 }
416 }
This diff has been collapsed as it changes many lines, (677 lines changed) Show them Hide them
@@ -1,889 +1,1012
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
2 #include <Variable/VariableAcquisitionWorker.h>
3 #include <Variable/VariableCacheStrategy.h>
3 #include <Variable/VariableCacheStrategy.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
5 #include <Variable/VariableController.h>
5 #include <Variable/VariableController.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
7 #include <Variable/VariableSynchronizationGroup.h>
7 #include <Variable/VariableSynchronizationGroup.h>
8
8
9 #include <Data/DataProviderParameters.h>
9 #include <Data/DataProviderParameters.h>
10 #include <Data/IDataProvider.h>
10 #include <Data/IDataProvider.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <Data/VariableRequest.h>
12 #include <Data/VariableRequest.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14
14
15 #include <QMutex>
15 #include <QMutex>
16 #include <QThread>
16 #include <QThread>
17 #include <QUuid>
17 #include <QUuid>
18 #include <QtCore/QItemSelectionModel>
18 #include <QtCore/QItemSelectionModel>
19
19
20 #include <deque>
20 #include <deque>
21 #include <set>
21 #include <set>
22 #include <unordered_map>
22 #include <unordered_map>
23
23
24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25
25
26 namespace {
26 namespace {
27
27
28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 const SqpRange &oldGraphRange)
29 const SqpRange &oldGraphRange)
30 {
30 {
31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32
32
33 auto varRangeRequested = varRange;
33 auto varRangeRequested = varRange;
34 switch (zoomType) {
34 switch (zoomType) {
35 case AcquisitionZoomType::ZoomIn: {
35 case AcquisitionZoomType::ZoomIn: {
36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 varRangeRequested.m_TStart += deltaLeft;
38 varRangeRequested.m_TStart += deltaLeft;
39 varRangeRequested.m_TEnd -= deltaRight;
39 varRangeRequested.m_TEnd -= deltaRight;
40 break;
40 break;
41 }
41 }
42
42
43 case AcquisitionZoomType::ZoomOut: {
43 case AcquisitionZoomType::ZoomOut: {
44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 varRangeRequested.m_TStart -= deltaLeft;
46 varRangeRequested.m_TStart -= deltaLeft;
47 varRangeRequested.m_TEnd += deltaRight;
47 varRangeRequested.m_TEnd += deltaRight;
48 break;
48 break;
49 }
49 }
50 case AcquisitionZoomType::PanRight: {
50 case AcquisitionZoomType::PanRight: {
51 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
51 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
52 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
52 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
53 varRangeRequested.m_TStart += deltaLeft;
53 varRangeRequested.m_TStart += deltaLeft;
54 varRangeRequested.m_TEnd += deltaRight;
54 varRangeRequested.m_TEnd += deltaRight;
55 break;
55 break;
56 }
56 }
57 case AcquisitionZoomType::PanLeft: {
57 case AcquisitionZoomType::PanLeft: {
58 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
58 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
59 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
60 varRangeRequested.m_TStart -= deltaLeft;
60 varRangeRequested.m_TStart -= deltaLeft;
61 varRangeRequested.m_TEnd -= deltaRight;
61 varRangeRequested.m_TEnd -= deltaRight;
62 break;
62 break;
63 }
63 }
64 case AcquisitionZoomType::Unknown: {
64 case AcquisitionZoomType::Unknown: {
65 qCCritical(LOG_VariableController())
65 qCCritical(LOG_VariableController())
66 << VariableController::tr("Impossible to synchronize: zoom type unknown");
66 << VariableController::tr("Impossible to synchronize: zoom type unknown");
67 break;
67 break;
68 }
68 }
69 default:
69 default:
70 qCCritical(LOG_VariableController()) << VariableController::tr(
70 qCCritical(LOG_VariableController()) << VariableController::tr(
71 "Impossible to synchronize: zoom type not take into account");
71 "Impossible to synchronize: zoom type not take into account");
72 // No action
72 // No action
73 break;
73 break;
74 }
74 }
75
75
76 return varRangeRequested;
76 return varRangeRequested;
77 }
77 }
78 }
78 }
79
79
80 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
81
82 struct VariableRequestHandler {
83
84 VariableRequestHandler()
85 {
86 m_CanUpdate = false;
87 m_State = VariableRequestHandlerState::OFF;
88 }
89
90 QUuid m_VarId;
91 VariableRequest m_RunningVarRequest;
92 VariableRequest m_PendingVarRequest;
93 VariableRequestHandlerState m_State;
94 bool m_CanUpdate;
95 };
96
80 struct VariableController::VariableControllerPrivate {
97 struct VariableController::VariableControllerPrivate {
81 explicit VariableControllerPrivate(VariableController *parent)
98 explicit VariableControllerPrivate(VariableController *parent)
82 : m_WorkingMutex{},
99 : m_WorkingMutex{},
83 m_VariableModel{new VariableModel{parent}},
100 m_VariableModel{new VariableModel{parent}},
84 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
101 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
85 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
102 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
86 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
103 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
87 CacheStrategy::SingleThreshold)},
104 CacheStrategy::SingleThreshold)},
88 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
105 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
89 q{parent}
106 q{parent}
90 {
107 {
91
108
92 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
109 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
93 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
110 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
94 }
111 }
95
112
96
113
97 virtual ~VariableControllerPrivate()
114 virtual ~VariableControllerPrivate()
98 {
115 {
99 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
116 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
100 m_VariableAcquisitionWorkerThread.quit();
117 m_VariableAcquisitionWorkerThread.quit();
101 m_VariableAcquisitionWorkerThread.wait();
118 m_VariableAcquisitionWorkerThread.wait();
102 }
119 }
103
120
104
121
105 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
122 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
106 QUuid varRequestId);
123 QUuid varRequestId);
107
124
108 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
125 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
109 std::shared_ptr<IDataSeries>
126 std::shared_ptr<IDataSeries>
110 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
127 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
111
128
112 void registerProvider(std::shared_ptr<IDataProvider> provider);
129 void registerProvider(std::shared_ptr<IDataProvider> provider);
113
130
114 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
131 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
115 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
132 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
133 void updateVariables(QUuid varRequestId);
116 void updateVariableRequest(QUuid varRequestId);
134 void updateVariableRequest(QUuid varRequestId);
117 void cancelVariableRequest(QUuid varRequestId);
135 void cancelVariableRequest(QUuid varRequestId);
118
136 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
119 SqpRange getLastRequestedRange(QUuid varId);
120
137
121 QMutex m_WorkingMutex;
138 QMutex m_WorkingMutex;
122 /// Variable model. The VariableController has the ownership
139 /// Variable model. The VariableController has the ownership
123 VariableModel *m_VariableModel;
140 VariableModel *m_VariableModel;
124 QItemSelectionModel *m_VariableSelectionModel;
141 QItemSelectionModel *m_VariableSelectionModel;
125
142
126
143
127 TimeController *m_TimeController{nullptr};
144 TimeController *m_TimeController{nullptr};
128 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
145 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
129 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
146 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
130 QThread m_VariableAcquisitionWorkerThread;
147 QThread m_VariableAcquisitionWorkerThread;
131
148
132 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
149 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
133 m_VariableToProviderMap;
150 m_VariableToProviderMap;
134 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
151 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
135 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
152 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
136 m_GroupIdToVariableSynchronizationGroupMap;
153 m_GroupIdToVariableSynchronizationGroupMap;
137 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
154 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
138 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
155 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
139
156
140 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
157 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
141
158 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
142 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
143
144
159
145 VariableController *q;
160 VariableController *q;
146 };
161 };
147
162
148
163
149 VariableController::VariableController(QObject *parent)
164 VariableController::VariableController(QObject *parent)
150 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
165 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
151 {
166 {
152 qCDebug(LOG_VariableController()) << tr("VariableController construction")
167 qCDebug(LOG_VariableController()) << tr("VariableController construction")
153 << QThread::currentThread();
168 << QThread::currentThread();
154
169
155 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
170 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
156 &VariableController::onAbortProgressRequested);
171 &VariableController::onAbortProgressRequested);
157
172
158 connect(impl->m_VariableAcquisitionWorker.get(),
173 connect(impl->m_VariableAcquisitionWorker.get(),
159 &VariableAcquisitionWorker::variableCanceledRequested, this,
174 &VariableAcquisitionWorker::variableCanceledRequested, this,
160 &VariableController::onAbortAcquisitionRequested);
175 &VariableController::onAbortAcquisitionRequested);
161
176
162 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
177 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
163 &VariableController::onDataProvided);
178 &VariableController::onDataProvided);
164 connect(impl->m_VariableAcquisitionWorker.get(),
179 connect(impl->m_VariableAcquisitionWorker.get(),
165 &VariableAcquisitionWorker::variableRequestInProgress, this,
180 &VariableAcquisitionWorker::variableRequestInProgress, this,
166 &VariableController::onVariableRetrieveDataInProgress);
181 &VariableController::onVariableRetrieveDataInProgress);
167
182
168
183
169 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
184 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
170 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
185 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
171 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
186 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
172 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
187 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
173
188
174
189
175 impl->m_VariableAcquisitionWorkerThread.start();
190 impl->m_VariableAcquisitionWorkerThread.start();
176 }
191 }
177
192
178 VariableController::~VariableController()
193 VariableController::~VariableController()
179 {
194 {
180 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
195 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
181 << QThread::currentThread();
196 << QThread::currentThread();
182 this->waitForFinish();
197 this->waitForFinish();
183 }
198 }
184
199
185 VariableModel *VariableController::variableModel() noexcept
200 VariableModel *VariableController::variableModel() noexcept
186 {
201 {
187 return impl->m_VariableModel;
202 return impl->m_VariableModel;
188 }
203 }
189
204
190 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
205 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
191 {
206 {
192 return impl->m_VariableSelectionModel;
207 return impl->m_VariableSelectionModel;
193 }
208 }
194
209
195 void VariableController::setTimeController(TimeController *timeController) noexcept
210 void VariableController::setTimeController(TimeController *timeController) noexcept
196 {
211 {
197 impl->m_TimeController = timeController;
212 impl->m_TimeController = timeController;
198 }
213 }
199
214
200 std::shared_ptr<Variable>
215 std::shared_ptr<Variable>
201 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
216 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
202 {
217 {
203 if (impl->m_VariableModel->containsVariable(variable)) {
218 if (impl->m_VariableModel->containsVariable(variable)) {
204 // Clones variable
219 // Clones variable
205 auto duplicate = variable->clone();
220 auto duplicate = variable->clone();
206
221
207 // Adds clone to model
222 // Adds clone to model
208 impl->m_VariableModel->addVariable(duplicate);
223 impl->m_VariableModel->addVariable(duplicate);
209
224
210 // Generates clone identifier
225 // Generates clone identifier
211 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
226 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
212
227
213 // Registers provider
228 // Registers provider
214 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
229 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
215 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
230 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
216
231
217 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
232 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
218 if (duplicateProvider) {
233 if (duplicateProvider) {
219 impl->registerProvider(duplicateProvider);
234 impl->registerProvider(duplicateProvider);
220 }
235 }
221
236
222 return duplicate;
237 return duplicate;
223 }
238 }
224 else {
239 else {
225 qCCritical(LOG_VariableController())
240 qCCritical(LOG_VariableController())
226 << tr("Can't create duplicate of variable %1: variable not registered in the model")
241 << tr("Can't create duplicate of variable %1: variable not registered in the model")
227 .arg(variable->name());
242 .arg(variable->name());
228 return nullptr;
243 return nullptr;
229 }
244 }
230 }
245 }
231
246
232 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
247 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
233 {
248 {
234 if (!variable) {
249 if (!variable) {
235 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
250 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
236 return;
251 return;
237 }
252 }
238
253
239 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
254 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
240 // make some treatments before the deletion
255 // make some treatments before the deletion
241 emit variableAboutToBeDeleted(variable);
256 emit variableAboutToBeDeleted(variable);
242
257
243 // Deletes identifier
258 // Deletes identifier
244 impl->m_VariableToIdentifierMap.erase(variable);
259 impl->m_VariableToIdentifierMap.erase(variable);
245
260
246 // Deletes provider
261 // Deletes provider
247 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
262 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
248 qCDebug(LOG_VariableController())
263 qCDebug(LOG_VariableController())
249 << tr("Number of providers deleted for variable %1: %2")
264 << tr("Number of providers deleted for variable %1: %2")
250 .arg(variable->name(), QString::number(nbProvidersDeleted));
265 .arg(variable->name(), QString::number(nbProvidersDeleted));
251
266
252
267
253 // Deletes from model
268 // Deletes from model
254 impl->m_VariableModel->deleteVariable(variable);
269 impl->m_VariableModel->deleteVariable(variable);
255 }
270 }
256
271
257 void VariableController::deleteVariables(
272 void VariableController::deleteVariables(
258 const QVector<std::shared_ptr<Variable> > &variables) noexcept
273 const QVector<std::shared_ptr<Variable> > &variables) noexcept
259 {
274 {
260 for (auto variable : qAsConst(variables)) {
275 for (auto variable : qAsConst(variables)) {
261 deleteVariable(variable);
276 deleteVariable(variable);
262 }
277 }
263 }
278 }
264
279
265 std::shared_ptr<Variable>
280 std::shared_ptr<Variable>
266 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
281 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
267 std::shared_ptr<IDataProvider> provider) noexcept
282 std::shared_ptr<IDataProvider> provider) noexcept
268 {
283 {
269 if (!impl->m_TimeController) {
284 if (!impl->m_TimeController) {
270 qCCritical(LOG_VariableController())
285 qCCritical(LOG_VariableController())
271 << tr("Impossible to create variable: The time controller is null");
286 << tr("Impossible to create variable: The time controller is null");
272 return nullptr;
287 return nullptr;
273 }
288 }
274
289
275 auto range = impl->m_TimeController->dateTime();
290 auto range = impl->m_TimeController->dateTime();
276
291
277 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
292 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
278 auto identifier = QUuid::createUuid();
293 auto varId = QUuid::createUuid();
294
295 // Create the handler
296 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
297 varRequestHandler->m_VarId = varId;
298
299 impl->m_VarIdToVarRequestHandler.insert(
300 std::make_pair(varId, std::move(varRequestHandler)));
279
301
280 // store the provider
302 // store the provider
281 impl->registerProvider(provider);
303 impl->registerProvider(provider);
282
304
283 // Associate the provider
305 // Associate the provider
284 impl->m_VariableToProviderMap[newVariable] = provider;
306 impl->m_VariableToProviderMap[newVariable] = provider;
285 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
307 impl->m_VariableToIdentifierMap[newVariable] = varId;
286 impl->m_VariableToIdentifierMap[newVariable] = identifier;
287
308
309 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
288
310
289 auto varRequestId = QUuid::createUuid();
311 // auto varRequestId = QUuid::createUuid();
290 impl->processRequest(newVariable, range, varRequestId);
312 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
291 impl->updateVariableRequest(varRequestId);
313 // impl->processRequest(newVariable, range, varRequestId);
314 // impl->updateVariableRequest(varRequestId);
292
315
293 return newVariable;
316 return newVariable;
294 }
317 }
295 }
318 }
296
319
297 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
320 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
298 {
321 {
299 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
322 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
300 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
323 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
301 << QThread::currentThread()->objectName();
324 << QThread::currentThread()->objectName();
302 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
325 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
303 auto variables = QVector<std::shared_ptr<Variable> >{};
304
326
305 for (const auto &selectedRow : qAsConst(selectedRows)) {
327 // NOTE we only permit the time modification for one variable
306 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
328 // DEPRECATED
307 variables << selectedVariable;
329 // auto variables = QVector<std::shared_ptr<Variable> >{};
330 // for (const auto &selectedRow : qAsConst(selectedRows)) {
331 // if (auto selectedVariable =
332 // impl->m_VariableModel->variable(selectedRow.row())) {
333 // variables << selectedVariable;
334
335 // // notify that rescale operation has to be done
336 // emit rangeChanged(selectedVariable, dateTime);
337 // }
338 // }
339 // if (!variables.isEmpty()) {
340 // this->onRequestDataLoading(variables, dateTime, synchro);
341 // }
342 if (selectedRows.size() == 1) {
343
344 if (auto selectedVariable
345 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
346
347 auto itVar = impl->m_VariableToIdentifierMap.find(selectedVariable);
348 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
349 qCCritical(LOG_VariableController())
350 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
351 return;
352 }
308
353
309 // notify that rescale operation has to be done
354 // notify that rescale operation has to be done
310 emit rangeChanged(selectedVariable, dateTime);
355 emit rangeChanged(selectedVariable, dateTime);
356
357 auto synchro = impl->m_VariableIdGroupIdMap.find(itVar->second)
358 != impl->m_VariableIdGroupIdMap.cend();
359
360 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{selectedVariable},
361 dateTime, synchro);
311 }
362 }
312 }
363 }
313
364 else if (selectedRows.size() > 1) {
314 if (!variables.isEmpty()) {
365 qCCritical(LOG_VariableController())
315 this->onRequestDataLoading(variables, dateTime, true);
366 << tr("Impossible to set time for more than 1 variable in the same time");
367 }
368 else {
369 qCWarning(LOG_VariableController())
370 << tr("There is no variable selected to set the time one");
316 }
371 }
317 }
372 }
318
373
319 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
374 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
320 const SqpRange &cacheRangeRequested,
375 const SqpRange &cacheRangeRequested,
321 QVector<AcquisitionDataPacket> dataAcquired)
376 QVector<AcquisitionDataPacket> dataAcquired)
322 {
377 {
378 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
323 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
379 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
324 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
380 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
325 if (!varRequestId.isNull()) {
381 if (!varRequestId.isNull()) {
326 impl->updateVariableRequest(varRequestId);
382 impl->updateVariables(varRequestId);
327 }
383 }
328 }
384 }
329
385
330 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
386 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
331 {
387 {
332 qCDebug(LOG_VariableController())
388 qCDebug(LOG_VariableController())
333 << "TORM: variableController::onVariableRetrieveDataInProgress"
389 << "TORM: variableController::onVariableRetrieveDataInProgress"
334 << QThread::currentThread()->objectName() << progress;
390 << QThread::currentThread()->objectName() << progress;
335 if (auto var = impl->findVariable(identifier)) {
391 if (auto var = impl->findVariable(identifier)) {
336 impl->m_VariableModel->setDataProgress(var, progress);
392 impl->m_VariableModel->setDataProgress(var, progress);
337 }
393 }
338 else {
394 else {
339 qCCritical(LOG_VariableController())
395 qCCritical(LOG_VariableController())
340 << tr("Impossible to notify progression of a null variable");
396 << tr("Impossible to notify progression of a null variable");
341 }
397 }
342 }
398 }
343
399
344 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
400 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
345 {
401 {
346 auto it = impl->m_VariableToIdentifierMap.find(variable);
402 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
347 if (it != impl->m_VariableToIdentifierMap.cend()) {
403 << QThread::currentThread()->objectName() << variable->name();
348 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
349
404
350 QUuid varRequestId;
405 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
351 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
406 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
352 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
407 qCCritical(LOG_VariableController())
353 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
408 << tr("Impossible to onAbortProgressRequested request for unknown variable");
354 varRequestId = varRequestIdQueue.front();
409 return;
355 impl->cancelVariableRequest(varRequestId);
410 }
356
411
357 // Finish the progression for the request
412 auto varId = itVar->second;
358 impl->m_VariableModel->setDataProgress(variable, 0.0);
413
359 }
414 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
360 else {
415 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
361 qCWarning(LOG_VariableController())
416 qCCritical(LOG_VariableController())
362 << tr("Aborting progression of inexistant variable request detected !!!")
417 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
363 << QThread::currentThread()->objectName();
418 return;
364 }
365 }
419 }
366 else {
420
367 qCWarning(LOG_VariableController())
421 auto varHandler = itVarHandler->second.get();
368 << tr("Aborting progression of inexistant variable detected !!!")
422
369 << QThread::currentThread()->objectName();
423 // case where a variable has a running request
424 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
425 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
370 }
426 }
371 }
427 }
372
428
373 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
429 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
374 {
430 {
375 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
431 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
376 << QThread::currentThread()->objectName() << vIdentifier;
432 << QThread::currentThread()->objectName() << vIdentifier;
377
433
378 if (auto var = impl->findVariable(vIdentifier)) {
434 if (auto var = impl->findVariable(vIdentifier)) {
379 this->onAbortProgressRequested(var);
435 this->onAbortProgressRequested(var);
380 }
436 }
381 else {
437 else {
382 qCCritical(LOG_VariableController())
438 qCCritical(LOG_VariableController())
383 << tr("Impossible to abort Acquisition Requestof a null variable");
439 << tr("Impossible to abort Acquisition Requestof a null variable");
384 }
440 }
385 }
441 }
386
442
387 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
443 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
388 {
444 {
389 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
445 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
390 << QThread::currentThread()->objectName()
446 << QThread::currentThread()->objectName()
391 << synchronizationGroupId;
447 << synchronizationGroupId;
392 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
448 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
393 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
449 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
394 std::make_pair(synchronizationGroupId, vSynchroGroup));
450 std::make_pair(synchronizationGroupId, vSynchroGroup));
395 }
451 }
396
452
397 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
453 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
398 {
454 {
399 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
455 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
400 }
456 }
401
457
402 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
458 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
403 QUuid synchronizationGroupId)
459 QUuid synchronizationGroupId)
404
460
405 {
461 {
406 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
462 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
407 << synchronizationGroupId;
463 << synchronizationGroupId;
408 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
464 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
409 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
465 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
410 auto groupIdToVSGIt
466 auto groupIdToVSGIt
411 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
467 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
412 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
468 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
413 impl->m_VariableIdGroupIdMap.insert(
469 impl->m_VariableIdGroupIdMap.insert(
414 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
470 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
415 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
471 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
416 }
472 }
417 else {
473 else {
418 qCCritical(LOG_VariableController())
474 qCCritical(LOG_VariableController())
419 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
475 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
420 << variable->name();
476 << variable->name();
421 }
477 }
422 }
478 }
423 else {
479 else {
424 qCCritical(LOG_VariableController())
480 qCCritical(LOG_VariableController())
425 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
481 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
426 }
482 }
427 }
483 }
428
484
429 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
485 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
430 QUuid synchronizationGroupId)
486 QUuid synchronizationGroupId)
431 {
487 {
432 // Gets variable id
488 // Gets variable id
433 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
489 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
434 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
490 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
435 qCCritical(LOG_VariableController())
491 qCCritical(LOG_VariableController())
436 << tr("Can't desynchronize variable %1: variable identifier not found")
492 << tr("Can't desynchronize variable %1: variable identifier not found")
437 .arg(variable->name());
493 .arg(variable->name());
438 return;
494 return;
439 }
495 }
440
496
441 // Gets synchronization group
497 // Gets synchronization group
442 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
498 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
443 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
499 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
444 qCCritical(LOG_VariableController())
500 qCCritical(LOG_VariableController())
445 << tr("Can't desynchronize variable %1: unknown synchronization group")
501 << tr("Can't desynchronize variable %1: unknown synchronization group")
446 .arg(variable->name());
502 .arg(variable->name());
447 return;
503 return;
448 }
504 }
449
505
450 auto variableId = variableIt->second;
506 auto variableId = variableIt->second;
451
507
452 // Removes variable from synchronization group
508 // Removes variable from synchronization group
453 auto synchronizationGroup = groupIt->second;
509 auto synchronizationGroup = groupIt->second;
454 synchronizationGroup->removeVariableId(variableId);
510 synchronizationGroup->removeVariableId(variableId);
455
511
456 // Removes link between variable and synchronization group
512 // Removes link between variable and synchronization group
457 impl->m_VariableIdGroupIdMap.erase(variableId);
513 impl->m_VariableIdGroupIdMap.erase(variableId);
458 }
514 }
459
515
460 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
516 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
461 const SqpRange &range, bool synchronise)
517 const SqpRange &range, bool synchronise)
462 {
518 {
463 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
519 // variables is assumed synchronized
464
520 // TODO: Asser variables synchronization
465 // we want to load data of the variable for the dateTime.
521 // we want to load data of the variable for the dateTime.
466 // First we check if the cache contains some of them.
522 if (variables.isEmpty()) {
467 // For the other, we ask the provider to give them.
523 return;
524 }
468
525
469 auto varRequestId = QUuid::createUuid();
526 auto varRequestId = QUuid::createUuid();
470 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
527 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
471 << QThread::currentThread()->objectName() << varRequestId;
528 << QThread::currentThread()->objectName() << varRequestId
472
529 << range << synchronise;
473 for (const auto &var : variables) {
474 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
475 impl->processRequest(var, range, varRequestId);
476 }
477
530
478 if (synchronise) {
531 if (!synchronise) {
479 // Get the group ids
532 auto varIds = std::list<QUuid>{};
480 qCDebug(LOG_VariableController())
481 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
482 auto groupIds = std::set<QUuid>{};
483 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
484 for (const auto &var : variables) {
533 for (const auto &var : variables) {
485 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
534 auto vId = impl->m_VariableToIdentifierMap.at(var);
486 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
535 varIds.push_back(vId);
487 auto vId = varToVarIdIt->second;
536 }
488 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
537 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
489 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
538 for (const auto &var : variables) {
490 auto gId = varIdToGroupIdIt->second;
539 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
491 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
540 << varIds.size();
492 if (groupIds.find(gId) == groupIds.cend()) {
541 impl->processRequest(var, range, varRequestId);
493 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
494 groupIds.insert(gId);
495 }
496 }
497 }
498 }
542 }
543 }
544 else {
545 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
546 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
547 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
548 auto groupId = varIdToGroupIdIt->second;
499
549
500 // We assume here all group ids exist
550 auto vSynchronizationGroup
501 for (const auto &gId : groupIds) {
551 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
502 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
503 auto vSyncIds = vSynchronizationGroup->getIds();
552 auto vSyncIds = vSynchronizationGroup->getIds();
504 qCDebug(LOG_VariableController()) << "Var in synchro group ";
553
554 auto varIds = std::list<QUuid>{};
555 for (auto vId : vSyncIds) {
556 varIds.push_back(vId);
557 }
558 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
559
505 for (auto vId : vSyncIds) {
560 for (auto vId : vSyncIds) {
506 auto var = impl->findVariable(vId);
561 auto var = impl->findVariable(vId);
507
562
508 // Don't process already processed var
563 // Don't process already processed var
509 if (!variables.contains(var)) {
564 if (var != nullptr) {
510 if (var != nullptr) {
565 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
511 qCDebug(LOG_VariableController()) << "processRequest synchro for"
566 << varRequestId;
512 << var->name();
567 auto vSyncRangeRequested
513 auto vSyncRangeRequested = computeSynchroRangeRequested(
568 = variables.contains(var)
514 var->range(), range, groupIdToOldRangeMap.at(gId));
569 ? range
515 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
570 : computeSynchroRangeRequested(var->range(), range,
516 impl->processRequest(var, vSyncRangeRequested, varRequestId);
571 variables.first()->range());
517 }
572 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
518 else {
573 impl->processRequest(var, vSyncRangeRequested, varRequestId);
519 qCCritical(LOG_VariableController())
574 }
575 else {
576 qCCritical(LOG_VariableController())
520
577
521 << tr("Impossible to synchronize a null variable");
578 << tr("Impossible to synchronize a null variable");
522 }
523 }
579 }
524 }
580 }
525 }
581 }
526 }
582 }
527
583
528 impl->updateVariableRequest(varRequestId);
584 impl->updateVariables(varRequestId);
529 }
585 }
530
586
531
587
532 void VariableController::initialize()
588 void VariableController::initialize()
533 {
589 {
534 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
590 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
535 impl->m_WorkingMutex.lock();
591 impl->m_WorkingMutex.lock();
536 qCDebug(LOG_VariableController()) << tr("VariableController init END");
592 qCDebug(LOG_VariableController()) << tr("VariableController init END");
537 }
593 }
538
594
539 void VariableController::finalize()
595 void VariableController::finalize()
540 {
596 {
541 impl->m_WorkingMutex.unlock();
597 impl->m_WorkingMutex.unlock();
542 }
598 }
543
599
544 void VariableController::waitForFinish()
600 void VariableController::waitForFinish()
545 {
601 {
546 QMutexLocker locker{&impl->m_WorkingMutex};
602 QMutexLocker locker{&impl->m_WorkingMutex};
547 }
603 }
548
604
549 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
605 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
550 {
606 {
551 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
607 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
552 auto zoomType = AcquisitionZoomType::Unknown;
608 auto zoomType = AcquisitionZoomType::Unknown;
553 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
609 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
554 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
610 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
555 zoomType = AcquisitionZoomType::ZoomOut;
611 zoomType = AcquisitionZoomType::ZoomOut;
556 }
612 }
557 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
613 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
558 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
614 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
559 zoomType = AcquisitionZoomType::PanRight;
615 zoomType = AcquisitionZoomType::PanRight;
560 }
616 }
561 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
617 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
562 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
618 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
563 zoomType = AcquisitionZoomType::PanLeft;
619 zoomType = AcquisitionZoomType::PanLeft;
564 }
620 }
565 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
621 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
566 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
622 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
567 zoomType = AcquisitionZoomType::ZoomIn;
623 zoomType = AcquisitionZoomType::ZoomIn;
568 }
624 }
569 else {
625 else {
570 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
626 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
571 }
627 }
572 return zoomType;
628 return zoomType;
573 }
629 }
574
630
575 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
631 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
576 const SqpRange &rangeRequested,
632 const SqpRange &rangeRequested,
577 QUuid varRequestId)
633 QUuid varRequestId)
578 {
634 {
579 auto varRequest = VariableRequest{};
635 auto itVar = m_VariableToIdentifierMap.find(var);
636 if (itVar == m_VariableToIdentifierMap.cend()) {
637 qCCritical(LOG_VariableController())
638 << tr("Impossible to process request for unknown variable");
639 return;
640 }
580
641
581 auto it = m_VariableToIdentifierMap.find(var);
642 auto varId = itVar->second;
582 if (it != m_VariableToIdentifierMap.cend()) {
583
643
584 auto varId = it->second;
644 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
645 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
646 qCCritical(LOG_VariableController())
647 << tr("Impossible to process request for variable with unknown handler");
648 return;
649 }
585
650
586 auto oldRange = getLastRequestedRange(varId);
651 auto oldRange = var->range();
587
652
588 // check for update oldRange to the last request range.
653 auto varHandler = itVarHandler->second.get();
589 if (oldRange == INVALID_RANGE) {
590 oldRange = var->range();
591 }
592
654
593 auto varStrategyRangesRequested
655 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
594 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
656 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
595
657 }
596 auto notInCacheRangeList
597 = Variable::provideNotInCacheRangeList(oldRange, varStrategyRangesRequested.second);
598 auto inCacheRangeList
599 = Variable::provideInCacheRangeList(oldRange, varStrategyRangesRequested.second);
600
601 if (!notInCacheRangeList.empty()) {
602 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
603 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
604
605 // store VarRequest
606 storeVariableRequest(varId, varRequestId, varRequest);
607
608 auto varProvider = m_VariableToProviderMap.at(var);
609 if (varProvider != nullptr) {
610 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
611 varRequestId, varId, varStrategyRangesRequested.first,
612 varStrategyRangesRequested.second,
613 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
614 varProvider);
615
616 if (!varRequestIdCanceled.isNull()) {
617 qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ")
618 << varRequestIdCanceled;
619 cancelVariableRequest(varRequestIdCanceled);
620 }
621 }
622 else {
623 qCCritical(LOG_VariableController())
624 << "Impossible to provide data with a null provider";
625 }
626
658
627 if (!inCacheRangeList.empty()) {
659 auto varRequest = VariableRequest{};
628 emit q->updateVarDisplaying(var, inCacheRangeList.first());
660 varRequest.m_VariableGroupId = varRequestId;
629 }
661 auto varStrategyRangesRequested
662 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
663 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
664 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
665
666 switch (varHandler->m_State) {
667 case VariableRequestHandlerState::OFF: {
668 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
669 << varRequest.m_RangeRequested
670 << varRequest.m_CacheRangeRequested;
671 varHandler->m_RunningVarRequest = varRequest;
672 varHandler->m_State = VariableRequestHandlerState::RUNNING;
673 executeVarRequest(var, varRequest);
674 break;
630 }
675 }
631 else {
676 case VariableRequestHandlerState::RUNNING: {
632 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
677 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
633 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
678 << varRequest.m_RangeRequested
634 // store VarRequest
679 << varRequest.m_CacheRangeRequested;
635 storeVariableRequest(varId, varRequestId, varRequest);
680 varHandler->m_State = VariableRequestHandlerState::PENDING;
636 acceptVariableRequest(
681 varHandler->m_PendingVarRequest = varRequest;
637 varId, var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
682 break;
638 }
683 }
684 case VariableRequestHandlerState::PENDING: {
685 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
686 << varRequest.m_RangeRequested
687 << varRequest.m_CacheRangeRequested;
688 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
689 cancelVariableRequest(variableGroupIdToCancel);
690 // Cancel variable can make state downgrade
691 varHandler->m_State = VariableRequestHandlerState::PENDING;
692 varHandler->m_PendingVarRequest = varRequest;
693
694 break;
695 }
696 default:
697 qCCritical(LOG_VariableController())
698 << QObject::tr("Unknown VariableRequestHandlerState");
639 }
699 }
640 }
700 }
641
701
642 std::shared_ptr<Variable>
702 std::shared_ptr<Variable>
643 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
703 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
644 {
704 {
645 std::shared_ptr<Variable> var;
705 std::shared_ptr<Variable> var;
646 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
706 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
647
707
648 auto end = m_VariableToIdentifierMap.cend();
708 auto end = m_VariableToIdentifierMap.cend();
649 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
709 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
650 if (it != end) {
710 if (it != end) {
651 var = it->first;
711 var = it->first;
652 }
712 }
653 else {
713 else {
654 qCCritical(LOG_VariableController())
714 qCCritical(LOG_VariableController())
655 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
715 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
656 }
716 }
657
717
658 return var;
718 return var;
659 }
719 }
660
720
661 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
721 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
662 const QVector<AcquisitionDataPacket> acqDataPacketVector)
722 const QVector<AcquisitionDataPacket> acqDataPacketVector)
663 {
723 {
664 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
724 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
665 << acqDataPacketVector.size();
725 << acqDataPacketVector.size();
666 std::shared_ptr<IDataSeries> dataSeries;
726 std::shared_ptr<IDataSeries> dataSeries;
667 if (!acqDataPacketVector.isEmpty()) {
727 if (!acqDataPacketVector.isEmpty()) {
668 dataSeries = acqDataPacketVector[0].m_DateSeries;
728 dataSeries = acqDataPacketVector[0].m_DateSeries;
669 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
729 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
670 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
730 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
671 }
731 }
672 }
732 }
673 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
733 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
674 << acqDataPacketVector.size();
734 << acqDataPacketVector.size();
675 return dataSeries;
735 return dataSeries;
676 }
736 }
677
737
678 void VariableController::VariableControllerPrivate::registerProvider(
738 void VariableController::VariableControllerPrivate::registerProvider(
679 std::shared_ptr<IDataProvider> provider)
739 std::shared_ptr<IDataProvider> provider)
680 {
740 {
681 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
741 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
682 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
742 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
683 << provider->objectName();
743 << provider->objectName();
684 m_ProviderSet.insert(provider);
744 m_ProviderSet.insert(provider);
685 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
745 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
686 &VariableAcquisitionWorker::onVariableDataAcquired);
746 &VariableAcquisitionWorker::onVariableDataAcquired);
687 connect(provider.get(), &IDataProvider::dataProvidedProgress,
747 connect(provider.get(), &IDataProvider::dataProvidedProgress,
688 m_VariableAcquisitionWorker.get(),
748 m_VariableAcquisitionWorker.get(),
689 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
749 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
690 connect(provider.get(), &IDataProvider::dataProvidedFailed,
750 connect(provider.get(), &IDataProvider::dataProvidedFailed,
691 m_VariableAcquisitionWorker.get(),
751 m_VariableAcquisitionWorker.get(),
692 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
752 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
693 }
753 }
694 else {
754 else {
695 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
755 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
696 }
756 }
697 }
757 }
698
758
699 void VariableController::VariableControllerPrivate::storeVariableRequest(
700 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
701 {
702 // First request for the variable. we can create an entry for it
703 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
704 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
705 auto varRequestIdQueue = std::deque<QUuid>{};
706 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
707 varRequestIdQueue.push_back(varRequestId);
708 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
709 }
710 else {
711 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
712 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
713 varRequestIdQueue.push_back(varRequestId);
714 }
715
716 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
717 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
718 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
719 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
720 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
721 m_VarRequestIdToVarIdVarRequestMap.insert(
722 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
723 }
724 else {
725 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
726 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
727 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
728 }
729 }
730
731 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
759 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
732 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
760 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
733 {
761 {
734 QUuid varRequestId;
762 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
735 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
763 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
736 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
764 return QUuid();
737 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
738 varRequestId = varRequestIdQueue.front();
739 auto varRequestIdToVarIdVarRequestMapIt
740 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
741 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
742 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
743 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
744 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
745 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
746 auto &varRequest = varIdToVarRequestMapIt->second;
747 varRequest.m_DataSeries = dataSeries;
748 varRequest.m_CanUpdate = true;
749 }
750 else {
751 qCDebug(LOG_VariableController())
752 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
753 "to a variableRequestId")
754 << varRequestId << varId;
755 }
756 }
757 else {
758 qCCritical(LOG_VariableController())
759 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
760 << varRequestId;
761 }
762
763 varRequestIdQueue.pop_front();
764 if (varRequestIdQueue.empty()) {
765 qCDebug(LOG_VariableController())
766 << tr("TORM Erase REQUEST because it has been accepted") << varId;
767 m_VarIdToVarRequestIdQueueMap.erase(varId);
768 }
769 }
765 }
770 else {
766
767 auto varHandler = itVarHandler->second.get();
768 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
771 qCCritical(LOG_VariableController())
769 qCCritical(LOG_VariableController())
772 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
770 << tr("acceptVariableRequest impossible on a variable with OFF state");
773 }
771 }
774
772
775 return varRequestId;
773 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
774 varHandler->m_CanUpdate = true;
775
776 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
777 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
778 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
779 << m_VarGroupIdToVarIds.size();
780
781 return varHandler->m_RunningVarRequest.m_VariableGroupId;
776 }
782 }
777
783
778 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
784 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
779 {
785 {
786 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
787 << QThread::currentThread()->objectName() << varRequestId;
780
788
781 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
789 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
782 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
790 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
783 bool processVariableUpdate = true;
791 qCWarning(LOG_VariableController())
784 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
792 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
785 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
793 return;
786 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
794 }
787 ++varIdToVarRequestMapIt) {
795
788 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
796 auto &varIds = varGroupIdToVarIdsIt->second;
789 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
797 auto varIdsEnd = varIds.end();
790 << processVariableUpdate;
798 bool processVariableUpdate = true;
799 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
800 << varRequestId << varIds.size();
801 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
802 ++varIdsIt) {
803 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
804 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
805 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
791 }
806 }
807 }
792
808
793 if (processVariableUpdate) {
809 if (processVariableUpdate) {
794 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
810 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
795 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
811 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
796 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
812 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
797 auto &varRequest = varIdToVarRequestMapIt->second;
813 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
814 if (auto var = findVariable(*varIdsIt)) {
815 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
798 var->setRange(varRequest.m_RangeRequested);
816 var->setRange(varRequest.m_RangeRequested);
799 var->setCacheRange(varRequest.m_CacheRangeRequested);
817 var->setCacheRange(varRequest.m_CacheRangeRequested);
800 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
818 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
801 << varRequest.m_RangeRequested
819 << varRequest.m_RangeRequested
802 << varRequest.m_CacheRangeRequested;
820 << varRequest.m_CacheRangeRequested;
803 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
821 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
804 << var->nbPoints()
822 << var->nbPoints()
805 << varRequest.m_DataSeries->nbPoints();
823 << varRequest.m_DataSeries->nbPoints();
806 var->mergeDataSeries(varRequest.m_DataSeries);
824 var->mergeDataSeries(varRequest.m_DataSeries);
807 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
825 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
808 << var->nbPoints();
826 << var->nbPoints();
809
827
810 emit var->updated();
828 emit var->updated();
829 qCDebug(LOG_VariableController()) << tr("Update OK");
811 }
830 }
812 else {
831 else {
813 qCCritical(LOG_VariableController())
832 qCCritical(LOG_VariableController())
814 << tr("Impossible to update data to a null variable");
833 << tr("Impossible to update data to a null variable");
815 }
834 }
816 }
835 }
817 // cleaning varRequestId
818 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
819 << m_VarRequestIdToVarIdVarRequestMap.size();
820 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
821 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
822 << m_VarRequestIdToVarIdVarRequestMap.size();
823 }
836 }
837 updateVariableRequest(varRequestId);
838
839 // cleaning varRequestId
840 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
841 m_VarGroupIdToVarIds.erase(varRequestId);
824 }
842 }
825 else {
843 }
826 qCCritical(LOG_VariableController())
844
827 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
845
846 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
847 {
848 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
849 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
850 qCCritical(LOG_VariableController()) << QObject::tr(
851 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
852
853 return;
854 }
855
856 auto &varIds = varGroupIdToVarIdsIt->second;
857 auto varIdsEnd = varIds.end();
858 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
859 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
860 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
861
862 auto varHandler = itVarHandler->second.get();
863 varHandler->m_CanUpdate = false;
864
865
866 switch (varHandler->m_State) {
867 case VariableRequestHandlerState::OFF: {
868 qCCritical(LOG_VariableController())
869 << QObject::tr("Impossible to update a variable with handler in OFF state");
870 } break;
871 case VariableRequestHandlerState::RUNNING: {
872 varHandler->m_State = VariableRequestHandlerState::OFF;
873 varHandler->m_RunningVarRequest = VariableRequest{};
874 break;
875 }
876 case VariableRequestHandlerState::PENDING: {
877 varHandler->m_State = VariableRequestHandlerState::RUNNING;
878 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
879 varHandler->m_PendingVarRequest = VariableRequest{};
880 auto var = findVariable(itVarHandler->first);
881 executeVarRequest(var, varHandler->m_RunningVarRequest);
882 break;
883 }
884 default:
885 qCCritical(LOG_VariableController())
886 << QObject::tr("Unknown VariableRequestHandlerState");
887 }
888 }
828 }
889 }
829 }
890 }
830
891
892
831 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
893 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
832 {
894 {
833 // cleaning varRequestId
895 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
834 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
896
897 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
898 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
899 qCCritical(LOG_VariableController())
900 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
901 return;
902 }
835
903
836 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
904 auto &varIds = varGroupIdToVarIdsIt->second;
837 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
905 auto varIdsEnd = varIds.end();
838 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
906 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
839 varRequestIdQueue.erase(
907 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
840 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
908 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
841 varRequestIdQueue.end());
842 if (varRequestIdQueue.empty()) {
843 varIdToVarRequestIdQueueMapIt
844 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
845
909
846 // Recompute if there is any next request based on the removed request.
910 auto varHandler = itVarHandler->second.get();
847 }
911 varHandler->m_VarId = QUuid{};
848 else {
912 switch (varHandler->m_State) {
849 ++varIdToVarRequestIdQueueMapIt;
913 case VariableRequestHandlerState::OFF: {
914 qCWarning(LOG_VariableController())
915 << QObject::tr("Impossible to cancel a variable with no running request");
916 break;
917 }
918 case VariableRequestHandlerState::RUNNING: {
919
920 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
921 auto var = findVariable(itVarHandler->first);
922 auto varProvider = m_VariableToProviderMap.at(var);
923 if (varProvider != nullptr) {
924 m_VariableAcquisitionWorker->abortProgressRequested(
925 itVarHandler->first);
926 }
927 m_VariableModel->setDataProgress(var, 0.0);
928 varHandler->m_CanUpdate = false;
929 varHandler->m_State = VariableRequestHandlerState::OFF;
930 varHandler->m_RunningVarRequest = VariableRequest{};
931 }
932 else {
933 // TODO: log Impossible to cancel the running variable request beacause its
934 // varRequestId isn't not the canceled one
935 }
936 break;
937 }
938 case VariableRequestHandlerState::PENDING: {
939 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
940 auto var = findVariable(itVarHandler->first);
941 auto varProvider = m_VariableToProviderMap.at(var);
942 if (varProvider != nullptr) {
943 m_VariableAcquisitionWorker->abortProgressRequested(
944 itVarHandler->first);
945 }
946 m_VariableModel->setDataProgress(var, 0.0);
947 varHandler->m_CanUpdate = false;
948 varHandler->m_State = VariableRequestHandlerState::RUNNING;
949 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
950 varHandler->m_PendingVarRequest = VariableRequest{};
951 executeVarRequest(var, varHandler->m_RunningVarRequest);
952 }
953 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
954 varHandler->m_State = VariableRequestHandlerState::RUNNING;
955 varHandler->m_PendingVarRequest = VariableRequest{};
956 }
957 else {
958 // TODO: log Impossible to cancel the variable request beacause its
959 // varRequestId isn't not the canceled one
960 }
961 break;
962 }
963 default:
964 qCCritical(LOG_VariableController())
965 << QObject::tr("Unknown VariableRequestHandlerState");
966 }
850 }
967 }
851 }
968 }
969 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
970 m_VarGroupIdToVarIds.erase(varRequestId);
852 }
971 }
853
972
854 SqpRange VariableController::VariableControllerPrivate::getLastRequestedRange(QUuid varId)
973 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
974 VariableRequest &varRequest)
855 {
975 {
856 auto lastRangeRequested = SqpRange{INVALID_RANGE};
976 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
857 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
977
858 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
978 auto varId = m_VariableToIdentifierMap.at(var);
859 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
979
860 auto varRequestId = varRequestIdQueue.back();
980 auto varCacheRange = var->cacheRange();
861 auto varRequestIdToVarIdVarRequestMapIt
981 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
862 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
982 auto notInCacheRangeList
863 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
983 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
864 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
984 auto inCacheRangeList
865 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
985 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
866 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
986
867 auto &varRequest = varIdToVarRequestMapIt->second;
987 if (!notInCacheRangeList.empty()) {
868 lastRangeRequested = varRequest.m_RangeRequested;
988
869 }
989 auto varProvider = m_VariableToProviderMap.at(var);
870 else {
990 if (varProvider != nullptr) {
871 qCDebug(LOG_VariableController())
991 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
872 << tr("Impossible to getLastRequestedRange of a unknown variable id attached "
992 << varRequest.m_CacheRangeRequested;
873 "to a variableRequestId")
993 m_VariableAcquisitionWorker->pushVariableRequest(
874 << varRequestId << varId;
994 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
875 }
995 varRequest.m_CacheRangeRequested,
996 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
997 varProvider);
876 }
998 }
877 else {
999 else {
878 qCCritical(LOG_VariableController())
1000 qCCritical(LOG_VariableController())
879 << tr("Impossible to getLastRequestedRange of a unknown variableRequestId")
1001 << "Impossible to provide data with a null provider";
880 << varRequestId;
1002 }
1003
1004 if (!inCacheRangeList.empty()) {
1005 emit q->updateVarDisplaying(var, inCacheRangeList.first());
881 }
1006 }
882 }
1007 }
883 else {
1008 else {
884 qDebug(LOG_VariableController())
1009 acceptVariableRequest(varId,
885 << tr("Impossible to getLastRequestedRange of a unknown variable id") << varId;
1010 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
886 }
1011 }
887
888 return lastRangeRequested;
889 }
1012 }
@@ -1,409 +1,409
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4
4
5 #include <QObject>
5 #include <QObject>
6 #include <QtTest>
6 #include <QtTest>
7
7
8 #include <memory>
8 #include <memory>
9
9
10 namespace {
10 namespace {
11
11
12 /// Generates a date in double
12 /// Generates a date in double
13 auto date = [](int year, int month, int day, int hours, int minutes, int seconds) {
13 auto date = [](int year, int month, int day, int hours, int minutes, int seconds) {
14 return DateUtils::secondsSinceEpoch(
14 return DateUtils::secondsSinceEpoch(
15 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
15 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
16 };
16 };
17
17
18 /// Generates a series of test data for a range
18 /// Generates a series of test data for a range
19 std::shared_ptr<ScalarSeries> dataSeries(const SqpRange &range)
19 std::shared_ptr<ScalarSeries> dataSeries(const SqpRange &range)
20 {
20 {
21 auto xAxisData = std::vector<double>{};
21 auto xAxisData = std::vector<double>{};
22 auto valuesData = std::vector<double>{};
22 auto valuesData = std::vector<double>{};
23
23
24 auto value = 0;
24 auto value = 0;
25 for (auto x = range.m_TStart; x <= range.m_TEnd; ++x, ++value) {
25 for (auto x = range.m_TStart; x <= range.m_TEnd; ++x, ++value) {
26 xAxisData.push_back(x);
26 xAxisData.push_back(x);
27 valuesData.push_back(value);
27 valuesData.push_back(value);
28 }
28 }
29
29
30 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
30 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
31 Unit{});
31 Unit{});
32 }
32 }
33
33
34 } // namespace
34 } // namespace
35
35
36 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
36 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
37
37
38 class TestVariable : public QObject {
38 class TestVariable : public QObject {
39 Q_OBJECT
39 Q_OBJECT
40
40
41 private slots:
41 private slots:
42 void testClone_data();
42 void testClone_data();
43 void testClone();
43 void testClone();
44
44
45 void testNotInCacheRangeList();
45 void testNotInCacheRangeList();
46 void testInCacheRangeList();
46 void testInCacheRangeList();
47
47
48 void testNbPoints_data();
48 void testNbPoints_data();
49 void testNbPoints();
49 void testNbPoints();
50
50
51 void testRealRange_data();
51 void testRealRange_data();
52 void testRealRange();
52 void testRealRange();
53 };
53 };
54
54
55 void TestVariable::testClone_data()
55 void TestVariable::testClone_data()
56 {
56 {
57 // ////////////// //
57 // ////////////// //
58 // Test structure //
58 // Test structure //
59 // ////////////// //
59 // ////////////// //
60
60
61 QTest::addColumn<QString>("name");
61 QTest::addColumn<QString>("name");
62 QTest::addColumn<QVariantHash>("metadata");
62 QTest::addColumn<QVariantHash>("metadata");
63 QTest::addColumn<SqpRange>("range");
63 QTest::addColumn<SqpRange>("range");
64 QTest::addColumn<SqpRange>("cacheRange");
64 QTest::addColumn<SqpRange>("cacheRange");
65 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
65 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
66
66
67 // ////////// //
67 // ////////// //
68 // Test cases //
68 // Test cases //
69 // ////////// //
69 // ////////// //
70
70
71 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)};
71 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)};
72 QTest::newRow("clone1") << QStringLiteral("var1")
72 QTest::newRow("clone1") << QStringLiteral("var1")
73 << QVariantHash{{"data1", 1}, {"data2", "abc"}}
73 << QVariantHash{{"data1", 1}, {"data2", "abc"}}
74 << SqpRange{date(2017, 1, 1, 12, 30, 0), (date(2017, 1, 1, 12, 45, 0))}
74 << SqpRange{date(2017, 1, 1, 12, 30, 0), (date(2017, 1, 1, 12, 45, 0))}
75 << cacheRange << dataSeries(cacheRange);
75 << cacheRange << dataSeries(cacheRange);
76 }
76 }
77
77
78 void TestVariable::testClone()
78 void TestVariable::testClone()
79 {
79 {
80 // Creates variable
80 // Creates variable
81 QFETCH(QString, name);
81 QFETCH(QString, name);
82 QFETCH(QVariantHash, metadata);
82 QFETCH(QVariantHash, metadata);
83 QFETCH(SqpRange, range);
83 QFETCH(SqpRange, range);
84 QFETCH(SqpRange, cacheRange);
84 QFETCH(SqpRange, cacheRange);
85 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
85 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
86
86
87 Variable variable{name, metadata};
87 Variable variable{name, metadata};
88 variable.setRange(range);
88 variable.setRange(range);
89 variable.setCacheRange(cacheRange);
89 variable.setCacheRange(cacheRange);
90 variable.mergeDataSeries(dataSeries);
90 variable.mergeDataSeries(dataSeries);
91
91
92 // Clones variable
92 // Clones variable
93 auto clone = variable.clone();
93 auto clone = variable.clone();
94
94
95 // Checks cloned variable's state
95 // Checks cloned variable's state
96 QCOMPARE(clone->name(), name);
96 QCOMPARE(clone->name(), name);
97 QCOMPARE(clone->metadata(), metadata);
97 QCOMPARE(clone->metadata(), metadata);
98 QCOMPARE(clone->range(), range);
98 QCOMPARE(clone->range(), range);
99 QCOMPARE(clone->cacheRange(), cacheRange);
99 QCOMPARE(clone->cacheRange(), cacheRange);
100
100
101 // Compares data series
101 // Compares data series
102 if (dataSeries != nullptr) {
102 if (dataSeries != nullptr) {
103 QVERIFY(clone->dataSeries() != nullptr);
103 QVERIFY(clone->dataSeries() != nullptr);
104 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), clone->dataSeries()->cbegin(),
104 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), clone->dataSeries()->cbegin(),
105 clone->dataSeries()->cend(), [](const auto &it1, const auto &it2) {
105 clone->dataSeries()->cend(), [](const auto &it1, const auto &it2) {
106 return it1.x() == it2.x() && it1.value() == it2.value();
106 return it1.x() == it2.x() && it1.value() == it2.value();
107 }));
107 }));
108 }
108 }
109 else {
109 else {
110 QVERIFY(clone->dataSeries() == nullptr);
110 QVERIFY(clone->dataSeries() == nullptr);
111 }
111 }
112 }
112 }
113
113
114 void TestVariable::testNotInCacheRangeList()
114 void TestVariable::testNotInCacheRangeList()
115 {
115 {
116 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
116 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
117 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
117 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
118
118
119 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
119 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
120
120
121 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
121 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
122 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
122 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
123
123
124 auto sqpCR
124 auto sqpCR
125 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
125 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
126
126
127 Variable var{"Var test"};
127 Variable var{"Var test"};
128 var.setRange(sqpR);
128 var.setRange(sqpR);
129 var.setCacheRange(sqpCR);
129 var.setCacheRange(sqpCR);
130
130
131 // 1: [ts,te] < varTS
131 // 1: [ts,te] < varTS
132 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
132 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
133 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
133 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
134 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
134 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
135
135
136 auto notInCach = var.provideNotInCacheRangeList(sqp);
136 auto notInCach = var.provideNotInCacheRangeList(sqp);
137
137
138 QCOMPARE(notInCach.size(), 1);
138 QCOMPARE(notInCach.size(), 1);
139
139
140 auto notInCachRange = notInCach.first();
140 auto notInCachRange = notInCach.first();
141
141
142 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
142 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
143 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
143 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
144
144
145 // 2: ts < varTS < te < varTE
145 // 2: ts < varTS < te < varTE
146 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
146 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
147 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
147 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
148 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
148 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
149 notInCach = var.provideNotInCacheRangeList(sqp);
149 notInCach = var.provideNotInCacheRangeList(sqp);
150 QCOMPARE(notInCach.size(), 1);
150 QCOMPARE(notInCach.size(), 1);
151 notInCachRange = notInCach.first();
151 notInCachRange = notInCach.first();
152 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
152 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
153 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
153 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
154
154
155 // 3: varTS < ts < te < varTE
155 // 3: varTS < ts < te < varTE
156 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
156 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
157 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
157 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
158 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
158 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
159 notInCach = var.provideNotInCacheRangeList(sqp);
159 notInCach = var.provideNotInCacheRangeList(sqp);
160 QCOMPARE(notInCach.size(), 0);
160 QCOMPARE(notInCach.size(), 0);
161
161
162
162
163 // 4: varTS < ts < varTE < te
163 // 4: varTS < ts < varTE < te
164 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
164 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
165 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
165 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
166 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
166 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
167 notInCach = var.provideNotInCacheRangeList(sqp);
167 notInCach = var.provideNotInCacheRangeList(sqp);
168 QCOMPARE(notInCach.size(), 1);
168 QCOMPARE(notInCach.size(), 1);
169 notInCachRange = notInCach.first();
169 notInCachRange = notInCach.first();
170 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
170 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
171 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
171 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
172
172
173 // 5: varTS < varTE < ts < te
173 // 5: varTS < varTE < ts < te
174 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
174 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
175 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
175 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
176 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
176 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
177 notInCach = var.provideNotInCacheRangeList(sqp);
177 notInCach = var.provideNotInCacheRangeList(sqp);
178 QCOMPARE(notInCach.size(), 1);
178 QCOMPARE(notInCach.size(), 1);
179 notInCachRange = notInCach.first();
179 notInCachRange = notInCach.first();
180 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
180 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
181 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
181 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
182
182
183 // 6: ts <varTS < varTE < te
183 // 6: ts <varTS < varTE < te
184 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
184 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
185 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
185 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
186 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
186 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
187 notInCach = var.provideNotInCacheRangeList(sqp);
187 notInCach = var.provideNotInCacheRangeList(sqp);
188 QCOMPARE(notInCach.size(), 2);
188 QCOMPARE(notInCach.size(), 2);
189 notInCachRange = notInCach.first();
189 notInCachRange = notInCach.first();
190 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
190 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
191 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
191 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
192 notInCachRange = notInCach[1];
192 notInCachRange = notInCach[1];
193 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
193 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
194 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
194 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
195 }
195 }
196
196
197
197
198 void TestVariable::testInCacheRangeList()
198 void TestVariable::testInCacheRangeList()
199 {
199 {
200 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
200 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
201 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
201 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
202
202
203 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
203 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
204
204
205 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
205 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
206 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
206 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
207 auto sqpCR
207 auto sqpCR
208 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
208 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
209
209
210 Variable var{"Var test"};
210 Variable var{"Var test"};
211 var.setRange(sqpR);
211 var.setRange(sqpR);
212 var.setCacheRange(sqpCR);
212 var.setCacheRange(sqpCR);
213
213
214 // 1: [ts,te] < varTS
214 // 1: [ts,te] < varTS
215 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
215 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
216 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
216 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
217 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
217 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
218
218
219 auto notInCach = var.provideInCacheRangeList(sqp);
219 auto notInCach = var.provideInCacheRangeList(sqp);
220
220
221 QCOMPARE(notInCach.size(), 0);
221 QCOMPARE(notInCach.size(), 0);
222
222
223 // 2: ts < varTS < te < varTE
223 // 2: ts < varTS < te < varTE
224 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
224 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
225 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
225 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
226 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
226 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
227 notInCach = var.provideInCacheRangeList(sqp);
227 notInCach = var.provideInCacheRangeList(sqp);
228 QCOMPARE(notInCach.size(), 1);
228 QCOMPARE(notInCach.size(), 1);
229 auto notInCachRange = notInCach.first();
229 auto notInCachRange = notInCach.first();
230 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
230 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
231 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
231 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
232
232
233 // 3: varTS < ts < te < varTE
233 // 3: varTS < ts < te < varTE
234 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
234 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
235 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
235 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
236 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
236 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
237 notInCach = var.provideInCacheRangeList(sqp);
237 notInCach = var.provideInCacheRangeList(sqp);
238 QCOMPARE(notInCach.size(), 1);
238 QCOMPARE(notInCach.size(), 1);
239 notInCachRange = notInCach.first();
239 notInCachRange = notInCach.first();
240 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
240 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
241 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
241 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
242
242
243 // 4: varTS < ts < varTE < te
243 // 4: varTS < ts < varTE < te
244 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
244 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
245 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
245 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
246 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
246 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
247 notInCach = var.provideInCacheRangeList(sqp);
247 notInCach = var.provideInCacheRangeList(sqp);
248 QCOMPARE(notInCach.size(), 1);
248 QCOMPARE(notInCach.size(), 1);
249 notInCachRange = notInCach.first();
249 notInCachRange = notInCach.first();
250 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
250 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
251 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
251 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
252
252
253 // 5: varTS < varTE < ts < te
253 // 5: varTS < varTE < ts < te
254 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
254 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
255 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
255 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
256 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
256 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
257 notInCach = var.provideInCacheRangeList(sqp);
257 notInCach = var.provideInCacheRangeList(sqp);
258 QCOMPARE(notInCach.size(), 0);
258 QCOMPARE(notInCach.size(), 0);
259
259
260 // 6: ts <varTS < varTE < te
260 // 6: ts <varTS < varTE < te
261 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
261 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
262 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
262 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
263 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
263 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
264 notInCach = var.provideInCacheRangeList(sqp);
264 notInCach = var.provideInCacheRangeList(sqp);
265 QCOMPARE(notInCach.size(), 1);
265 QCOMPARE(notInCach.size(), 1);
266 notInCachRange = notInCach.first();
266 notInCachRange = notInCach.first();
267 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
267 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
268 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
268 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
269 }
269 }
270
270
271 namespace {
271 namespace {
272
272
273 /// Struct used to represent an operation for @sa TestVariable::testNbPoints()
273 /// Struct used to represent an operation for @sa TestVariable::testNbPoints()
274 struct NbPointsOperation {
274 struct NbPointsOperation {
275 SqpRange m_CacheRange; /// Range to set for the variable
275 SqpRange m_CacheRange; /// Range to set for the variable
276 std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable
276 std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable
277 int m_ExpectedNbPoints; /// Number of points in the variable expected after operation
277 int m_ExpectedNbPoints; /// Number of points in the variable expected after operation
278 };
278 };
279
279
280 using NbPointsOperations = std::vector<NbPointsOperation>;
280 using NbPointsOperations = std::vector<NbPointsOperation>;
281
281
282 } // namespace
282 } // namespace
283
283
284 Q_DECLARE_METATYPE(NbPointsOperations)
284 Q_DECLARE_METATYPE(NbPointsOperations)
285
285
286 void TestVariable::testNbPoints_data()
286 void TestVariable::testNbPoints_data()
287 {
287 {
288 // ////////////// //
288 // ////////////// //
289 // Test structure //
289 // Test structure //
290 // ////////////// //
290 // ////////////// //
291
291
292 QTest::addColumn<NbPointsOperations>("operations");
292 QTest::addColumn<NbPointsOperations>("operations");
293
293
294 // ////////// //
294 // ////////// //
295 // Test cases //
295 // Test cases //
296 // ////////// //
296 // ////////// //
297 NbPointsOperations operations{};
297 NbPointsOperations operations{};
298
298
299 // Sets cache range (expected nb points = series xAxis data + series values data)
299 // Sets cache range (expected nb points = series xAxis data + series values data)
300 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 9)};
300 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 9)};
301 operations.push_back({cacheRange, dataSeries(cacheRange), 20});
301 operations.push_back({cacheRange, dataSeries(cacheRange), 20});
302
302
303 // Doubles cache but don't add data series (expected nb points don't change)
303 // Doubles cache but don't add data series (expected nb points don't change)
304 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)};
304 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)};
305 operations.push_back({cacheRange, nullptr, 20});
305 operations.push_back({cacheRange, dataSeries(INVALID_RANGE), 20});
306
306
307 // Doubles cache and data series (expected nb points change)
307 // Doubles cache and data series (expected nb points change)
308 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)};
308 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)};
309 operations.push_back({cacheRange, dataSeries(cacheRange), 40});
309 operations.push_back({cacheRange, dataSeries(cacheRange), 40});
310
310
311 // Decreases cache (expected nb points decreases as the series is purged)
311 // Decreases cache (expected nb points decreases as the series is purged)
312 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 5), date(2017, 1, 1, 12, 0, 9)};
312 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 5), date(2017, 1, 1, 12, 0, 9)};
313 operations.push_back({cacheRange, nullptr, 10});
313 operations.push_back({cacheRange, dataSeries(INVALID_RANGE), 10});
314
314
315 QTest::newRow("nbPoints1") << operations;
315 QTest::newRow("nbPoints1") << operations;
316 }
316 }
317
317
318 void TestVariable::testNbPoints()
318 void TestVariable::testNbPoints()
319 {
319 {
320 // Creates variable
320 // Creates variable
321 Variable variable{"var"};
321 Variable variable{"var"};
322 QCOMPARE(variable.nbPoints(), 0);
322 QCOMPARE(variable.nbPoints(), 0);
323
323
324 QFETCH(NbPointsOperations, operations);
324 QFETCH(NbPointsOperations, operations);
325 for (const auto &operation : operations) {
325 for (const auto &operation : operations) {
326 // Sets cache range and merge data series
326 // Sets cache range and merge data series
327 variable.setCacheRange(operation.m_CacheRange);
327 variable.setCacheRange(operation.m_CacheRange);
328 if (operation.m_DataSeries != nullptr) {
328 if (operation.m_DataSeries != nullptr) {
329 variable.mergeDataSeries(operation.m_DataSeries);
329 variable.mergeDataSeries(operation.m_DataSeries);
330 }
330 }
331
331
332 // Checks nb points
332 // Checks nb points
333 QCOMPARE(variable.nbPoints(), operation.m_ExpectedNbPoints);
333 QCOMPARE(variable.nbPoints(), operation.m_ExpectedNbPoints);
334 }
334 }
335 }
335 }
336
336
337 namespace {
337 namespace {
338
338
339 /// Struct used to represent a range operation on a variable
339 /// Struct used to represent a range operation on a variable
340 /// @sa TestVariable::testRealRange()
340 /// @sa TestVariable::testRealRange()
341 struct RangeOperation {
341 struct RangeOperation {
342 SqpRange m_CacheRange; /// Range to set for the variable
342 SqpRange m_CacheRange; /// Range to set for the variable
343 std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable
343 std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable
344 SqpRange m_ExpectedRealRange; /// Real Range expected after operation on the variable
344 SqpRange m_ExpectedRealRange; /// Real Range expected after operation on the variable
345 };
345 };
346
346
347 using RangeOperations = std::vector<RangeOperation>;
347 using RangeOperations = std::vector<RangeOperation>;
348
348
349 } // namespace
349 } // namespace
350
350
351 Q_DECLARE_METATYPE(RangeOperations)
351 Q_DECLARE_METATYPE(RangeOperations)
352
352
353 void TestVariable::testRealRange_data()
353 void TestVariable::testRealRange_data()
354 {
354 {
355 // ////////////// //
355 // ////////////// //
356 // Test structure //
356 // Test structure //
357 // ////////////// //
357 // ////////////// //
358
358
359 QTest::addColumn<RangeOperations>("operations");
359 QTest::addColumn<RangeOperations>("operations");
360
360
361 // ////////// //
361 // ////////// //
362 // Test cases //
362 // Test cases //
363 // ////////// //
363 // ////////// //
364 RangeOperations operations{};
364 RangeOperations operations{};
365
365
366 // Inits cache range and data series (expected real range = cache range)
366 // Inits cache range and data series (expected real range = cache range)
367 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)};
367 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)};
368 operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange});
368 operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange});
369
369
370 // Changes cache range and updates data series (expected real range = cache range)
370 // Changes cache range and updates data series (expected real range = cache range)
371 cacheRange = SqpRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)};
371 cacheRange = SqpRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)};
372 operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange});
372 operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange});
373
373
374 // Changes cache range and update data series but with a lower range (expected real range =
374 // Changes cache range and update data series but with a lower range (expected real range =
375 // data series range)
375 // data series range)
376 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 16, 0, 0)};
376 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 16, 0, 0)};
377 auto dataSeriesRange = SqpRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)};
377 auto dataSeriesRange = SqpRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)};
378 operations.push_back({cacheRange, dataSeries(dataSeriesRange), dataSeriesRange});
378 operations.push_back({cacheRange, dataSeries(dataSeriesRange), dataSeriesRange});
379
379
380 // Changes cache range but DON'T update data series (expected real range = cache range
380 // Changes cache range but DON'T update data series (expected real range = cache range
381 // before operation)
381 // before operation)
382 cacheRange = SqpRange{date(2017, 1, 1, 10, 0, 0), date(2017, 1, 1, 17, 0, 0)};
382 cacheRange = SqpRange{date(2017, 1, 1, 10, 0, 0), date(2017, 1, 1, 17, 0, 0)};
383 operations.push_back({cacheRange, nullptr, dataSeriesRange});
383 operations.push_back({cacheRange, nullptr, dataSeriesRange});
384
384
385 QTest::newRow("realRange1") << operations;
385 QTest::newRow("realRange1") << operations;
386 }
386 }
387
387
388 void TestVariable::testRealRange()
388 void TestVariable::testRealRange()
389 {
389 {
390 // Creates variable (real range is invalid)
390 // Creates variable (real range is invalid)
391 Variable variable{"var"};
391 Variable variable{"var"};
392 QCOMPARE(variable.realRange(), INVALID_RANGE);
392 QCOMPARE(variable.realRange(), INVALID_RANGE);
393
393
394 QFETCH(RangeOperations, operations);
394 QFETCH(RangeOperations, operations);
395 for (const auto &operation : operations) {
395 for (const auto &operation : operations) {
396 // Sets cache range and merge data series
396 // Sets cache range and merge data series
397 variable.setCacheRange(operation.m_CacheRange);
397 variable.setCacheRange(operation.m_CacheRange);
398 if (operation.m_DataSeries != nullptr) {
398 if (operation.m_DataSeries != nullptr) {
399 variable.mergeDataSeries(operation.m_DataSeries);
399 variable.mergeDataSeries(operation.m_DataSeries);
400 }
400 }
401
401
402 // Checks real range
402 // Checks real range
403 QCOMPARE(variable.realRange(), operation.m_ExpectedRealRange);
403 QCOMPARE(variable.realRange(), operation.m_ExpectedRealRange);
404 }
404 }
405 }
405 }
406
406
407
407
408 QTEST_MAIN(TestVariable)
408 QTEST_MAIN(TestVariable)
409 #include "TestVariable.moc"
409 #include "TestVariable.moc"
@@ -1,390 +1,506
1 #include <QObject>
1 #include <QObject>
2 #include <QtTest>
2 #include <QtTest>
3
3
4 #include <memory>
4 #include <memory>
5
5
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Data/IDataProvider.h>
7 #include <Data/IDataProvider.h>
8 #include <Data/ScalarSeries.h>
8 #include <Data/ScalarSeries.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11 #include <Variable/VariableController.h>
11 #include <Variable/VariableController.h>
12 #include <Variable/VariableModel.h>
12 #include <Variable/VariableModel.h>
13
13
14 namespace {
14 namespace {
15
15
16 /// Delay after each operation on the variable before validating it (in ms)
16 /// Delay after each operation on the variable before validating it (in ms)
17 const auto OPERATION_DELAY = 100;
17 const auto OPERATION_DELAY = 100;
18
18
19 /**
19 /**
20 * Generates values according to a range. The value generated for a time t is the number of seconds
20 * Generates values according to a range. The value generated for a time t is the number of seconds
21 * of difference between t and a reference value (which is midnight -> 00:00:00)
21 * of difference between t and a reference value (which is midnight -> 00:00:00)
22 *
22 *
23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
24 * {10,11,12,13,14,15,16,17,18,19,20}
24 * {10,11,12,13,14,15,16,17,18,19,20}
25 */
25 */
26 std::vector<double> values(const SqpRange &range)
26 std::vector<double> values(const SqpRange &range)
27 {
27 {
28 QTime referenceTime{0, 0};
28 QTime referenceTime{0, 0};
29
29
30 std::vector<double> result{};
30 std::vector<double> result{};
31
31
32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
33 auto time = DateUtils::dateTime(i).time();
33 auto time = DateUtils::dateTime(i).time();
34 result.push_back(referenceTime.secsTo(time));
34 result.push_back(referenceTime.secsTo(time));
35 }
35 }
36
36
37 return result;
37 return result;
38 }
38 }
39
39
40 void validateRanges(VariableController &variableController,
41 const std::map<int, SqpRange> &expectedRanges)
42 {
43 for (const auto &expectedRangeEntry : expectedRanges) {
44 auto variableIndex = expectedRangeEntry.first;
45 auto expectedRange = expectedRangeEntry.second;
46
47 // Gets the variable in the controller
48 auto variable = variableController.variableModel()->variable(variableIndex);
49
50 // Compares variable's range to the expected range
51 QVERIFY(variable != nullptr);
52 auto range = variable->range();
53 qInfo() << "range vs expected range" << range << expectedRange;
54 QCOMPARE(range, expectedRange);
55
56 // Compares variable's data with values expected for its range
57 auto dataSeries = variable->dataSeries();
58 QVERIFY(dataSeries != nullptr);
59
60 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
61 auto expectedValues = values(range);
62 qInfo() << std::distance(it.first, it.second) << expectedValues.size();
63 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
64 [](const auto &dataSeriesIt, const auto &expectedValue) {
65 return dataSeriesIt.value() == expectedValue;
66 }));
67 }
68 }
69
40 /// Provider used for the tests
70 /// Provider used for the tests
41 class TestProvider : public IDataProvider {
71 class TestProvider : public IDataProvider {
42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
72 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
43
73
44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
74 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
45 {
75 {
46 const auto &ranges = parameters.m_Times;
76 const auto &ranges = parameters.m_Times;
47
77
48 for (const auto &range : ranges) {
78 for (const auto &range : ranges) {
49 // Generates data series
79 // Generates data series
50 auto valuesData = values(range);
80 auto valuesData = values(range);
51
81
52 std::vector<double> xAxisData{};
82 std::vector<double> xAxisData{};
53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
83 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
54 xAxisData.push_back(i);
84 xAxisData.push_back(i);
55 }
85 }
56
86
57 auto dataSeries = std::make_shared<ScalarSeries>(
87 auto dataSeries = std::make_shared<ScalarSeries>(
58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
88 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
59
89
60 emit dataProvided(acqIdentifier, dataSeries, range);
90 emit dataProvided(acqIdentifier, dataSeries, range);
61 }
91 }
62 }
92 }
63
93
64 void requestDataAborting(QUuid acqIdentifier) override
94 void requestDataAborting(QUuid acqIdentifier) override
65 {
95 {
66 // Does nothing
96 // Does nothing
67 }
97 }
68 };
98 };
69
99
70 /**
100 /**
71 * Interface representing an operation performed on a variable controller.
101 * Interface representing an operation performed on a variable controller.
72 * This interface is used in tests to apply a set of operations and check the status of the
102 * This interface is used in tests to apply a set of operations and check the status of the
73 * controller after each operation
103 * controller after each operation
74 */
104 */
75 struct IOperation {
105 struct IOperation {
76 virtual ~IOperation() = default;
106 virtual ~IOperation() = default;
77 /// Executes the operation on the variable controller
107 /// Executes the operation on the variable controller
78 virtual void exec(VariableController &variableController) const = 0;
108 virtual void exec(VariableController &variableController) const = 0;
79 };
109 };
80
110
81 /**
111 /**
82 *Variable creation operation in the controller
112 *Variable creation operation in the controller
83 */
113 */
84 struct Create : public IOperation {
114 struct Create : public IOperation {
85 explicit Create(int index) : m_Index{index} {}
115 explicit Create(int index) : m_Index{index} {}
86
116
87 void exec(VariableController &variableController) const override
117 void exec(VariableController &variableController) const override
88 {
118 {
89 auto variable = variableController.createVariable(QString::number(m_Index), {},
119 auto variable = variableController.createVariable(QString::number(m_Index), {},
90 std::make_unique<TestProvider>());
120 std::make_unique<TestProvider>());
91 }
121 }
92
122
93 int m_Index; ///< The index of the variable to create in the controller
123 int m_Index; ///< The index of the variable to create in the controller
94 };
124 };
95
125
96 /**
126 /**
97 * Variable move/shift operation in the controller
127 * Variable move/shift operation in the controller
98 */
128 */
99 struct Move : public IOperation {
129 struct Move : public IOperation {
100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
130 explicit Move(int index, const SqpRange &newRange, bool shift = false, int delayMS = 10)
101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
131 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}, m_DelayMs{delayMS}
102 {
132 {
103 }
133 }
104
134
105 void exec(VariableController &variableController) const override
135 void exec(VariableController &variableController) const override
106 {
136 {
107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
137 if (auto variable = variableController.variableModel()->variable(m_Index)) {
108 variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift);
138 variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift);
139 QTest::qWait(m_DelayMs);
109 }
140 }
110 }
141 }
111
142
112 int m_Index; ///< The index of the variable to move
143 int m_Index; ///< The index of the variable to move
113 SqpRange m_NewRange; ///< The new range of the variable
144 SqpRange m_NewRange; ///< The new range of the variable
114 bool m_Shift; ///< Performs a shift (
145 bool m_Shift; ///< Performs a shift (
146 int m_DelayMs; ///< wait the delay after running the request (
115 };
147 };
116
148
117 /**
149 /**
118 * Variable synchronization/desynchronization operation in the controller
150 * Variable synchronization/desynchronization operation in the controller
119 */
151 */
120 struct Synchronize : public IOperation {
152 struct Synchronize : public IOperation {
121 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
153 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
122 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
154 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
123 {
155 {
124 }
156 }
125
157
126 void exec(VariableController &variableController) const override
158 void exec(VariableController &variableController) const override
127 {
159 {
128 if (auto variable = variableController.variableModel()->variable(m_Index)) {
160 if (auto variable = variableController.variableModel()->variable(m_Index)) {
129 if (m_Synchronize) {
161 if (m_Synchronize) {
130 variableController.onAddSynchronized(variable, m_SyncId);
162 variableController.onAddSynchronized(variable, m_SyncId);
131 }
163 }
132 else {
164 else {
133 variableController.desynchronize(variable, m_SyncId);
165 variableController.desynchronize(variable, m_SyncId);
134 }
166 }
135 }
167 }
136 }
168 }
137
169
138 int m_Index; ///< The index of the variable to sync/desync
170 int m_Index; ///< The index of the variable to sync/desync
139 QUuid m_SyncId; ///< The synchronization group of the variable
171 QUuid m_SyncId; ///< The synchronization group of the variable
140 bool m_Synchronize; ///< Performs sync or desync operation
172 bool m_Synchronize; ///< Performs sync or desync operation
141 };
173 };
142
174
143 /**
175 /**
144 * Test Iteration
176 * Test Iteration
145 *
177 *
146 * A test iteration includes an operation to be performed, and a set of expected ranges after each
178 * A test iteration includes an operation to be performed, and a set of expected ranges after each
147 * operation. Each range is tested after the operation to ensure that:
179 * operation. Each range is tested after the operation to ensure that:
148 * - the range of the variable is the expected range
180 * - the range of the variable is the expected range
149 * - the data of the variable are those generated for the expected range
181 * - the data of the variable are those generated for the expected range
150 */
182 */
151 struct Iteration {
183 struct Iteration {
152 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
184 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
153 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
185 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
154 };
186 };
155
187
156 using Iterations = std::vector<Iteration>;
188 using Iterations = std::vector<Iteration>;
157
189
158 } // namespace
190 } // namespace
159
191
160 Q_DECLARE_METATYPE(Iterations)
192 Q_DECLARE_METATYPE(Iterations)
161
193
162 class TestVariableSync : public QObject {
194 class TestVariableSync : public QObject {
163 Q_OBJECT
195 Q_OBJECT
164
196
165 private slots:
197 private slots:
166 /// Input data for @sa testSync()
198 /// Input data for @sa testSync()
167 void testSync_data();
199 void testSync_data();
168
200
201 /// Input data for @sa testSyncOneVar()
202 void testSyncOneVar_data();
203
169 /// Tests synchronization between variables through several operations
204 /// Tests synchronization between variables through several operations
170 void testSync();
205 void testSync();
206
207 /// Tests synchronization between variables through several operations
208 void testSyncOneVar();
171 };
209 };
172
210
173 namespace {
211 namespace {
174
212
175 void testSyncCase1()
213 void testSyncCase1()
176 {
214 {
177 // Id used to synchronize variables in the controller
215 // Id used to synchronize variables in the controller
178 auto syncId = QUuid::createUuid();
216 auto syncId = QUuid::createUuid();
179
217
180 /// Generates a range according to a start time and a end time (the date is the same)
218 /// Generates a range according to a start time and a end time (the date is the same)
181 auto range = [](const QTime &startTime, const QTime &endTime) {
219 auto range = [](const QTime &startTime, const QTime &endTime) {
182 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
220 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
183 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
221 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
184 };
222 };
185
223
186 auto initialRange = range({12, 0}, {13, 0});
224 auto initialRange = range({12, 0}, {13, 0});
187
225
188 Iterations iterations{};
226 Iterations iterations{};
189 // Creates variables var0, var1 and var2
227 // Creates variables var0, var1 and var2
190 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
228 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
191 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
229 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
192 iterations.push_back(
230 iterations.push_back(
193 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
231 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
194
232
195 // Adds variables into the sync group (ranges don't need to be tested here)
233 // Adds variables into the sync group (ranges don't need to be tested here)
196 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
234 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
197 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
235 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
198 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
236 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
199
237
200 // Moves var0: ranges of var0, var1 and var2 change
238 // Moves var0: ranges of var0, var1 and var2 change
201 auto newRange = range({12, 30}, {13, 30});
239 auto newRange = range({12, 30}, {13, 30});
202 iterations.push_back(
240 iterations.push_back(
203 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
241 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
204
242
205 // Moves var1: ranges of var0, var1 and var2 change
243 // Moves var1: ranges of var0, var1 and var2 change
206 newRange = range({13, 0}, {14, 0});
244 newRange = range({13, 0}, {14, 0});
207 iterations.push_back(
245 iterations.push_back(
208 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
246 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
209
247
210 // Moves var2: ranges of var0, var1 and var2 change
248 // Moves var2: ranges of var0, var1 and var2 change
211 newRange = range({13, 30}, {14, 30});
249 newRange = range({13, 30}, {14, 30});
212 iterations.push_back(
250 iterations.push_back(
213 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
251 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
214
252
215 // Desyncs var2 and moves var0:
253 // Desyncs var2 and moves var0:
216 // - ranges of var0 and var1 change
254 // - ranges of var0 and var1 change
217 // - range of var2 doesn't change anymore
255 // - range of var2 doesn't change anymore
218 auto var2Range = newRange;
256 auto var2Range = newRange;
219 newRange = range({13, 45}, {14, 45});
257 newRange = range({13, 45}, {14, 45});
220 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
258 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
221 iterations.push_back(
259 iterations.push_back(
222 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
260 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
223
261
224 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
262 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
225 auto var1Range = newRange;
263 auto var1Range = newRange;
226 newRange = range({14, 45}, {15, 45});
264 newRange = range({14, 45}, {15, 45});
227 iterations.push_back({std::make_shared<Move>(0, newRange, true),
265 iterations.push_back({std::make_shared<Move>(0, newRange, true),
228 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
266 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
229
267
230 // Moves var0 through several operations:
268 // Moves var0 through several operations:
231 // - range of var0 changes
269 // - range of var0 changes
232 // - range or var1 changes according to the previous shift (one hour)
270 // - range or var1 changes according to the previous shift (one hour)
233 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
271 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
234 iterations.push_back(
272 iterations.push_back(
235 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
273 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
236 };
274 };
275
237 // Pan left
276 // Pan left
238 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
277 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
239 // Pan right
278 // Pan right
240 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
279 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
241 // Zoom in
280 // Zoom in
242 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
281 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
243 // Zoom out
282 // Zoom out
244 moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0}));
283 moveVar0(range({16, 15}, {17, 0}), range({15, 15}, {16, 0}));
245
284
246 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
285 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
247 }
286 }
248
287
249 void testSyncCase2()
288 void testSyncCase2()
250 {
289 {
251 // Id used to synchronize variables in the controller
290 // Id used to synchronize variables in the controller
252 auto syncId = QUuid::createUuid();
291 auto syncId = QUuid::createUuid();
253
292
254 /// Generates a range according to a start time and a end time (the date is the same)
293 /// Generates a range according to a start time and a end time (the date is the same)
255 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
294 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
256 return DateUtils::secondsSinceEpoch(
295 return DateUtils::secondsSinceEpoch(
257 QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
296 QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
258 };
297 };
259
298
260 auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
299 auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
261
300
262 Iterations iterations{};
301 Iterations iterations{};
263 // Creates variables var0 and var1
302 // Creates variables var0 and var1
264 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
303 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
265 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
304 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
266
305
267 // Adds variables into the sync group (ranges don't need to be tested here)
306 // Adds variables into the sync group (ranges don't need to be tested here)
268 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
307 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
269 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
308 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
270
309
271
310
272 // Moves var0 through several operations:
311 // Moves var0 through several operations:
273 // - range of var0 changes
312 // - range of var0 changes
274 // - range or var1 changes according to the previous shift (one hour)
313 // - range or var1 changes according to the previous shift (one hour)
275 auto moveVar0 = [&iterations](const auto &var0NewRange) {
314 auto moveVar0 = [&iterations](const auto &var0NewRange) {
276 iterations.push_back(
315 iterations.push_back(
277 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
316 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
278 };
317 };
279 moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
318 moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
280 moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
319 moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
281 moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
320 moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
282 // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
321 // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
283 moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
322 moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
284 moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
323 moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
285
324
286 moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
325 moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
287 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
326 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
288 moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
327 moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
289
328
290 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
329 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
291 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
330 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
292 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
331 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
293 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
332 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
294 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
333 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
295 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
334 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
296 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
335 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
297 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
336 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
298 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
337 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
299 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
338 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
300 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
339 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
301 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
340 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
302
341
303
342
304 QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
343 QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
305 // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
344 // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
306 }
345 }
346
347 void testSyncOnVarCase1()
348 {
349 // Id used to synchronize variables in the controller
350 auto syncId = QUuid::createUuid();
351
352 /// Generates a range according to a start time and a end time (the date is the same)
353 auto range = [](const QTime &startTime, const QTime &endTime) {
354 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
355 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
356 };
357
358 auto initialRange = range({12, 0}, {13, 0});
359
360 Iterations creations{};
361 // Creates variables var0, var1 and var2
362 creations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
363
364 Iterations synchronization{};
365 // Adds variables into the sync group (ranges don't need to be tested here)
366 synchronization.push_back({std::make_shared<Synchronize>(0, syncId)});
367
368 Iterations iterations{};
369
370 // Moves var0 through several operations
371 auto moveOp = [&iterations](const auto &requestedRange, const auto &expectedRange, auto delay) {
372 iterations.push_back(
373 {std::make_shared<Move>(0, requestedRange, true, delay), {{0, expectedRange}}});
374 };
375
376 // we assume here 300 ms is enough to finsh a operation
377 int delayToFinish = 300;
378 // jump to right, let's the operation time to finish
379 moveOp(range({14, 30}, {15, 30}), range({14, 30}, {15, 30}), delayToFinish);
380 // pan to right, let's the operation time to finish
381 moveOp(range({14, 45}, {15, 45}), range({14, 45}, {15, 45}), delayToFinish);
382 // jump to left, let's the operation time to finish
383 moveOp(range({03, 30}, {04, 30}), range({03, 30}, {04, 30}), delayToFinish);
384 // Pan to left, let's the operation time to finish
385 moveOp(range({03, 10}, {04, 10}), range({03, 10}, {04, 10}), delayToFinish);
386 // Zoom in, let's the operation time to finish
387 moveOp(range({03, 30}, {04, 00}), range({03, 30}, {04, 00}), delayToFinish);
388 // Zoom out left, let's the operation time to finish
389 moveOp(range({01, 10}, {18, 10}), range({01, 10}, {18, 10}), delayToFinish);
390 // Go back to initial range
391 moveOp(initialRange, initialRange, delayToFinish);
392
393
394 // jump to right, let's the operation time to finish
395 // moveOp(range({14, 30}, {15, 30}), initialRange, delayToFinish);
396 // Zoom out left, let's the operation time to finish
397 moveOp(range({01, 10}, {18, 10}), initialRange, delayToFinish);
398 // Go back to initial range
399 moveOp(initialRange, initialRange, 300);
400
401 QTest::newRow("syncOnVarCase1") << syncId << initialRange << std::move(creations)
402 << std::move(iterations);
403 }
307 }
404 }
308
405
309 void TestVariableSync::testSync_data()
406 void TestVariableSync::testSync_data()
310 {
407 {
311 // ////////////// //
408 // ////////////// //
312 // Test structure //
409 // Test structure //
313 // ////////////// //
410 // ////////////// //
314
411
315 QTest::addColumn<QUuid>("syncId");
412 QTest::addColumn<QUuid>("syncId");
316 QTest::addColumn<SqpRange>("initialRange");
413 QTest::addColumn<SqpRange>("initialRange");
317 QTest::addColumn<Iterations>("iterations");
414 QTest::addColumn<Iterations>("iterations");
318 QTest::addColumn<int>("operationDelay");
415 QTest::addColumn<int>("operationDelay");
319
416
320 // ////////// //
417 // ////////// //
321 // Test cases //
418 // Test cases //
322 // ////////// //
419 // ////////// //
323
420
324 testSyncCase1();
421 testSyncCase1();
325 testSyncCase2();
422 testSyncCase2();
326 }
423 }
327
424
425 void TestVariableSync::testSyncOneVar_data()
426 {
427 // ////////////// //
428 // Test structure //
429 // ////////////// //
430
431 QTest::addColumn<QUuid>("syncId");
432 QTest::addColumn<SqpRange>("initialRange");
433 QTest::addColumn<Iterations>("creations");
434 QTest::addColumn<Iterations>("iterations");
435
436 // ////////// //
437 // Test cases //
438 // ////////// //
439
440 testSyncOnVarCase1();
441 }
442
328 void TestVariableSync::testSync()
443 void TestVariableSync::testSync()
329 {
444 {
330 // Inits controllers
445 // Inits controllers
331 TimeController timeController{};
446 TimeController timeController{};
332 VariableController variableController{};
447 VariableController variableController{};
333 variableController.setTimeController(&timeController);
448 variableController.setTimeController(&timeController);
334
449
335 QFETCH(QUuid, syncId);
450 QFETCH(QUuid, syncId);
336 QFETCH(SqpRange, initialRange);
451 QFETCH(SqpRange, initialRange);
337 timeController.onTimeToUpdate(initialRange);
452 timeController.onTimeToUpdate(initialRange);
338
453
339 // Synchronization group used
454 // Synchronization group used
340 variableController.onAddSynchronizationGroupId(syncId);
455 variableController.onAddSynchronizationGroupId(syncId);
341
456
342 auto validateRanges = [&variableController](const auto &expectedRanges) {
343 for (const auto &expectedRangeEntry : expectedRanges) {
344 auto variableIndex = expectedRangeEntry.first;
345 auto expectedRange = expectedRangeEntry.second;
346
347 // Gets the variable in the controller
348 auto variable = variableController.variableModel()->variable(variableIndex);
349
350 // Compares variable's range to the expected range
351 QVERIFY(variable != nullptr);
352 auto range = variable->range();
353 QCOMPARE(range, expectedRange);
354
355 // Compares variable's data with values expected for its range
356 auto dataSeries = variable->dataSeries();
357 QVERIFY(dataSeries != nullptr);
358
359 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
360 auto expectedValues = values(range);
361 qInfo() << std::distance(it.first, it.second) << expectedValues.size();
362 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
363 [](const auto &dataSeriesIt, const auto &expectedValue) {
364 return dataSeriesIt.value() == expectedValue;
365 }));
366 }
367 };
368
369 // For each iteration:
457 // For each iteration:
370 // - execute operation
458 // - execute operation
371 // - compare the variables' state to the expected states
459 // - compare the variables' state to the expected states
372 QFETCH(Iterations, iterations);
460 QFETCH(Iterations, iterations);
373 QFETCH(int, operationDelay);
461 QFETCH(int, operationDelay);
374 for (const auto &iteration : iterations) {
462 for (const auto &iteration : iterations) {
375 iteration.m_Operation->exec(variableController);
463 iteration.m_Operation->exec(variableController);
376 QTest::qWait(operationDelay);
464 QTest::qWait(operationDelay);
377
465
378 validateRanges(iteration.m_ExpectedRanges);
466 validateRanges(variableController, iteration.m_ExpectedRanges);
467 }
468 }
469
470 void TestVariableSync::testSyncOneVar()
471 {
472 // Inits controllers
473 TimeController timeController{};
474 VariableController variableController{};
475 variableController.setTimeController(&timeController);
476
477 QFETCH(QUuid, syncId);
478 QFETCH(SqpRange, initialRange);
479 timeController.onTimeToUpdate(initialRange);
480
481 // Synchronization group used
482 variableController.onAddSynchronizationGroupId(syncId);
483
484 // For each iteration:
485 // - execute operation
486 // - compare the variables' state to the expected states
487 QFETCH(Iterations, iterations);
488 QFETCH(Iterations, creations);
489
490 for (const auto &creation : creations) {
491 creation.m_Operation->exec(variableController);
492 QTest::qWait(300);
379 }
493 }
380
494
381 for (const auto &iteration : iterations) {
495 for (const auto &iteration : iterations) {
382 iteration.m_Operation->exec(variableController);
496 iteration.m_Operation->exec(variableController);
383 }
497 }
384 QTest::qWait(operationDelay);
498
385 validateRanges(iterations.back().m_ExpectedRanges);
499 if (!iterations.empty()) {
500 validateRanges(variableController, iterations.back().m_ExpectedRanges);
501 }
386 }
502 }
387
503
388 QTEST_MAIN(TestVariableSync)
504 QTEST_MAIN(TestVariableSync)
389
505
390 #include "TestVariableSync.moc"
506 #include "TestVariableSync.moc"
@@ -1,285 +1,282
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 #include "AmdaDefs.h"
3 #include "AmdaResultParser.h"
3 #include "AmdaResultParser.h"
4
4
5 #include <Common/DateUtils.h>
5 #include <Common/DateUtils.h>
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Network/NetworkController.h>
7 #include <Network/NetworkController.h>
8 #include <SqpApplication.h>
8 #include <SqpApplication.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10
10
11 #include <QNetworkAccessManager>
11 #include <QNetworkAccessManager>
12 #include <QNetworkReply>
12 #include <QNetworkReply>
13 #include <QTemporaryFile>
13 #include <QTemporaryFile>
14 #include <QThread>
14 #include <QThread>
15
15
16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17
17
18 namespace {
18 namespace {
19
19
20 /// URL format for a request on AMDA server. The parameters are as follows:
20 /// URL format for a request on AMDA server. The parameters are as follows:
21 /// - %1: start date
21 /// - %1: start date
22 /// - %2: end date
22 /// - %2: end date
23 /// - %3: parameter id
23 /// - %3: parameter id
24 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
24 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
25 const auto AMDA_URL_FORMAT = QStringLiteral(
25 const auto AMDA_URL_FORMAT = QStringLiteral(
26 "http://amda.irap.omp.eu/php/rest/"
26 "http://amda.irap.omp.eu/php/rest/"
27 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
27 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
28 "timeFormat=ISO8601&gzip=0");
28 "timeFormat=ISO8601&gzip=0");
29
29
30 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
30 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
31 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
31 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
32
32
33 /// Formats a time to a date that can be passed in URL
33 /// Formats a time to a date that can be passed in URL
34 QString dateFormat(double sqpRange) noexcept
34 QString dateFormat(double sqpRange) noexcept
35 {
35 {
36 auto dateTime = DateUtils::dateTime(sqpRange);
36 auto dateTime = DateUtils::dateTime(sqpRange);
37 return dateTime.toString(AMDA_TIME_FORMAT);
37 return dateTime.toString(AMDA_TIME_FORMAT);
38 }
38 }
39
39
40 AmdaResultParser::ValueType valueType(const QString &valueType)
40 AmdaResultParser::ValueType valueType(const QString &valueType)
41 {
41 {
42 if (valueType == QStringLiteral("scalar")) {
42 if (valueType == QStringLiteral("scalar")) {
43 return AmdaResultParser::ValueType::SCALAR;
43 return AmdaResultParser::ValueType::SCALAR;
44 }
44 }
45 else if (valueType == QStringLiteral("vector")) {
45 else if (valueType == QStringLiteral("vector")) {
46 return AmdaResultParser::ValueType::VECTOR;
46 return AmdaResultParser::ValueType::VECTOR;
47 }
47 }
48 else {
48 else {
49 return AmdaResultParser::ValueType::UNKNOWN;
49 return AmdaResultParser::ValueType::UNKNOWN;
50 }
50 }
51 }
51 }
52
52
53 } // namespace
53 } // namespace
54
54
55 AmdaProvider::AmdaProvider()
55 AmdaProvider::AmdaProvider()
56 {
56 {
57 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
57 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
58 if (auto app = sqpApp) {
58 if (auto app = sqpApp) {
59 auto &networkController = app->networkController();
59 auto &networkController = app->networkController();
60 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
60 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
61 std::function<void(QNetworkReply *, QUuid)>)),
61 std::function<void(QNetworkReply *, QUuid)>)),
62 &networkController,
62 &networkController,
63 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
63 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
64 std::function<void(QNetworkReply *, QUuid)>)));
64 std::function<void(QNetworkReply *, QUuid)>)));
65
65
66
66
67 connect(&sqpApp->networkController(),
67 connect(&sqpApp->networkController(),
68 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
68 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
69 this,
69 this,
70 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
70 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
71 }
71 }
72 }
72 }
73
73
74 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
74 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
75 {
75 {
76 // No copy is made in the clone
76 // No copy is made in the clone
77 return std::make_shared<AmdaProvider>();
77 return std::make_shared<AmdaProvider>();
78 }
78 }
79
79
80 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
80 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
81 {
81 {
82 // NOTE: Try to use multithread if possible
82 // NOTE: Try to use multithread if possible
83 const auto times = parameters.m_Times;
83 const auto times = parameters.m_Times;
84 const auto data = parameters.m_Data;
84 const auto data = parameters.m_Data;
85 for (const auto &dateTime : qAsConst(times)) {
85 for (const auto &dateTime : qAsConst(times)) {
86 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
86 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
87 << dateTime;
87 << dateTime;
88 this->retrieveData(acqIdentifier, dateTime, data);
88 this->retrieveData(acqIdentifier, dateTime, data);
89
89
90
90
91 // TORM when AMDA will support quick asynchrone request
91 // TORM when AMDA will support quick asynchrone request
92 QThread::msleep(1000);
92 QThread::msleep(1000);
93 }
93 }
94 }
94 }
95
95
96 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
96 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
97 {
97 {
98 if (auto app = sqpApp) {
98 if (auto app = sqpApp) {
99 auto &networkController = app->networkController();
99 auto &networkController = app->networkController();
100 networkController.onReplyCanceled(acqIdentifier);
100 networkController.onReplyCanceled(acqIdentifier);
101 }
101 }
102 }
102 }
103
103
104 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
104 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
105 std::shared_ptr<QNetworkRequest> networkRequest,
105 std::shared_ptr<QNetworkRequest> networkRequest,
106 double progress)
106 double progress)
107 {
107 {
108 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
108 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
109 << networkRequest.get() << progress;
109 << networkRequest.get() << progress;
110 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
110 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
111 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
111 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
112
112
113 // Update the progression for the current request
113 // Update the progression for the current request
114 auto requestPtr = networkRequest;
114 auto requestPtr = networkRequest;
115 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
115 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
116
116
117 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
117 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
118 auto requestProgressMapEnd = requestProgressMap.end();
118 auto requestProgressMapEnd = requestProgressMap.end();
119 auto requestProgressMapIt
119 auto requestProgressMapIt
120 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
120 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
121
121
122 if (requestProgressMapIt != requestProgressMapEnd) {
122 if (requestProgressMapIt != requestProgressMapEnd) {
123 requestProgressMapIt->second = progress;
123 requestProgressMapIt->second = progress;
124 }
124 }
125 else {
125 else {
126 // This case can happened when a progression is send after the request has been
126 // This case can happened when a progression is send after the request has been
127 // finished.
127 // finished.
128 // Generaly the case when aborting a request
128 // Generaly the case when aborting a request
129 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
129 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
130 << networkRequest.get() << progress;
130 << networkRequest.get() << progress;
131 }
131 }
132
132
133 // Compute the current final progress and notify it
133 // Compute the current final progress and notify it
134 double finalProgress = 0.0;
134 double finalProgress = 0.0;
135
135
136 auto fraq = requestProgressMap.size();
136 auto fraq = requestProgressMap.size();
137
137
138 for (auto requestProgress : requestProgressMap) {
138 for (auto requestProgress : requestProgressMap) {
139 finalProgress += requestProgress.second;
139 finalProgress += requestProgress.second;
140 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
140 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
141 << finalProgress << requestProgress.second;
141 << finalProgress << requestProgress.second;
142 }
142 }
143
143
144 if (fraq > 0) {
144 if (fraq > 0) {
145 finalProgress = finalProgress / fraq;
145 finalProgress = finalProgress / fraq;
146 }
146 }
147
147
148 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
148 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
149 emit dataProvidedProgress(acqIdentifier, finalProgress);
149 emit dataProvidedProgress(acqIdentifier, finalProgress);
150 }
150 }
151 else {
151 else {
152 // This case can happened when a progression is send after the request has been finished.
152 // This case can happened when a progression is send after the request has been finished.
153 // Generaly the case when aborting a request
153 // Generaly the case when aborting a request
154 emit dataProvidedProgress(acqIdentifier, 100.0);
154 emit dataProvidedProgress(acqIdentifier, 100.0);
155 }
155 }
156 }
156 }
157
157
158 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
158 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
159 {
159 {
160 // Retrieves product ID from data: if the value is invalid, no request is made
160 // Retrieves product ID from data: if the value is invalid, no request is made
161 auto productId = data.value(AMDA_XML_ID_KEY).toString();
161 auto productId = data.value(AMDA_XML_ID_KEY).toString();
162 if (productId.isNull()) {
162 if (productId.isNull()) {
163 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
163 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
164 return;
164 return;
165 }
165 }
166
166
167 // Retrieves the data type that determines whether the expected format for the result file is
167 // Retrieves the data type that determines whether the expected format for the result file is
168 // scalar, vector...
168 // scalar, vector...
169 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
169 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
170
170
171 // /////////// //
171 // /////////// //
172 // Creates URL //
172 // Creates URL //
173 // /////////// //
173 // /////////// //
174
174
175 auto startDate = dateFormat(dateTime.m_TStart);
175 auto startDate = dateFormat(dateTime.m_TStart);
176 auto endDate = dateFormat(dateTime.m_TEnd);
176 auto endDate = dateFormat(dateTime.m_TEnd);
177
177
178 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
178 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
179 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
179 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
180 auto tempFile = std::make_shared<QTemporaryFile>();
180 auto tempFile = std::make_shared<QTemporaryFile>();
181
181
182 // LAMBDA
182 // LAMBDA
183 auto httpDownloadFinished = [this, dateTime, tempFile,
183 auto httpDownloadFinished = [this, dateTime, tempFile,
184 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
184 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
185
185
186 // Don't do anything if the reply was abort
186 // Don't do anything if the reply was abort
187 if (reply->error() == QNetworkReply::NoError) {
187 if (reply->error() == QNetworkReply::NoError) {
188
188
189 if (tempFile) {
189 if (tempFile) {
190 auto replyReadAll = reply->readAll();
190 auto replyReadAll = reply->readAll();
191 if (!replyReadAll.isEmpty()) {
191 if (!replyReadAll.isEmpty()) {
192 tempFile->write(replyReadAll);
192 tempFile->write(replyReadAll);
193 }
193 }
194 tempFile->close();
194 tempFile->close();
195
195
196 // Parse results file
196 // Parse results file
197 if (auto dataSeries
197 if (auto dataSeries
198 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
198 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
199 emit dataProvided(dataId, dataSeries, dateTime);
199 emit dataProvided(dataId, dataSeries, dateTime);
200 }
200 }
201 else {
201 else {
202 /// @todo ALX : debug
202 /// @todo ALX : debug
203 emit dataProvidedFailed(dataId);
203 emit dataProvidedFailed(dataId);
204 }
204 }
205 }
205 }
206 qCDebug(LOG_AmdaProvider()) << tr("acquisition requests erase because of finishing")
207 << dataId;
208 m_AcqIdToRequestProgressMap.erase(dataId);
206 m_AcqIdToRequestProgressMap.erase(dataId);
209 }
207 }
210 else {
208 else {
211 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
209 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
212 emit dataProvidedFailed(dataId);
210 emit dataProvidedFailed(dataId);
213 }
211 }
214
212
215 };
213 };
216 auto httpFinishedLambda
214 auto httpFinishedLambda
217 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
215 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
218
216
219 // Don't do anything if the reply was abort
217 // Don't do anything if the reply was abort
220 if (reply->error() == QNetworkReply::NoError) {
218 if (reply->error() == QNetworkReply::NoError) {
221 // AMDA v2: auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
219 // AMDA v2: auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
222 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
220 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
223
221
224 qCInfo(LOG_AmdaProvider())
222 qCInfo(LOG_AmdaProvider())
225 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
223 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
226 // Executes request for downloading file //
224 // Executes request for downloading file //
227
225
228 // Creates destination file
226 // Creates destination file
229 if (tempFile->open()) {
227 if (tempFile->open()) {
230 // Executes request and store the request for progression
228 // Executes request and store the request for progression
231 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
229 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
232 updateRequestProgress(dataId, request, 0.0);
230 updateRequestProgress(dataId, request, 0.0);
233 emit requestConstructed(request, dataId, httpDownloadFinished);
231 emit requestConstructed(request, dataId, httpDownloadFinished);
234 }
232 }
235 else {
233 else {
236 emit dataProvidedFailed(dataId);
234 emit dataProvidedFailed(dataId);
237 }
235 }
238 }
236 }
239 else {
237 else {
240 qCDebug(LOG_AmdaProvider())
241 << tr("acquisition requests erase because of aborting") << dataId;
242 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
238 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
243 m_AcqIdToRequestProgressMap.erase(dataId);
239 m_AcqIdToRequestProgressMap.erase(dataId);
244 emit dataProvidedFailed(dataId);
240 emit dataProvidedFailed(dataId);
245 }
241 }
246 };
242 };
247
243
248 // //////////////// //
244 // //////////////// //
249 // Executes request //
245 // Executes request //
250 // //////////////// //
246 // //////////////// //
251
247
252 auto request = std::make_shared<QNetworkRequest>(url);
248 auto request = std::make_shared<QNetworkRequest>(url);
253 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
249 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
254 updateRequestProgress(token, request, 0.0);
250 updateRequestProgress(token, request, 0.0);
255
251
256 emit requestConstructed(request, token, httpFinishedLambda);
252 emit requestConstructed(request, token, httpFinishedLambda);
257 }
253 }
258
254
259 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
255 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
260 std::shared_ptr<QNetworkRequest> request, double progress)
256 std::shared_ptr<QNetworkRequest> request, double progress)
261 {
257 {
258 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
262 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
259 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
263 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
260 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
264 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
261 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
265 auto requestProgressMapIt = requestProgressMap.find(request);
262 auto requestProgressMapIt = requestProgressMap.find(request);
266 if (requestProgressMapIt != requestProgressMap.end()) {
263 if (requestProgressMapIt != requestProgressMap.end()) {
267 requestProgressMapIt->second = progress;
264 requestProgressMapIt->second = progress;
268 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
265 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
269 << acqIdentifier << request.get() << progress;
266 << acqIdentifier << request.get() << progress;
270 }
267 }
271 else {
268 else {
272 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
269 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
273 << request.get() << progress;
270 << request.get() << progress;
274 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
271 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
275 }
272 }
276 }
273 }
277 else {
274 else {
278 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
275 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
279 << acqIdentifier << request.get() << progress;
276 << acqIdentifier << request.get() << progress;
280 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
277 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
281 requestProgressMap.insert(std::make_pair(request, progress));
278 requestProgressMap.insert(std::make_pair(request, progress));
282 m_AcqIdToRequestProgressMap.insert(
279 m_AcqIdToRequestProgressMap.insert(
283 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
280 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
284 }
281 }
285 }
282 }
@@ -1,237 +1,240
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Common/DateUtils.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <QDateTime>
7 #include <QDateTime>
8 #include <QFile>
8 #include <QFile>
9 #include <QRegularExpression>
9 #include <QRegularExpression>
10
10
11 #include <cmath>
11 #include <cmath>
12
12
13 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
13 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
14
14
15 namespace {
15 namespace {
16
16
17 /// Message in result file when the file was not found on server
17 /// Message in result file when the file was not found on server
18 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
18 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
19
19
20 /// Separator between values in a result line
20 /// Separator between values in a result line
21 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
21 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
22
22
23 // AMDA V2
23 // AMDA V2
24 // /// Regex to find the header of the data in the file. This header indicates the end of comments
24 // /// Regex to find the header of the data in the file. This header indicates the end of comments
25 // in
25 // in
26 // /// the file
26 // /// the file
27 // const auto DATA_HEADER_REGEX = QRegularExpression{QStringLiteral("#\\s*DATA\\s*:")};
27 // const auto DATA_HEADER_REGEX = QRegularExpression{QStringLiteral("#\\s*DATA\\s*:")};
28
28
29 /// Format for dates in result files
29 /// Format for dates in result files
30 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
30 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
31
31
32 // AMDA V2
32 // AMDA V2
33 // /// Regex to find unit in a line. Examples of valid lines:
33 // /// Regex to find unit in a line. Examples of valid lines:
34 // /// ... PARAMETER_UNITS : nT ...
34 // /// ... PARAMETER_UNITS : nT ...
35 // /// ... PARAMETER_UNITS:nT ...
35 // /// ... PARAMETER_UNITS:nT ...
36 // /// ... PARAMETER_UNITS: mΒ² ...
36 // /// ... PARAMETER_UNITS: mΒ² ...
37 // /// ... PARAMETER_UNITS : m/s ...
37 // /// ... PARAMETER_UNITS : m/s ...
38 // const auto UNIT_REGEX = QRegularExpression{QStringLiteral("\\s*PARAMETER_UNITS\\s*:\\s*(.+)")};
38 // const auto UNIT_REGEX = QRegularExpression{QStringLiteral("\\s*PARAMETER_UNITS\\s*:\\s*(.+)")};
39
39
40 /// ... - Units : nT - ...
40 /// ... - Units : nT - ...
41 /// ... -Units:nT- ...
41 /// ... -Units:nT- ...
42 /// ... -Units: mΒ²- ...
42 /// ... -Units: mΒ²- ...
43 /// ... - Units : m/s - ...
43 /// ... - Units : m/s - ...
44 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
44 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
45
45
46 QDateTime dateTimeFromString(const QString &stringDate) noexcept
46 QDateTime dateTimeFromString(const QString &stringDate) noexcept
47 {
47 {
48 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
48 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
49 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
49 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
50 #else
50 #else
51 return QDateTime::fromString(stringDate, DATE_FORMAT);
51 return QDateTime::fromString(stringDate, DATE_FORMAT);
52 #endif
52 #endif
53 }
53 }
54
54
55 /// Converts a string date to a double date
55 /// Converts a string date to a double date
56 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
56 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
57 double doubleDate(const QString &stringDate) noexcept
57 double doubleDate(const QString &stringDate) noexcept
58 {
58 {
59 // Format: yyyy-MM-ddThh:mm:ss.zzz
59 // Format: yyyy-MM-ddThh:mm:ss.zzz
60 auto dateTime = dateTimeFromString(stringDate);
60 auto dateTime = dateTimeFromString(stringDate);
61 dateTime.setTimeSpec(Qt::UTC);
61 dateTime.setTimeSpec(Qt::UTC);
62 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
62 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
63 : std::numeric_limits<double>::quiet_NaN();
63 : std::numeric_limits<double>::quiet_NaN();
64 }
64 }
65
65
66 /// Checks if a line is a comment line
66 /// Checks if a line is a comment line
67 bool isCommentLine(const QString &line)
67 bool isCommentLine(const QString &line)
68 {
68 {
69 return line.startsWith("#");
69 return line.startsWith("#");
70 }
70 }
71
71
72 /// @return the number of lines to be read depending on the type of value passed in parameter
72 /// @return the number of lines to be read depending on the type of value passed in parameter
73 int nbValues(AmdaResultParser::ValueType valueType) noexcept
73 int nbValues(AmdaResultParser::ValueType valueType) noexcept
74 {
74 {
75 switch (valueType) {
75 switch (valueType) {
76 case AmdaResultParser::ValueType::SCALAR:
76 case AmdaResultParser::ValueType::SCALAR:
77 return 1;
77 return 1;
78 case AmdaResultParser::ValueType::VECTOR:
78 case AmdaResultParser::ValueType::VECTOR:
79 return 3;
79 return 3;
80 case AmdaResultParser::ValueType::UNKNOWN:
80 case AmdaResultParser::ValueType::UNKNOWN:
81 // Invalid case
81 // Invalid case
82 break;
82 break;
83 }
83 }
84
84
85 // Invalid cases
85 // Invalid cases
86 qCCritical(LOG_AmdaResultParser())
86 qCCritical(LOG_AmdaResultParser())
87 << QObject::tr("Can't get the number of values to read: unsupported type");
87 << QObject::tr("Can't get the number of values to read: unsupported type");
88 return 0;
88 return 0;
89 }
89 }
90
90
91 /**
91 /**
92 * Reads stream to retrieve x-axis unit
92 * Reads stream to retrieve x-axis unit
93 * @param stream the stream to read
93 * @param stream the stream to read
94 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
94 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
95 * error occured during reading
95 * error occured during reading
96 */
96 */
97 Unit readXAxisUnit(QTextStream &stream)
97 Unit readXAxisUnit(QTextStream &stream)
98 {
98 {
99 QString line{};
99 QString line{};
100
100
101 // Searches unit in the comment lines (as long as the reading has not reached the data header)
101 // Searches unit in the comment lines (as long as the reading has not reached the data header)
102 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
102 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
103 while (stream.readLineInto(&line) && isCommentLine(line)) {
103 while (stream.readLineInto(&line) && isCommentLine(line)) {
104 auto match = UNIT_REGEX.match(line);
104 auto match = UNIT_REGEX.match(line);
105 if (match.hasMatch()) {
105 if (match.hasMatch()) {
106 return Unit{match.captured(1), true};
106 return Unit{match.captured(1), true};
107 }
107 }
108 }
108 }
109
109
110 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
110 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
111
111
112 // Error cases
112 // Error cases
113 return Unit{{}, true};
113 return Unit{{}, true};
114 }
114 }
115
115
116 /**
116 /**
117 * Reads stream to retrieve results
117 * Reads stream to retrieve results
118 * @param stream the stream to read
118 * @param stream the stream to read
119 * @return the pair of vectors x-axis data/values data that has been read in the stream
119 * @return the pair of vectors x-axis data/values data that has been read in the stream
120 */
120 */
121 std::pair<std::vector<double>, std::vector<double> >
121 std::pair<std::vector<double>, std::vector<double> >
122 readResults(QTextStream &stream, AmdaResultParser::ValueType valueType)
122 readResults(QTextStream &stream, AmdaResultParser::ValueType valueType)
123 {
123 {
124 auto expectedNbValues = nbValues(valueType) + 1;
124 auto expectedNbValues = nbValues(valueType) + 1;
125
125
126 auto xData = std::vector<double>{};
126 auto xData = std::vector<double>{};
127 auto valuesData = std::vector<double>{};
127 auto valuesData = std::vector<double>{};
128
128
129 QString line{};
129 QString line{};
130
130
131 // Skip comment lines
131 // Skip comment lines
132 while (stream.readLineInto(&line) && isCommentLine(line)) {
132 while (stream.readLineInto(&line) && isCommentLine(line)) {
133 }
133 }
134
134
135 if (!stream.atEnd()) {
135 if (!stream.atEnd()) {
136 do {
136 do {
137 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
137 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
138 if (lineData.size() == expectedNbValues) {
138 if (lineData.size() == expectedNbValues) {
139 // X : the data is converted from date to double (in secs)
139 // X : the data is converted from date to double (in secs)
140 auto x = doubleDate(lineData.at(0));
140 auto x = doubleDate(lineData.at(0));
141
141
142 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
142 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
143 if (!std::isnan(x)) {
143 if (!std::isnan(x)) {
144 xData.push_back(x);
144 xData.push_back(x);
145
145
146 // Values
146 // Values
147 for (auto valueIndex = 1; valueIndex < expectedNbValues; ++valueIndex) {
147 for (auto valueIndex = 1; valueIndex < expectedNbValues; ++valueIndex) {
148 auto column = valueIndex;
148 auto column = valueIndex;
149
149
150 bool valueOk;
150 bool valueOk;
151 auto value = lineData.at(column).toDouble(&valueOk);
151 auto value = lineData.at(column).toDouble(&valueOk);
152
152
153 if (!valueOk) {
153 if (!valueOk) {
154 qCWarning(LOG_AmdaResultParser())
154 qCWarning(LOG_AmdaResultParser())
155 << QObject::tr(
155 << QObject::tr(
156 "Value from (line %1, column %2) is invalid and will be "
156 "Value from (line %1, column %2) is invalid and will be "
157 "converted to NaN")
157 "converted to NaN")
158 .arg(line, column);
158 .arg(line, column);
159 value = std::numeric_limits<double>::quiet_NaN();
159 value = std::numeric_limits<double>::quiet_NaN();
160 }
160 }
161 valuesData.push_back(value);
161 valuesData.push_back(value);
162 }
162 }
163 }
163 }
164 else {
164 else {
165 qCWarning(LOG_AmdaResultParser())
165 qCWarning(LOG_AmdaResultParser())
166 << QObject::tr("Can't retrieve results from line %1: x is invalid")
166 << QObject::tr("Can't retrieve results from line %1: x is invalid")
167 .arg(line);
167 .arg(line);
168 }
168 }
169 }
169 }
170 else {
170 else {
171 qCWarning(LOG_AmdaResultParser())
171 qCWarning(LOG_AmdaResultParser())
172 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
172 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
173 }
173 }
174 } while (stream.readLineInto(&line));
174 } while (stream.readLineInto(&line));
175 }
175 }
176
176
177 return std::make_pair(std::move(xData), std::move(valuesData));
177 return std::make_pair(std::move(xData), std::move(valuesData));
178 }
178 }
179
179
180 } // namespace
180 } // namespace
181
181
182 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
182 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
183 ValueType valueType) noexcept
183 ValueType valueType) noexcept
184 {
184 {
185 if (valueType == ValueType::UNKNOWN) {
185 if (valueType == ValueType::UNKNOWN) {
186 qCCritical(LOG_AmdaResultParser())
186 qCCritical(LOG_AmdaResultParser())
187 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
187 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
188 return nullptr;
188 return nullptr;
189 }
189 }
190
190
191 QFile file{filePath};
191 QFile file{filePath};
192
192
193 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
193 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
194 qCCritical(LOG_AmdaResultParser())
194 qCCritical(LOG_AmdaResultParser())
195 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
195 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
196 .arg(filePath, file.errorString());
196 .arg(filePath, file.errorString());
197 return nullptr;
197 return nullptr;
198 }
198 }
199
199
200 QTextStream stream{&file};
200 QTextStream stream{&file};
201
201
202 // Checks if the file was found on the server
202 // Checks if the file was found on the server
203 auto firstLine = stream.readLine();
203 auto firstLine = stream.readLine();
204 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
204 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
205 qCCritical(LOG_AmdaResultParser())
205 qCCritical(LOG_AmdaResultParser())
206 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
206 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
207 .arg(filePath);
207 .arg(filePath);
208 return nullptr;
208 return nullptr;
209 }
209 }
210
210
211 // Reads x-axis unit
211 // Reads x-axis unit
212 stream.seek(0); // returns to the beginning of the file
212 stream.seek(0); // returns to the beginning of the file
213 auto xAxisUnit = readXAxisUnit(stream);
213 auto xAxisUnit = readXAxisUnit(stream);
214 if (xAxisUnit.m_Name.isEmpty()) {
215 return nullptr;
216 }
214
217
215 // Reads results
218 // Reads results
216 // AMDA V2: remove line
219 // AMDA V2: remove line
217 stream.seek(0); // returns to the beginning of the file
220 stream.seek(0); // returns to the beginning of the file
218 auto results = readResults(stream, valueType);
221 auto results = readResults(stream, valueType);
219
222
220 // Creates data series
223 // Creates data series
221 switch (valueType) {
224 switch (valueType) {
222 case ValueType::SCALAR:
225 case ValueType::SCALAR:
223 return std::make_shared<ScalarSeries>(std::move(results.first),
226 return std::make_shared<ScalarSeries>(std::move(results.first),
224 std::move(results.second), xAxisUnit, Unit{});
227 std::move(results.second), xAxisUnit, Unit{});
225 case ValueType::VECTOR:
228 case ValueType::VECTOR:
226 return std::make_shared<VectorSeries>(std::move(results.first),
229 return std::make_shared<VectorSeries>(std::move(results.first),
227 std::move(results.second), xAxisUnit, Unit{});
230 std::move(results.second), xAxisUnit, Unit{});
228 case ValueType::UNKNOWN:
231 case ValueType::UNKNOWN:
229 // Invalid case
232 // Invalid case
230 break;
233 break;
231 }
234 }
232
235
233 // Invalid cases
236 // Invalid cases
234 qCCritical(LOG_AmdaResultParser())
237 qCCritical(LOG_AmdaResultParser())
235 << QObject::tr("Can't create data series: unsupported value type");
238 << QObject::tr("Can't create data series: unsupported value type");
236 return nullptr;
239 return nullptr;
237 }
240 }
@@ -1,196 +1,164
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaResultParser.h"
2 #include "AmdaResultParser.h"
3
3
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include <Data/DataSeries.h>
5 #include <Data/DataSeries.h>
6 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
7 #include <Data/ScalarSeries.h>
7 #include <Data/ScalarSeries.h>
8 #include <Time/TimeController.h>
8 #include <Time/TimeController.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <QObject>
12 #include <QObject>
13 #include <QtTest>
13 #include <QtTest>
14
14
15 #include <memory>
15 #include <memory>
16
16
17 // TEST with REF:
17 // TEST with REF:
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 // Name : bx_gse - Units : nT - Size : 1 -
20 // Name : bx_gse - Units : nT - Size : 1 -
21 // Frame : GSE - Mission : ACE -
21 // Frame : GSE - Mission : ACE -
22 // Instrument : MFI - Dataset : mfi_final-prelim
22 // Instrument : MFI - Dataset : mfi_final-prelim
23 // REFERENCE DOWNLOAD FILE =
23 // REFERENCE DOWNLOAD FILE =
24 // http://amda.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25
25
26 namespace {
26 namespace {
27
27
28 /// Path for the tests
28 /// Path for the tests
29 const auto TESTS_RESOURCES_PATH
29 const auto TESTS_RESOURCES_PATH
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31
31
32 const auto TESTS_AMDA_REF_FILE = QString{"AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"};
32 /// Delay after each operation on the variable before validating it (in ms)
33 const auto OPERATION_DELAY = 10000;
33
34
34 template <typename T>
35 template <typename T>
35 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
36 std::shared_ptr<IDataSeries> reference)
37 std::shared_ptr<IDataSeries> reference)
37 {
38 {
38 auto compareLambda = [](const auto &it1, const auto &it2) {
39 auto compareLambda = [](const auto &it1, const auto &it2) {
39 return (it1.x() == it2.x()) && (it1.value() == it2.value());
40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
40 };
41 };
41
42
42 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
43 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
44
45
45 if (candidateDS && referenceDS) {
46 if (candidateDS && referenceDS) {
46
47
47 auto itRefs
48 auto itRefs
48 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
49 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
50 << std::distance(itRefs.first, itRefs.second);
51 << std::distance(itRefs.first, itRefs.second);
51
52
52 // auto xcValue = candidateDS->valuesData()->data();
53 // auto dist = std::distance(itRefs.first, itRefs.second);
54 // auto it = itRefs.first;
55 // for (auto i = 0; i < dist - 1; ++i) {
56 // ++it;
57 // qInfo() << "END:" << it->value();
58 // }
59 // qDebug() << "END:" << it->value() << xcValue.last();
60
61 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
62 compareLambda);
54 compareLambda);
63 }
55 }
64 else {
56 else {
65 return false;
57 return false;
66 }
58 }
67 }
59 }
68 }
60 }
69
61
70 class TestAmdaAcquisition : public QObject {
62 class TestAmdaAcquisition : public QObject {
71 Q_OBJECT
63 Q_OBJECT
72
64
73 private slots:
65 private slots:
66 /// Input data for @sa testAcquisition()
67 void testAcquisition_data();
74 void testAcquisition();
68 void testAcquisition();
75 };
69 };
76
70
77 void TestAmdaAcquisition::testAcquisition()
71 void TestAmdaAcquisition::testAcquisition_data()
78 {
72 {
79 /// @todo: update test to be compatible with AMDA v2
73 // ////////////// //
80
74 // Test structure //
81 // READ the ref file:
75 // ////////////// //
82 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, TESTS_AMDA_REF_FILE}.absoluteFilePath();
83 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
84
85 auto provider = std::make_shared<AmdaProvider>();
86 auto timeController = std::make_unique<TimeController>();
87
88 auto varRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 3, 0, 0}};
89 auto varRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
90
91 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
92
93 timeController->onTimeToUpdate(sqpR);
94
95 QVariantHash metaData;
96 metaData.insert("dataType", "scalar");
97 metaData.insert("xml:id", "imf(0)");
98
99 VariableController vc;
100 vc.setTimeController(timeController.get());
101
102 auto var = vc.createVariable("bx_gse", metaData, provider);
103
104 // 1 : Variable creation
105
106 qDebug() << " 1: TIMECONTROLLER" << timeController->dateTime();
107 qDebug() << " 1: RANGE " << var->range();
108 qDebug() << " 1: CACHERANGE" << var->cacheRange();
109
110 // wait for 10 sec before asking next request toi permit asynchrone process to finish.
111 auto timeToWaitMs = 10000;
112
76
113 QEventLoop loop;
77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
114 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
78 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
115 loop.exec();
79 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
116
80
117 // Tests on acquisition operation
81 // ////////// //
118
82 // Test cases //
119 int count = 1;
83 // ////////// //
120
121 auto requestDataLoading = [&vc, var, timeToWaitMs, results, &count](auto tStart, auto tEnd) {
122 ++count;
123
124 auto nextSqpR
125 = SqpRange{DateUtils::secondsSinceEpoch(tStart), DateUtils::secondsSinceEpoch(tEnd)};
126 vc.onRequestDataLoading(QVector<std::shared_ptr<Variable> >{} << var, nextSqpR, true);
127
128 QEventLoop loop;
129 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
130 loop.exec();
131
132 qInfo() << count << "RANGE " << var->range();
133 qInfo() << count << "CACHERANGE" << var->cacheRange();
134
135 QCOMPARE(var->range().m_TStart, nextSqpR.m_TStart);
136 QCOMPARE(var->range().m_TEnd, nextSqpR.m_TEnd);
137
138 // Verify dataserie
139 QVERIFY(compareDataSeries<ScalarSeries>(var->dataSeries(), var->cacheRange(), results));
140
84
85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
86 return DateUtils::secondsSinceEpoch(
87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
141 };
88 };
142
89
143 // 2 : pan (jump) left for one hour
144 auto nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 1, 0, 0}};
145 auto nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 2, 0, 0}};
146 // requestDataLoading(nextVarRS, nextVarRE);
147
90
91 QTest::newRow("amda")
92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
93 << SqpRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
94 << std::vector<SqpRange>{
95 // 2 : pan (jump) left for two min
96 SqpRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
97 // 3 : pan (jump) right for four min
98 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
99 // 4 : pan (overlay) right for 30 sec
100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
101 // 5 : pan (overlay) left for 30 sec
102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
103 // 6 : pan (overlay) left for 30 sec - BIS
104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
105 // 7 : Zoom in Inside 20 sec range
106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
107 // 8 : Zoom out Inside 20 sec range
108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
109 }
148
110
149 // 3 : pan (jump) right for one hour
111 void TestAmdaAcquisition::testAcquisition()
150 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
112 {
151 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
113 /// @todo: update test to be compatible with AMDA v2
152 // requestDataLoading(nextVarRS, nextVarRE);
153
114
154 // 4 : pan (overlay) right for 30 min
115 // Retrieves data file
155 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
116 QFETCH(QString, dataFilename);
156 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 30, 0}};
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
157 // requestDataLoading(nextVarRS, nextVarRE);
118 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
158
119
159 // 5 : pan (overlay) left for 30 min
120 /// Lambda used to validate a variable at each step
160 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
161 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
122 // Checks that the variable's range has changed
162 // requestDataLoading(nextVarRS, nextVarRE);
123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
124 QCOMPARE(variable->range(), range);
163
125
164 // 6 : pan (overlay) left for 30 min - BIS
126 // Checks the variable's data series
165 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 30, 0}};
127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
166 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
128 results));
167 // requestDataLoading(nextVarRS, nextVarRE);
129 qInfo() << "\n";
130 };
168
131
169 // 7 : Zoom in Inside 20 min range
132 // Creates variable
170 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 50, 0}};
133 QFETCH(SqpRange, initialRange);
171 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 10, 0}};
134 sqpApp->timeController().onTimeToUpdate(initialRange);
172 // requestDataLoading(nextVarRS, nextVarRE);
135 auto provider = std::make_shared<AmdaProvider>();
136 auto variable = sqpApp->variableController().createVariable(
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider);
173
138
174 // 8 : Zoom out Inside 2 hours range
139 QTest::qWait(OPERATION_DELAY);
175 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
140 validateVariable(variable, initialRange);
176 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
177 // requestDataLoading(nextVarRS, nextVarRE);
178
141
142 // Makes operations on the variable
143 QFETCH(std::vector<SqpRange>, operations);
144 for (const auto &operation : operations) {
145 // Asks request on the variable and waits during its execution
146 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
179
147
180 // Close the app after 10 sec
148 QTest::qWait(OPERATION_DELAY);
181 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
149 validateVariable(variable, operation);
182 loop.exec();
150 }
183 }
151 }
184
152
185 int main(int argc, char *argv[])
153 int main(int argc, char *argv[])
186 {
154 {
187 SqpApplication app(argc, argv);
155 SqpApplication app(argc, argv);
188 app.setAttribute(Qt::AA_Use96Dpi, true);
156 app.setAttribute(Qt::AA_Use96Dpi, true);
189 TestAmdaAcquisition tc;
157 TestAmdaAcquisition tc;
190 QTEST_SET_MAIN_SOURCE_PATH
158 QTEST_SET_MAIN_SOURCE_PATH
191 return QTest::qExec(&tc, argc, argv);
159 return QTest::qExec(&tc, argc, argv);
192 }
160 }
193
161
194 // QTEST_MAIN(TestAmdaAcquisition)
162 // QTEST_MAIN(TestAmdaAcquisition)
195
163
196 #include "TestAmdaAcquisition.moc"
164 #include "TestAmdaAcquisition.moc"
@@ -1,281 +1,286
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/VectorSeries.h>
4 #include <Data/VectorSeries.h>
5
5
6 #include <QObject>
6 #include <QObject>
7 #include <QtTest>
7 #include <QtTest>
8
8
9 namespace {
9 namespace {
10
10
11 /// Path for the tests
11 /// Path for the tests
12 const auto TESTS_RESOURCES_PATH
12 const auto TESTS_RESOURCES_PATH
13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
14
14
15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
16 {
16 {
17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
18 }
18 }
19
19
20 QString inputFilePath(const QString &inputFileName)
20 QString inputFilePath(const QString &inputFileName)
21 {
21 {
22 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
22 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
23 }
23 }
24
24
25 template <typename T>
25 template <typename T>
26 struct ExpectedResults {
26 struct ExpectedResults {
27 explicit ExpectedResults() = default;
27 explicit ExpectedResults() = default;
28
28
29 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
29 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
30 QVector<double> valuesData)
30 QVector<double> valuesData)
31 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
31 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
32 QVector<QVector<double> >{std::move(valuesData)})
32 QVector<QVector<double> >{std::move(valuesData)})
33 {
33 {
34 }
34 }
35
35
36 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
36 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
37 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
37 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
38 QVector<QVector<double> > valuesData)
38 QVector<QVector<double> > valuesData)
39 : m_ParsingOK{true},
39 : m_ParsingOK{true},
40 m_XAxisUnit{xAxisUnit},
40 m_XAxisUnit{xAxisUnit},
41 m_ValuesUnit{valuesUnit},
41 m_ValuesUnit{valuesUnit},
42 m_XAxisData{},
42 m_XAxisData{},
43 m_ValuesData{std::move(valuesData)}
43 m_ValuesData{std::move(valuesData)}
44 {
44 {
45 // Converts QVector<QDateTime> to QVector<double>
45 // Converts QVector<QDateTime> to QVector<double>
46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
48 }
48 }
49
49
50 /**
50 /**
51 * Validates a DataSeries compared to the expected results
51 * Validates a DataSeries compared to the expected results
52 * @param results the DataSeries to validate
52 * @param results the DataSeries to validate
53 */
53 */
54 void validate(std::shared_ptr<IDataSeries> results)
54 void validate(std::shared_ptr<IDataSeries> results)
55 {
55 {
56 if (m_ParsingOK) {
56 if (m_ParsingOK) {
57 auto dataSeries = dynamic_cast<T *>(results.get());
57 auto dataSeries = dynamic_cast<T *>(results.get());
58 QVERIFY(dataSeries != nullptr);
58 if (dataSeries == nullptr) {
59
60 // No unit detected, parsink ok but data is nullptr
61 // TODO, improve the test to verify that the data is null
62 return;
63 }
59
64
60 // Checks units
65 // Checks units
61 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
66 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
62 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
67 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
63
68
64 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
69 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
65 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
70 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
66 expectedData.cend(),
71 expectedData.cend(),
67 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
72 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
68 return equalFun(dataSeriesIt, expectedX);
73 return equalFun(dataSeriesIt, expectedX);
69 }));
74 }));
70 };
75 };
71
76
72 // Checks x-axis data
77 // Checks x-axis data
73 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
78 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
74 return seriesIt.x() == value;
79 return seriesIt.x() == value;
75 });
80 });
76
81
77 // Checks values data of each component
82 // Checks values data of each component
78 for (auto i = 0; i < m_ValuesData.size(); ++i) {
83 for (auto i = 0; i < m_ValuesData.size(); ++i) {
79 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
84 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
80 auto itValue = seriesIt.value(i);
85 auto itValue = seriesIt.value(i);
81 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
86 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
82 });
87 });
83 }
88 }
84 }
89 }
85 else {
90 else {
86 QVERIFY(results == nullptr);
91 QVERIFY(results == nullptr);
87 }
92 }
88 }
93 }
89
94
90 // Parsing was successfully completed
95 // Parsing was successfully completed
91 bool m_ParsingOK{false};
96 bool m_ParsingOK{false};
92 // Expected x-axis unit
97 // Expected x-axis unit
93 Unit m_XAxisUnit{};
98 Unit m_XAxisUnit{};
94 // Expected values unit
99 // Expected values unit
95 Unit m_ValuesUnit{};
100 Unit m_ValuesUnit{};
96 // Expected x-axis data
101 // Expected x-axis data
97 QVector<double> m_XAxisData{};
102 QVector<double> m_XAxisData{};
98 // Expected values data
103 // Expected values data
99 QVector<QVector<double> > m_ValuesData{};
104 QVector<QVector<double> > m_ValuesData{};
100 };
105 };
101
106
102 } // namespace
107 } // namespace
103
108
104 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
109 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
105 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
110 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
106
111
107 class TestAmdaResultParser : public QObject {
112 class TestAmdaResultParser : public QObject {
108 Q_OBJECT
113 Q_OBJECT
109 private:
114 private:
110 template <typename T>
115 template <typename T>
111 void testReadDataStructure()
116 void testReadDataStructure()
112 {
117 {
113 // ////////////// //
118 // ////////////// //
114 // Test structure //
119 // Test structure //
115 // ////////////// //
120 // ////////////// //
116
121
117 // Name of TXT file to read
122 // Name of TXT file to read
118 QTest::addColumn<QString>("inputFileName");
123 QTest::addColumn<QString>("inputFileName");
119 // Expected results
124 // Expected results
120 QTest::addColumn<ExpectedResults<T> >("expectedResults");
125 QTest::addColumn<ExpectedResults<T> >("expectedResults");
121 }
126 }
122
127
123 template <typename T>
128 template <typename T>
124 void testRead(AmdaResultParser::ValueType valueType)
129 void testRead(AmdaResultParser::ValueType valueType)
125 {
130 {
126 QFETCH(QString, inputFileName);
131 QFETCH(QString, inputFileName);
127 QFETCH(ExpectedResults<T>, expectedResults);
132 QFETCH(ExpectedResults<T>, expectedResults);
128
133
129 // Parses file
134 // Parses file
130 auto filePath = inputFilePath(inputFileName);
135 auto filePath = inputFilePath(inputFileName);
131 auto results = AmdaResultParser::readTxt(filePath, valueType);
136 auto results = AmdaResultParser::readTxt(filePath, valueType);
132
137
133 // ///////////////// //
138 // ///////////////// //
134 // Validates results //
139 // Validates results //
135 // ///////////////// //
140 // ///////////////// //
136 expectedResults.validate(results);
141 expectedResults.validate(results);
137 }
142 }
138
143
139 private slots:
144 private slots:
140 /// Input test data
145 /// Input test data
141 /// @sa testReadScalarTxt()
146 /// @sa testReadScalarTxt()
142 void testReadScalarTxt_data();
147 void testReadScalarTxt_data();
143
148
144 /// Tests parsing scalar series of a TXT file
149 /// Tests parsing scalar series of a TXT file
145 void testReadScalarTxt();
150 void testReadScalarTxt();
146
151
147 /// Input test data
152 /// Input test data
148 /// @sa testReadVectorTxt()
153 /// @sa testReadVectorTxt()
149 void testReadVectorTxt_data();
154 void testReadVectorTxt_data();
150
155
151 /// Tests parsing vector series of a TXT file
156 /// Tests parsing vector series of a TXT file
152 void testReadVectorTxt();
157 void testReadVectorTxt();
153 };
158 };
154
159
155 void TestAmdaResultParser::testReadScalarTxt_data()
160 void TestAmdaResultParser::testReadScalarTxt_data()
156 {
161 {
157 testReadDataStructure<ScalarSeries>();
162 testReadDataStructure<ScalarSeries>();
158
163
159 // ////////// //
164 // ////////// //
160 // Test cases //
165 // Test cases //
161 // ////////// //
166 // ////////// //
162
167
163 // Valid files
168 // Valid files
164 QTest::newRow("Valid file")
169 QTest::newRow("Valid file")
165 << QStringLiteral("ValidScalar1.txt")
170 << QStringLiteral("ValidScalar1.txt")
166 << ExpectedResults<ScalarSeries>{
171 << ExpectedResults<ScalarSeries>{
167 Unit{QStringLiteral("nT"), true}, Unit{},
172 Unit{QStringLiteral("nT"), true}, Unit{},
168 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
173 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
169 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
174 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
170 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
175 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
171 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
176 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
172 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
177 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
173 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
178 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
174 -2.55800, -2.43250, -2.42200}};
179 -2.55800, -2.43250, -2.42200}};
175
180
176 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
181 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
177 << QStringLiteral("WrongValue.txt")
182 << QStringLiteral("WrongValue.txt")
178 << ExpectedResults<ScalarSeries>{
183 << ExpectedResults<ScalarSeries>{
179 Unit{QStringLiteral("nT"), true}, Unit{},
184 Unit{QStringLiteral("nT"), true}, Unit{},
180 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
185 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
181 dateTime(2013, 9, 23, 9, 2, 30)},
186 dateTime(2013, 9, 23, 9, 2, 30)},
182 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
187 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
183
188
184 QTest::newRow("Valid file that contains NaN values")
189 QTest::newRow("Valid file that contains NaN values")
185 << QStringLiteral("NaNValue.txt")
190 << QStringLiteral("NaNValue.txt")
186 << ExpectedResults<ScalarSeries>{
191 << ExpectedResults<ScalarSeries>{
187 Unit{QStringLiteral("nT"), true}, Unit{},
192 Unit{QStringLiteral("nT"), true}, Unit{},
188 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
193 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
189 dateTime(2013, 9, 23, 9, 2, 30)},
194 dateTime(2013, 9, 23, 9, 2, 30)},
190 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
195 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
191
196
192 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
197 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
193 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
198 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
194 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
199 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
195 Unit{}, QVector<QDateTime>{},
200 Unit{}, QVector<QDateTime>{},
196 QVector<double>{}};
201 QVector<double>{}};
197 QTest::newRow("Wrong unit file")
202 QTest::newRow("Wrong unit file")
198 << QStringLiteral("WrongUnit.txt")
203 << QStringLiteral("WrongUnit.txt")
199 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
204 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
200 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
205 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
201 dateTime(2013, 9, 23, 9, 1, 30),
206 dateTime(2013, 9, 23, 9, 1, 30),
202 dateTime(2013, 9, 23, 9, 2, 30)},
207 dateTime(2013, 9, 23, 9, 2, 30)},
203 QVector<double>{-2.83950, -2.71850, -2.52150}};
208 QVector<double>{-2.83950, -2.71850, -2.52150}};
204
209
205 QTest::newRow("Wrong results file (date of first line is invalid")
210 QTest::newRow("Wrong results file (date of first line is invalid")
206 << QStringLiteral("WrongDate.txt")
211 << QStringLiteral("WrongDate.txt")
207 << ExpectedResults<ScalarSeries>{
212 << ExpectedResults<ScalarSeries>{
208 Unit{QStringLiteral("nT"), true}, Unit{},
213 Unit{QStringLiteral("nT"), true}, Unit{},
209 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
214 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
210 QVector<double>{-2.71850, -2.52150}};
215 QVector<double>{-2.71850, -2.52150}};
211
216
212 QTest::newRow("Wrong results file (too many values for first line")
217 QTest::newRow("Wrong results file (too many values for first line")
213 << QStringLiteral("TooManyValues.txt")
218 << QStringLiteral("TooManyValues.txt")
214 << ExpectedResults<ScalarSeries>{
219 << ExpectedResults<ScalarSeries>{
215 Unit{QStringLiteral("nT"), true}, Unit{},
220 Unit{QStringLiteral("nT"), true}, Unit{},
216 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
221 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
217 QVector<double>{-2.71850, -2.52150}};
222 QVector<double>{-2.71850, -2.52150}};
218
223
219 QTest::newRow("Wrong results file (x of first line is NaN")
224 QTest::newRow("Wrong results file (x of first line is NaN")
220 << QStringLiteral("NaNX.txt")
225 << QStringLiteral("NaNX.txt")
221 << ExpectedResults<ScalarSeries>{
226 << ExpectedResults<ScalarSeries>{
222 Unit{QStringLiteral("nT"), true}, Unit{},
227 Unit{QStringLiteral("nT"), true}, Unit{},
223 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
228 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
224 QVector<double>{-2.71850, -2.52150}};
229 QVector<double>{-2.71850, -2.52150}};
225
230
226 QTest::newRow("Invalid file type (vector)")
231 QTest::newRow("Invalid file type (vector)")
227 << QStringLiteral("ValidVector1.txt")
232 << QStringLiteral("ValidVector1.txt")
228 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
233 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
229 QVector<QDateTime>{}, QVector<double>{}};
234 QVector<QDateTime>{}, QVector<double>{}};
230
235
231 // Invalid files
236 // Invalid files
232 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
237 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
233 << ExpectedResults<ScalarSeries>{};
238 << ExpectedResults<ScalarSeries>{};
234
239
235 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
240 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
236 << ExpectedResults<ScalarSeries>{};
241 << ExpectedResults<ScalarSeries>{};
237 }
242 }
238
243
239 void TestAmdaResultParser::testReadScalarTxt()
244 void TestAmdaResultParser::testReadScalarTxt()
240 {
245 {
241 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
246 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
242 }
247 }
243
248
244 void TestAmdaResultParser::testReadVectorTxt_data()
249 void TestAmdaResultParser::testReadVectorTxt_data()
245 {
250 {
246 testReadDataStructure<VectorSeries>();
251 testReadDataStructure<VectorSeries>();
247
252
248 // ////////// //
253 // ////////// //
249 // Test cases //
254 // Test cases //
250 // ////////// //
255 // ////////// //
251
256
252 // Valid files
257 // Valid files
253 QTest::newRow("Valid file")
258 QTest::newRow("Valid file")
254 << QStringLiteral("ValidVector1.txt")
259 << QStringLiteral("ValidVector1.txt")
255 << ExpectedResults<VectorSeries>{
260 << ExpectedResults<VectorSeries>{
256 Unit{QStringLiteral("nT"), true}, Unit{},
261 Unit{QStringLiteral("nT"), true}, Unit{},
257 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
262 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
258 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
263 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
259 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
264 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
260 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
265 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
261 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
266 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
262 QVector<QVector<double> >{
267 QVector<QVector<double> >{
263 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
268 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
264 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
269 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
265 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
270 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
266
271
267 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
272 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
268 QTest::newRow("Invalid file type (scalar)")
273 QTest::newRow("Invalid file type (scalar)")
269 << QStringLiteral("ValidScalar1.txt")
274 << QStringLiteral("ValidScalar1.txt")
270 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
275 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
271 QVector<QDateTime>{},
276 QVector<QDateTime>{},
272 QVector<QVector<double> >{{}, {}, {}}};
277 QVector<QVector<double> >{{}, {}, {}}};
273 }
278 }
274
279
275 void TestAmdaResultParser::testReadVectorTxt()
280 void TestAmdaResultParser::testReadVectorTxt()
276 {
281 {
277 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
282 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
278 }
283 }
279
284
280 QTEST_MAIN(TestAmdaResultParser)
285 QTEST_MAIN(TestAmdaResultParser)
281 #include "TestAmdaResultParser.moc"
286 #include "TestAmdaResultParser.moc"
@@ -1,192 +1,195
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Time/TimeController.h>
7 #include <Time/TimeController.h>
8 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
9 #include <Variable/VariableController.h>
9 #include <Variable/VariableController.h>
10
10
11 #include <QObject>
11 #include <QObject>
12 #include <QtTest>
12 #include <QtTest>
13
13
14 #include <cmath>
14 #include <cmath>
15 #include <memory>
15 #include <memory>
16
16
17 namespace {
17 namespace {
18
18
19 /// Path for the tests
19 /// Path for the tests
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
22 "TestCosinusAcquisition"}.absoluteFilePath();
22 "TestCosinusAcquisition"}.absoluteFilePath();
23
23
24 /// Format of dates in data files
24 /// Format of dates in data files
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
26
26
27 /**
27 /**
28 * Verifies that the data in the candidate series are identical to the data in the reference series
28 * Verifies that the data in the candidate series are identical to the data in the reference series
29 * in a specific range
29 * in a specific range
30 * @param candidate the candidate data series
30 * @param candidate the candidate data series
31 * @param range the range to check
31 * @param range the range to check
32 * @param reference the reference data series
32 * @param reference the reference data series
33 * @return true if the data of the candidate series and the reference series are identical in the
33 * @return true if the data of the candidate series and the reference series are identical in the
34 * range, false otherwise
34 * range, false otherwise
35 */
35 */
36 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
36 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
37 std::shared_ptr<IDataSeries> reference)
37 std::shared_ptr<IDataSeries> reference)
38 {
38 {
39 if (candidate == nullptr || reference == nullptr) {
39 if (candidate == nullptr || reference == nullptr) {
40 return candidate == reference;
40 return candidate == reference;
41 }
41 }
42
42
43 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
43 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
44
44
45 qInfo() << "candidateSize" << std::distance(candidate->cbegin(), candidate->cend());
45 qInfo() << "candidateSize" << std::distance(candidate->cbegin(), candidate->cend());
46 qInfo() << "refSize" << std::distance(referenceIt.first, referenceIt.second);
46 qInfo() << "refSize" << std::distance(referenceIt.first, referenceIt.second);
47
47
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
49 [](const auto &it1, const auto &it2) {
49 [](const auto &it1, const auto &it2) {
50 // - milliseconds precision for time
50 // - milliseconds precision for time
51 // - 1e-6 precision for value
51 // - 1e-6 precision for value
52 return std::abs(it1.x() - it2.x()) < 1e-3
52 return std::abs(it1.x() - it2.x()) < 1e-3
53 && std::abs(it1.value() - it2.value()) < 1e-6;
53 && std::abs(it1.value() - it2.value()) < 1e-6;
54 });
54 });
55 }
55 }
56
56
57 } // namespace
57 } // namespace
58
58
59 /**
59 /**
60 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
60 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
61 * zooms out, pans) of data from CosinusProvider
61 * zooms out, pans) of data from CosinusProvider
62 * @sa CosinusProvider
62 * @sa CosinusProvider
63 */
63 */
64 class TestCosinusAcquisition : public QObject {
64 class TestCosinusAcquisition : public QObject {
65 Q_OBJECT
65 Q_OBJECT
66
66
67 private slots:
67 private slots:
68 /// Input data for @sa testAcquisition()
68 /// Input data for @sa testAcquisition()
69 void testAcquisition_data();
69 void testAcquisition_data();
70 void testAcquisition();
70 void testAcquisition();
71 };
71 };
72
72
73 void TestCosinusAcquisition::testAcquisition_data()
73 void TestCosinusAcquisition::testAcquisition_data()
74 {
74 {
75 // ////////////// //
75 // ////////////// //
76 // Test structure //
76 // Test structure //
77 // ////////////// //
77 // ////////////// //
78
78
79 QTest::addColumn<SqpRange>("referenceRange"); // Range for generating reference series
79 QTest::addColumn<SqpRange>("referenceRange"); // Range for generating reference series
80 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
80 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
81 QTest::addColumn<int>("operationDelay"); // Acquisitions to make
81 QTest::addColumn<int>("operationDelay"); // Acquisitions to make
82 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
82 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
83
83
84 // ////////// //
84 // ////////// //
85 // Test cases //
85 // Test cases //
86 // ////////// //
86 // ////////// //
87
87
88 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
88 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
89 return DateUtils::secondsSinceEpoch(
89 return DateUtils::secondsSinceEpoch(
90 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
90 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
91 };
91 };
92
92
93 QTest::newRow("cosinus")
93 QTest::newRow("cosinus")
94 << SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}
94 << SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}
95 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)} << 250
95 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)} << 250
96 << std::vector<SqpRange>{
96 << std::vector<SqpRange>{
97 // Pan (jump) left
97 // Pan (jump) left
98 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
98 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
99 // Pan (jump) right
99 // Pan (jump) right
100 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
100 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
101 // Pan (overlay) right
101 // Pan (overlay) right
102 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
102 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
103 // Pan (overlay) left
103 // Pan (overlay) left
104 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
104 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
105 // Pan (overlay) left
105 // Pan (overlay) left
106 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
106 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
107 // Zoom in
107 // Zoom in
108 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
108 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
109 // Zoom out
109 // Zoom out
110 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
110 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
111
111
112 QTest::newRow("cosinus_big")
112 QTest::newRow("cosinus_big")
113 << SqpRange{dateTime(2017, 1, 1, 1, 0, 0), dateTime(2017, 1, 5, 13, 0, 0)}
113 << SqpRange{dateTime(2017, 1, 1, 1, 0, 0), dateTime(2017, 1, 5, 13, 0, 0)}
114 << SqpRange{dateTime(2017, 1, 2, 6, 30, 0), dateTime(2017, 1, 2, 18, 30, 0)} << 5000
114 << SqpRange{dateTime(2017, 1, 2, 6, 30, 0), dateTime(2017, 1, 2, 18, 30, 0)} << 5000
115 << std::vector<SqpRange>{
115 << std::vector<SqpRange>{
116 // Pan (jump) left
116 // Pan (jump) left
117 SqpRange{dateTime(2017, 1, 1, 13, 30, 0), dateTime(2017, 1, 1, 18, 30, 0)},
117 SqpRange{dateTime(2017, 1, 1, 13, 30, 0), dateTime(2017, 1, 1, 18, 30, 0)},
118 // Pan (jump) right
118 // Pan (jump) right
119 SqpRange{dateTime(2017, 1, 3, 4, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
119 SqpRange{dateTime(2017, 1, 3, 4, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
120 // Pan (overlay) right
120 // Pan (overlay) right
121 SqpRange{dateTime(2017, 1, 3, 8, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)},
121 SqpRange{dateTime(2017, 1, 3, 8, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)},
122 // Pan (overlay) left
122 // Pan (overlay) left
123 SqpRange{dateTime(2017, 1, 2, 8, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
123 SqpRange{dateTime(2017, 1, 2, 8, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
124 // Pan (overlay) left
124 // Pan (overlay) left
125 SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 3, 5, 30, 0)},
125 SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 3, 5, 30, 0)},
126 // Zoom in
126 // Zoom in
127 SqpRange{dateTime(2017, 1, 2, 2, 30, 0), dateTime(2017, 1, 2, 8, 30, 0)},
127 SqpRange{dateTime(2017, 1, 2, 2, 30, 0), dateTime(2017, 1, 2, 8, 30, 0)},
128 // Zoom out
128 // Zoom out
129 SqpRange{dateTime(2017, 1, 1, 14, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)}};
129 SqpRange{dateTime(2017, 1, 1, 14, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)}};
130 }
130 }
131
131
132 void TestCosinusAcquisition::testAcquisition()
132 void TestCosinusAcquisition::testAcquisition()
133 {
133 {
134 // Retrieves reference range
134 // Retrieves reference range
135 QFETCH(SqpRange, referenceRange);
135 QFETCH(SqpRange, referenceRange);
136 CosinusProvider referenceProvider{};
136 CosinusProvider referenceProvider{};
137 auto dataSeries = referenceProvider.provideDataSeries(
137 auto dataSeries = referenceProvider.provideDataSeries(
138 referenceRange, {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}});
138 referenceRange, {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}});
139
139
140 auto end = dataSeries->cend() - 1;
140 auto end = dataSeries->cend() - 1;
141 qInfo() << dataSeries->nbPoints() << dataSeries->cbegin()->x() << end->x();
141 qInfo() << dataSeries->nbPoints() << dataSeries->cbegin()->x() << end->x();
142
142
143 /// Lambda used to validate a variable at each step
143 /// Lambda used to validate a variable at each step
144 auto validateVariable
144 auto validateVariable
145 = [dataSeries](std::shared_ptr<Variable> variable, const SqpRange &range) {
145 = [dataSeries](std::shared_ptr<Variable> variable, const SqpRange &range) {
146 // Checks that the variable's range has changed
146 // Checks that the variable's range has changed
147 qInfo() << "range vs expected range" << variable->range() << range;
147 QCOMPARE(variable->range(), range);
148 QCOMPARE(variable->range(), range);
148
149
149 // Checks the variable's data series
150 // Checks the variable's data series
150 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
151 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
151 };
152 };
152
153
153 // Creates variable
154 // Creates variable
154 QFETCH(SqpRange, initialRange);
155 QFETCH(SqpRange, initialRange);
155 sqpApp->timeController().onTimeToUpdate(initialRange);
156 sqpApp->timeController().onTimeToUpdate(initialRange);
156 auto provider = std::make_shared<CosinusProvider>();
157 auto provider = std::make_shared<CosinusProvider>();
157 auto variable = sqpApp->variableController().createVariable(
158 auto variable = sqpApp->variableController().createVariable(
158 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}}, provider);
159 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}}, provider);
159
160
161
160 QFETCH(int, operationDelay);
162 QFETCH(int, operationDelay);
161 QTest::qWait(operationDelay);
163 QTest::qWait(operationDelay);
162 validateVariable(variable, initialRange);
164 validateVariable(variable, initialRange);
163
165
166 QTest::qWait(operationDelay);
164 // Makes operations on the variable
167 // Makes operations on the variable
165 QFETCH(std::vector<SqpRange>, operations);
168 QFETCH(std::vector<SqpRange>, operations);
166 for (const auto &operation : operations) {
169 for (const auto &operation : operations) {
167 // Asks request on the variable and waits during its execution
170 // Asks request on the variable and waits during its execution
168 sqpApp->variableController().onRequestDataLoading({variable}, operation, true);
171 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
169
172
170 QTest::qWait(operationDelay);
173 QTest::qWait(operationDelay);
171 validateVariable(variable, operation);
174 validateVariable(variable, operation);
172 }
175 }
173
176
174
177
175 for (const auto &operation : operations) {
178 for (const auto &operation : operations) {
176 // Asks request on the variable and waits during its execution
179 // Asks request on the variable and waits during its execution
177 sqpApp->variableController().onRequestDataLoading({variable}, operation, true);
180 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
178 }
181 }
179 QTest::qWait(operationDelay);
182 QTest::qWait(operationDelay);
180 validateVariable(variable, operations.back());
183 validateVariable(variable, operations.back());
181 }
184 }
182
185
183 int main(int argc, char *argv[])
186 int main(int argc, char *argv[])
184 {
187 {
185 SqpApplication app{argc, argv};
188 SqpApplication app{argc, argv};
186 app.setAttribute(Qt::AA_Use96Dpi, true);
189 app.setAttribute(Qt::AA_Use96Dpi, true);
187 TestCosinusAcquisition testObject{};
190 TestCosinusAcquisition testObject{};
188 QTEST_SET_MAIN_SOURCE_PATH
191 QTEST_SET_MAIN_SOURCE_PATH
189 return QTest::qExec(&testObject, argc, argv);
192 return QTest::qExec(&testObject, argc, argv);
190 }
193 }
191
194
192 #include "TestCosinusAcquisition.moc"
195 #include "TestCosinusAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now