##// END OF EJS Templates
Merge branch 'feature/FuzzingTests2' into develop
Alexandre Leroux -
r1221:5e5e6b9907f3 merge
parent child
Show More
@@ -0,0 +1,38
1 #ifndef SCIQLOP_SIGNALWAITER_H
2 #define SCIQLOP_SIGNALWAITER_H
3
4 #include "CoreGlobal.h"
5
6 #include <QEventLoop>
7
8 /**
9 * Class for synchronously waiting for the reception of a signal. The signal to wait is passed to
10 * the construction of the object. When starting the wait, a timeout can be set to exit if the
11 * signal has not been sent
12 */
13 class SCIQLOP_CORE_EXPORT SignalWaiter : public QObject {
14 Q_OBJECT
15 public:
16 /**
17 * Ctor
18 * @param object the sender of the signal
19 * @param signal the signal to listen
20 */
21 explicit SignalWaiter(QObject &sender, const char *signal);
22
23 /**
24 * Starts the signal and leaves after the signal has been received, or after the timeout
25 * @param timeout the timeout set (if 0, uses a default timeout)
26 * @return true if the signal was sent, false if the timeout occured
27 */
28 bool wait(int timeout);
29
30 private:
31 bool m_Timeout;
32 QEventLoop m_EventLoop;
33
34 private slots:
35 void timeout();
36 };
37
38 #endif // SCIQLOP_SIGNALWAITER_H
@@ -0,0 +1,36
1 #include "Common/SignalWaiter.h"
2
3 #include <QTimer>
4
5 namespace {
6
7 const auto DEFAULT_TIMEOUT = 30000;
8
9 } // namespace
10
11 SignalWaiter::SignalWaiter(QObject &sender, const char *signal) : m_Timeout{false}
12 {
13 connect(&sender, signal, &m_EventLoop, SLOT(quit()));
14 }
15
16 bool SignalWaiter::wait(int timeout)
17 {
18 if (timeout == 0) {
19 timeout = DEFAULT_TIMEOUT;
20 }
21
22 QTimer timer{};
23 timer.setInterval(timeout);
24 timer.start();
25 connect(&timer, &QTimer::timeout, this, &SignalWaiter::timeout);
26
27 m_EventLoop.exec();
28
29 return !m_Timeout;
30 }
31
32 void SignalWaiter::timeout()
33 {
34 m_Timeout = true;
35 m_EventLoop.quit();
36 }
@@ -0,0 +1,228
1 #include "FuzzingValidators.h"
2 #include "FuzzingDefs.h"
3
4 #include <Data/DataSeries.h>
5 #include <Variable/Variable.h>
6
7 #include <QTest>
8
9 #include <functional>
10
11 Q_LOGGING_CATEGORY(LOG_FuzzingValidators, "FuzzingValidators")
12
13 namespace {
14
15 // ////////////// //
16 // DATA VALIDATOR //
17 // ////////////// //
18
19 /// Singleton used to validate data of a variable
20 class DataValidatorHelper {
21 public:
22 /// @return the single instance of the helper
23 static DataValidatorHelper &instance();
24 virtual ~DataValidatorHelper() noexcept = default;
25
26 virtual void validate(const VariableState &variableState) const = 0;
27 };
28
29 /**
30 * Default implementation of @sa DataValidatorHelper
31 */
32 class DefaultDataValidatorHelper : public DataValidatorHelper {
33 public:
34 void validate(const VariableState &variableState) const override
35 {
36 Q_UNUSED(variableState);
37 qCWarning(LOG_FuzzingValidators()).noquote() << "Checking variable's data... WARN: no data "
38 "verification is available for this server";
39 }
40 };
41
42 /// Data resolution in local server's files
43 const auto LOCALHOST_SERVER_RESOLUTION = 4;
44 /// Reference value used to generate the data on the local server (a value is the number of seconds
45 /// between the data date and this reference date)
46 const auto LOCALHOST_REFERENCE_VALUE
47 = DateUtils::secondsSinceEpoch(QDateTime{QDate{2000, 1, 1}, QTime{}, Qt::UTC});
48
49 /**
50 * Implementation of @sa DataValidatorHelper for the local AMDA server
51 */
52 class LocalhostServerDataValidatorHelper : public DataValidatorHelper {
53 public:
54 void validate(const VariableState &variableState) const override
55 {
56 // Don't check data for null variable
57 if (!variableState.m_Variable || variableState.m_Range == INVALID_RANGE) {
58 return;
59 }
60
61 auto message = "Checking variable's data...";
62 auto toDateString = [](double value) { return DateUtils::dateTime(value).toString(); };
63
64 // Checks that data are defined
65 auto variableDataSeries = variableState.m_Variable->dataSeries();
66 if (variableDataSeries == nullptr && variableState.m_Range != INVALID_RANGE) {
67 qCInfo(LOG_FuzzingValidators()).noquote()
68 << message << "FAIL: the variable has no data while a range is defined";
69 QFAIL("");
70 }
71
72 auto dataIts = variableDataSeries->xAxisRange(variableState.m_Range.m_TStart,
73 variableState.m_Range.m_TEnd);
74
75 // Checks that the data are well defined in the range:
76 // - there is at least one data
77 // - the data are consistent (no data holes)
78 if (std::distance(dataIts.first, dataIts.second) == 0) {
79 qCInfo(LOG_FuzzingValidators()).noquote()
80 << message << "FAIL: the variable has no data";
81 QFAIL("");
82 }
83
84 auto firstXAxisData = dataIts.first->x();
85 auto lastXAxisData = (dataIts.second - 1)->x();
86
87 if (std::abs(firstXAxisData - variableState.m_Range.m_TStart) > LOCALHOST_SERVER_RESOLUTION
88 || std::abs(lastXAxisData - variableState.m_Range.m_TEnd)
89 > LOCALHOST_SERVER_RESOLUTION) {
90 qCInfo(LOG_FuzzingValidators()).noquote()
91 << message << "FAIL: the data in the defined range are inconsistent (data hole "
92 "found at the beginning or the end)";
93 QFAIL("");
94 }
95
96 auto dataHoleIt = std::adjacent_find(
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
98 /// @todo: validate resolution
99 return std::abs(it1.x() - it2.x()) > 2 * (LOCALHOST_SERVER_RESOLUTION - 1);
100 });
101
102 if (dataHoleIt != dataIts.second) {
103 qCInfo(LOG_FuzzingValidators()).noquote()
104 << message << "FAIL: the data in the defined range are inconsistent (data hole "
105 "found between times "
106 << toDateString(dataHoleIt->x()) << "and " << toDateString((dataHoleIt + 1)->x())
107 << ")";
108 QFAIL("");
109 }
110
111 // Checks values
112 auto dataIndex = 0;
113 for (auto dataIt = dataIts.first; dataIt != dataIts.second; ++dataIt, ++dataIndex) {
114 auto xAxisData = dataIt->x();
115 auto valuesData = dataIt->values();
116 for (auto valueIndex = 0, valueEnd = valuesData.size(); valueIndex < valueEnd;
117 ++valueIndex) {
118 auto value = valuesData.at(valueIndex);
119 auto expectedValue = xAxisData + valueIndex * LOCALHOST_SERVER_RESOLUTION
120 - LOCALHOST_REFERENCE_VALUE;
121
122 if (value != expectedValue) {
123 qCInfo(LOG_FuzzingValidators()).noquote()
124 << message << "FAIL: incorrect value data at time"
125 << toDateString(xAxisData) << ", index" << valueIndex << "(found:" << value
126 << ", expected:" << expectedValue << ")";
127 QFAIL("");
128 }
129 }
130 }
131
132 // At this step validation is OK
133 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
134 }
135 };
136
137 /// Creates the @sa DataValidatorHelper according to the server passed in parameter
138 std::unique_ptr<DataValidatorHelper> createDataValidatorInstance(const QString &server)
139 {
140 if (server == QString{"localhost"}) {
141 return std::make_unique<LocalhostServerDataValidatorHelper>();
142 }
143 else {
144 return std::make_unique<DefaultDataValidatorHelper>();
145 }
146 }
147
148 DataValidatorHelper &DataValidatorHelper::instance()
149 {
150 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
151 static auto instance = createDataValidatorInstance(SCIQLOP_AMDA_SERVER);
152 return *instance;
153 }
154
155 // /////////////// //
156 // RANGE VALIDATOR //
157 // /////////////// //
158
159 /**
160 * Checks that a range of a variable matches the expected range passed as a parameter
161 * @param variable the variable for which to check the range
162 * @param expectedRange the expected range
163 * @param getVariableRangeFun the function to retrieve the range from the variable
164 * @remarks if the variable is null, checks that the expected range is the invalid range
165 */
166 void validateRange(std::shared_ptr<Variable> variable, const SqpRange &expectedRange,
167 std::function<SqpRange(const Variable &)> getVariableRangeFun)
168 {
169 auto compare = [](const auto &range, const auto &expectedRange, const auto &message) {
170 if (range == expectedRange) {
171 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
172 }
173 else {
174 qCInfo(LOG_FuzzingValidators()).noquote()
175 << message << "FAIL (current range:" << range
176 << ", expected range:" << expectedRange << ")";
177 QFAIL("");
178 }
179 };
180
181 if (variable) {
182 compare(getVariableRangeFun(*variable), expectedRange, "Checking variable's range...");
183 }
184 else {
185 compare(INVALID_RANGE, expectedRange, "Checking that there is no range set...");
186 }
187 }
188
189 /**
190 * Default implementation of @sa IFuzzingValidator. This validator takes as parameter of its
191 * construction a function of validation which is called in the validate() method
192 */
193 class FuzzingValidator : public IFuzzingValidator {
194 public:
195 /// Signature of a validation function
196 using ValidationFunction = std::function<void(const VariableState &variableState)>;
197
198 explicit FuzzingValidator(ValidationFunction fun) : m_Fun(std::move(fun)) {}
199
200 void validate(const VariableState &variableState) const override { m_Fun(variableState); }
201
202 private:
203 ValidationFunction m_Fun;
204 };
205
206 } // namespace
207
208 std::unique_ptr<IFuzzingValidator> FuzzingValidatorFactory::create(FuzzingValidatorType type)
209 {
210 switch (type) {
211 case FuzzingValidatorType::DATA:
212 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
213 DataValidatorHelper::instance().validate(variableState);
214 });
215 case FuzzingValidatorType::RANGE:
216 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
217 auto getVariableRange = [](const Variable &variable) { return variable.range(); };
218 validateRange(variableState.m_Variable, variableState.m_Range, getVariableRange);
219 });
220 default:
221 // Default case returns invalid validator
222 break;
223 }
224
225 // Invalid validator
226 return std::make_unique<FuzzingValidator>(
227 [](const VariableState &) { QFAIL("Invalid validator"); });
228 }
@@ -0,0 +1,40
1 #ifndef SCIQLOP_FUZZINGVALIDATORS_H
2 #define SCIQLOP_FUZZINGVALIDATORS_H
3
4 #include <memory>
5 #include <set>
6
7 #include <QLoggingCategory>
8 #include <QMetaType>
9
10 Q_DECLARE_LOGGING_CATEGORY(LOG_FuzzingValidators)
11
12 class VariableState;
13
14 /// Types of validators that can be defined
15 enum class FuzzingValidatorType {
16 DATA, ///< Validates variable's data
17 RANGE ///< Validates variable's range
18 };
19
20 /**
21 * Struct that represents a validator. A validator checks if the state of a variable is valid at the
22 * moment it is called during a fuzzing test
23 */
24 struct IFuzzingValidator {
25 virtual ~IFuzzingValidator() noexcept = default;
26
27 /// Validates the variable's state passed in parameter
28 virtual void validate(const VariableState &variableState) const = 0;
29 };
30
31 /// Factory of @sa IFuzzingValidator
32 struct FuzzingValidatorFactory {
33 /// Creates a validator according to the type passed in parameter
34 static std::unique_ptr<IFuzzingValidator> create(FuzzingValidatorType type);
35 };
36
37 using ValidatorsTypes = std::vector<FuzzingValidatorType>;
38 Q_DECLARE_METATYPE(ValidatorsTypes)
39
40 #endif // SCIQLOP_FUZZINGVALIDATORS_H
@@ -1,66 +1,66
1 #ifndef SCIQLOP_SQPRANGE_H
1 #ifndef SCIQLOP_SQPRANGE_H
2 #define SCIQLOP_SQPRANGE_H
2 #define SCIQLOP_SQPRANGE_H
3
3
4 #include <QObject>
4 #include <QObject>
5
5
6 #include <QDebug>
6 #include <QDebug>
7
7
8 #include <Common/DateUtils.h>
8 #include <Common/DateUtils.h>
9 #include <Common/MetaTypes.h>
9 #include <Common/MetaTypes.h>
10
10
11 #include <cmath>
11 #include <cmath>
12
12
13 /**
13 /**
14 * @brief The SqpRange struct holds the information of time parameters
14 * @brief The SqpRange struct holds the information of time parameters
15 */
15 */
16 struct SqpRange {
16 struct SqpRange {
17 /// Creates SqpRange from dates and times
17 /// Creates SqpRange from dates and times
18 static SqpRange fromDateTime(const QDate &startDate, const QTime &startTime,
18 static SqpRange fromDateTime(const QDate &startDate, const QTime &startTime,
19 const QDate &endDate, const QTime &endTime)
19 const QDate &endDate, const QTime &endTime)
20 {
20 {
21 return {DateUtils::secondsSinceEpoch(QDateTime{startDate, startTime}),
21 return {DateUtils::secondsSinceEpoch(QDateTime{startDate, startTime, Qt::UTC}),
22 DateUtils::secondsSinceEpoch(QDateTime{endDate, endTime})};
22 DateUtils::secondsSinceEpoch(QDateTime{endDate, endTime, Qt::UTC})};
23 }
23 }
24
24
25 /// Start time (UTC)
25 /// Start time (UTC)
26 double m_TStart;
26 double m_TStart;
27 /// End time (UTC)
27 /// End time (UTC)
28 double m_TEnd;
28 double m_TEnd;
29
29
30 bool contains(const SqpRange &dateTime) const noexcept
30 bool contains(const SqpRange &dateTime) const noexcept
31 {
31 {
32 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
32 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
33 }
33 }
34
34
35 bool intersect(const SqpRange &dateTime) const noexcept
35 bool intersect(const SqpRange &dateTime) const noexcept
36 {
36 {
37 return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd);
37 return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd);
38 }
38 }
39
39
40 bool operator==(const SqpRange &other) const
40 bool operator==(const SqpRange &other) const
41 {
41 {
42 auto equals = [](const auto &v1, const auto &v2) {
42 auto equals = [](const auto &v1, const auto &v2) {
43 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
43 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
44 };
44 };
45
45
46 return equals(m_TStart, other.m_TStart) && equals(m_TEnd, other.m_TEnd);
46 return equals(m_TStart, other.m_TStart) && equals(m_TEnd, other.m_TEnd);
47 }
47 }
48 bool operator!=(const SqpRange &other) const { return !(*this == other); }
48 bool operator!=(const SqpRange &other) const { return !(*this == other); }
49 };
49 };
50
50
51 const auto INVALID_RANGE
51 const auto INVALID_RANGE
52 = SqpRange{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()};
52 = SqpRange{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()};
53
53
54 inline QDebug operator<<(QDebug d, SqpRange obj)
54 inline QDebug operator<<(QDebug d, SqpRange obj)
55 {
55 {
56 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
56 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
57 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
57 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
58
58
59 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
59 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
60 return d;
60 return d;
61 }
61 }
62
62
63 // Required for using shared_ptr in signals/slots
63 // Required for using shared_ptr in signals/slots
64 SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, SqpRange)
64 SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, SqpRange)
65
65
66 #endif // SCIQLOP_SQPRANGE_H
66 #endif // SCIQLOP_SQPRANGE_H
@@ -1,138 +1,142
1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 #define SCIQLOP_VARIABLECONTROLLER_H
2 #define SCIQLOP_VARIABLECONTROLLER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/AcquisitionDataPacket.h>
6 #include <Data/AcquisitionDataPacket.h>
7 #include <Data/SqpRange.h>
7 #include <Data/SqpRange.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QObject>
10 #include <QObject>
11 #include <QUuid>
11 #include <QUuid>
12
12
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 class IDataProvider;
15 class IDataProvider;
16 class QItemSelectionModel;
16 class QItemSelectionModel;
17 class TimeController;
17 class TimeController;
18 class Variable;
18 class Variable;
19 class VariableModel;
19 class VariableModel;
20
20
21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
22
22
23
23
24 /**
24 /**
25 * Possible types of zoom operation
25 * Possible types of zoom operation
26 */
26 */
27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
28
28
29
29
30 /**
30 /**
31 * @brief The VariableController class aims to handle the variables in SciQlop.
31 * @brief The VariableController class aims to handle the variables in SciQlop.
32 */
32 */
33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
34 Q_OBJECT
34 Q_OBJECT
35 public:
35 public:
36 explicit VariableController(QObject *parent = 0);
36 explicit VariableController(QObject *parent = 0);
37 virtual ~VariableController();
37 virtual ~VariableController();
38
38
39 VariableModel *variableModel() noexcept;
39 VariableModel *variableModel() noexcept;
40 QItemSelectionModel *variableSelectionModel() noexcept;
40 QItemSelectionModel *variableSelectionModel() noexcept;
41
41
42 void setTimeController(TimeController *timeController) noexcept;
42 void setTimeController(TimeController *timeController) noexcept;
43
43
44 /**
44 /**
45 * Clones the variable passed in parameter and adds the duplicate to the controller
45 * Clones the variable passed in parameter and adds the duplicate to the controller
46 * @param variable the variable to duplicate
46 * @param variable the variable to duplicate
47 * @return the duplicate created, nullptr if the variable couldn't be created
47 * @return the duplicate created, nullptr if the variable couldn't be created
48 */
48 */
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
50
50
51 /**
51 /**
52 * Deletes from the controller the variable passed in parameter.
52 * Deletes from the controller the variable passed in parameter.
53 *
53 *
54 * Delete a variable includes:
54 * Delete a variable includes:
55 * - the deletion of the various references to the variable in SciQlop
55 * - the deletion of the various references to the variable in SciQlop
56 * - the deletion of the model variable
56 * - the deletion of the model variable
57 * - the deletion of the provider associated with the variable
57 * - the deletion of the provider associated with the variable
58 * - removing the cache associated with the variable
58 * - removing the cache associated with the variable
59 *
59 *
60 * @param variable the variable to delete from the controller.
60 * @param variable the variable to delete from the controller.
61 */
61 */
62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
63
63
64 /**
64 /**
65 * Deletes from the controller the variables passed in parameter.
65 * Deletes from the controller the variables passed in parameter.
66 * @param variables the variables to delete from the controller.
66 * @param variables the variables to delete from the controller.
67 * @sa deleteVariable()
67 * @sa deleteVariable()
68 */
68 */
69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
70
70
71 /// Returns the MIME data associated to a list of variables
71 /// Returns the MIME data associated to a list of variables
72 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
72 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
73
73
74 /// Returns the list of variables contained in a MIME data
74 /// Returns the list of variables contained in a MIME data
75 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
75 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
76
76
77 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
77 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
78 signals:
78 signals:
79 /// Signal emitted when a variable is about to be deleted from the controller
79 /// Signal emitted when a variable is about to be deleted from the controller
80 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
80 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
81
81
82 /// Signal emitted when a data acquisition is requested on a range for a variable
82 /// Signal emitted when a data acquisition is requested on a range for a variable
83 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
83 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
84
84
85 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
85 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
86 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
86 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
87
87
88 /// Signal emitted when all acquisitions related to the variables have been completed (whether
89 /// validated, canceled, or failed)
90 void acquisitionFinished();
91
88 public slots:
92 public slots:
89 /// Request the data loading of the variable whithin range
93 /// Request the data loading of the variable whithin range
90 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
94 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
91 bool synchronise);
95 bool synchronise);
92 /**
96 /**
93 * Creates a new variable and adds it to the model
97 * Creates a new variable and adds it to the model
94 * @param name the name of the new variable
98 * @param name the name of the new variable
95 * @param metadata the metadata of the new variable
99 * @param metadata the metadata of the new variable
96 * @param provider the data provider for the new variable
100 * @param provider the data provider for the new variable
97 * @return the pointer to the new variable or nullptr if the creation failed
101 * @return the pointer to the new variable or nullptr if the creation failed
98 */
102 */
99 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
103 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
100 std::shared_ptr<IDataProvider> provider) noexcept;
104 std::shared_ptr<IDataProvider> provider) noexcept;
101
105
102 /// Update the temporal parameters of every selected variable to dateTime
106 /// Update the temporal parameters of every selected variable to dateTime
103 void onDateTimeOnSelection(const SqpRange &dateTime);
107 void onDateTimeOnSelection(const SqpRange &dateTime);
104
108
105 /// Update the temporal parameters of the specified variable
109 /// Update the temporal parameters of the specified variable
106 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
110 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
107
111
108
112
109 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
113 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
110 const SqpRange &cacheRangeRequested,
114 const SqpRange &cacheRangeRequested,
111 QVector<AcquisitionDataPacket> dataAcquired);
115 QVector<AcquisitionDataPacket> dataAcquired);
112
116
113 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
117 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
114
118
115 /// Cancel the current request for the variable
119 /// Cancel the current request for the variable
116 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
120 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
117 void onAbortAcquisitionRequested(QUuid vIdentifier);
121 void onAbortAcquisitionRequested(QUuid vIdentifier);
118
122
119 // synchronization group methods
123 // synchronization group methods
120 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
124 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
121 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
125 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
122 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
126 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
123
127
124 /// Desynchronizes the variable of the group whose identifier is passed in parameter
128 /// Desynchronizes the variable of the group whose identifier is passed in parameter
125 /// @remarks the method does nothing if the variable is not part of the group
129 /// @remarks the method does nothing if the variable is not part of the group
126 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
130 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
127
131
128 void initialize();
132 void initialize();
129 void finalize();
133 void finalize();
130
134
131 private:
135 private:
132 void waitForFinish();
136 void waitForFinish();
133
137
134 class VariableControllerPrivate;
138 class VariableControllerPrivate;
135 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
139 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
136 };
140 };
137
141
138 #endif // SCIQLOP_VARIABLECONTROLLER_H
142 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,73 +1,75
1
1
2 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
2 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
3 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
3 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
4
4
5
5
6 core_moc_headers = [
6 core_moc_headers = [
7 'include/Catalogue/CatalogueController.h',
7 'include/Catalogue/CatalogueController.h',
8 'include/Common/SignalWaiter.h',
8 'include/Data/IDataProvider.h',
9 'include/Data/IDataProvider.h',
9 'include/DataSource/DataSourceController.h',
10 'include/DataSource/DataSourceController.h',
10 'include/DataSource/DataSourceItemAction.h',
11 'include/DataSource/DataSourceItemAction.h',
11 'include/Network/NetworkController.h',
12 'include/Network/NetworkController.h',
12 'include/Time/TimeController.h',
13 'include/Time/TimeController.h',
13 'include/Variable/Variable.h',
14 'include/Variable/Variable.h',
14 'include/Variable/VariableCacheController.h',
15 'include/Variable/VariableCacheController.h',
15 'include/Variable/VariableController.h',
16 'include/Variable/VariableController.h',
16 'include/Variable/VariableAcquisitionWorker.h',
17 'include/Variable/VariableAcquisitionWorker.h',
17 'include/Variable/VariableSynchronizationGroup.h',
18 'include/Variable/VariableSynchronizationGroup.h',
18 'include/Variable/VariableModel.h',
19 'include/Variable/VariableModel.h',
19 'include/Visualization/VisualizationController.h'
20 'include/Visualization/VisualizationController.h'
20 ]
21 ]
21
22
22
23
23 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers)
24 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers)
24
25
25 core_sources = [
26 core_sources = [
26 'src/Common/DateUtils.cpp',
27 'src/Common/DateUtils.cpp',
28 'src/Common/SignalWaiter.cpp',
27 'src/Common/StringUtils.cpp',
29 'src/Common/StringUtils.cpp',
28 'src/Common/MimeTypesDef.cpp',
30 'src/Common/MimeTypesDef.cpp',
29 'src/Catalogue/CatalogueController.cpp',
31 'src/Catalogue/CatalogueController.cpp',
30 'src/Data/ScalarSeries.cpp',
32 'src/Data/ScalarSeries.cpp',
31 'src/Data/SpectrogramSeries.cpp',
33 'src/Data/SpectrogramSeries.cpp',
32 'src/Data/DataSeriesIterator.cpp',
34 'src/Data/DataSeriesIterator.cpp',
33 'src/Data/ArrayDataIterator.cpp',
35 'src/Data/ArrayDataIterator.cpp',
34 'src/Data/VectorSeries.cpp',
36 'src/Data/VectorSeries.cpp',
35 'src/Data/OptionalAxis.cpp',
37 'src/Data/OptionalAxis.cpp',
36 'src/Data/DataSeriesUtils.cpp',
38 'src/Data/DataSeriesUtils.cpp',
37 'src/DataSource/DataSourceController.cpp',
39 'src/DataSource/DataSourceController.cpp',
38 'src/DataSource/DataSourceItem.cpp',
40 'src/DataSource/DataSourceItem.cpp',
39 'src/DataSource/DataSourceItemAction.cpp',
41 'src/DataSource/DataSourceItemAction.cpp',
40 'src/DataSource/DataSourceItemMergeHelper.cpp',
42 'src/DataSource/DataSourceItemMergeHelper.cpp',
41 'src/Network/NetworkController.cpp',
43 'src/Network/NetworkController.cpp',
42 'src/Plugin/PluginManager.cpp',
44 'src/Plugin/PluginManager.cpp',
43 'src/Settings/SqpSettingsDefs.cpp',
45 'src/Settings/SqpSettingsDefs.cpp',
44 'src/Time/TimeController.cpp',
46 'src/Time/TimeController.cpp',
45 'src/Variable/Variable.cpp',
47 'src/Variable/Variable.cpp',
46 'src/Variable/VariableCacheController.cpp',
48 'src/Variable/VariableCacheController.cpp',
47 'src/Variable/VariableController.cpp',
49 'src/Variable/VariableController.cpp',
48 'src/Variable/VariableAcquisitionWorker.cpp',
50 'src/Variable/VariableAcquisitionWorker.cpp',
49 'src/Variable/VariableSynchronizationGroup.cpp',
51 'src/Variable/VariableSynchronizationGroup.cpp',
50 'src/Variable/VariableModel.cpp',
52 'src/Variable/VariableModel.cpp',
51 'src/Visualization/VisualizationController.cpp'
53 'src/Visualization/VisualizationController.cpp'
52 ]
54 ]
53
55
54 core_inc = include_directories(['include', '../plugin/include'])
56 core_inc = include_directories(['include', '../plugin/include'])
55
57
56 sciqlop_core_lib = library('sciqlopcore',
58 sciqlop_core_lib = library('sciqlopcore',
57 core_sources,
59 core_sources,
58 core_moc_files,
60 core_moc_files,
59 cpp_args : '-DCORE_LIB',
61 cpp_args : '-DCORE_LIB',
60 include_directories : core_inc,
62 include_directories : core_inc,
61 dependencies : [qt5core, qt5network, catalogueapi_dep],
63 dependencies : [qt5core, qt5network, catalogueapi_dep],
62 install : true
64 install : true
63 )
65 )
64
66
65
67
66 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
68 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
67 include_directories : core_inc,
69 include_directories : core_inc,
68 dependencies : [qt5core, qt5network, catalogueapi_dep])
70 dependencies : [qt5core, qt5network, catalogueapi_dep])
69
71
70
72
71
73
72 subdir('tests')
74 subdir('tests')
73
75
@@ -1,1063 +1,1069
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 <QDataStream>
15 #include <QDataStream>
16 #include <QMutex>
16 #include <QMutex>
17 #include <QThread>
17 #include <QThread>
18 #include <QUuid>
18 #include <QUuid>
19 #include <QtCore/QItemSelectionModel>
19 #include <QtCore/QItemSelectionModel>
20
20
21 #include <deque>
21 #include <deque>
22 #include <set>
22 #include <set>
23 #include <unordered_map>
23 #include <unordered_map>
24
24
25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
26
26
27 namespace {
27 namespace {
28
28
29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
30 const SqpRange &oldGraphRange)
30 const SqpRange &oldGraphRange)
31 {
31 {
32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
33
33
34 auto varRangeRequested = varRange;
34 auto varRangeRequested = varRange;
35 switch (zoomType) {
35 switch (zoomType) {
36 case AcquisitionZoomType::ZoomIn: {
36 case AcquisitionZoomType::ZoomIn: {
37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
39 varRangeRequested.m_TStart += deltaLeft;
39 varRangeRequested.m_TStart += deltaLeft;
40 varRangeRequested.m_TEnd -= deltaRight;
40 varRangeRequested.m_TEnd -= deltaRight;
41 break;
41 break;
42 }
42 }
43
43
44 case AcquisitionZoomType::ZoomOut: {
44 case AcquisitionZoomType::ZoomOut: {
45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
47 varRangeRequested.m_TStart -= deltaLeft;
47 varRangeRequested.m_TStart -= deltaLeft;
48 varRangeRequested.m_TEnd += deltaRight;
48 varRangeRequested.m_TEnd += deltaRight;
49 break;
49 break;
50 }
50 }
51 case AcquisitionZoomType::PanRight: {
51 case AcquisitionZoomType::PanRight: {
52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
54 varRangeRequested.m_TStart += deltaLeft;
54 varRangeRequested.m_TStart += deltaLeft;
55 varRangeRequested.m_TEnd += deltaRight;
55 varRangeRequested.m_TEnd += deltaRight;
56 break;
56 break;
57 }
57 }
58 case AcquisitionZoomType::PanLeft: {
58 case AcquisitionZoomType::PanLeft: {
59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
61 varRangeRequested.m_TStart -= deltaLeft;
61 varRangeRequested.m_TStart -= deltaLeft;
62 varRangeRequested.m_TEnd -= deltaRight;
62 varRangeRequested.m_TEnd -= deltaRight;
63 break;
63 break;
64 }
64 }
65 case AcquisitionZoomType::Unknown: {
65 case AcquisitionZoomType::Unknown: {
66 qCCritical(LOG_VariableController())
66 qCCritical(LOG_VariableController())
67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
68 break;
68 break;
69 }
69 }
70 default:
70 default:
71 qCCritical(LOG_VariableController()) << VariableController::tr(
71 qCCritical(LOG_VariableController()) << VariableController::tr(
72 "Impossible to synchronize: zoom type not take into account");
72 "Impossible to synchronize: zoom type not take into account");
73 // No action
73 // No action
74 break;
74 break;
75 }
75 }
76
76
77 return varRangeRequested;
77 return varRangeRequested;
78 }
78 }
79 }
79 }
80
80
81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
82
82
83 struct VariableRequestHandler {
83 struct VariableRequestHandler {
84
84
85 VariableRequestHandler()
85 VariableRequestHandler()
86 {
86 {
87 m_CanUpdate = false;
87 m_CanUpdate = false;
88 m_State = VariableRequestHandlerState::OFF;
88 m_State = VariableRequestHandlerState::OFF;
89 }
89 }
90
90
91 QUuid m_VarId;
91 QUuid m_VarId;
92 VariableRequest m_RunningVarRequest;
92 VariableRequest m_RunningVarRequest;
93 VariableRequest m_PendingVarRequest;
93 VariableRequest m_PendingVarRequest;
94 VariableRequestHandlerState m_State;
94 VariableRequestHandlerState m_State;
95 bool m_CanUpdate;
95 bool m_CanUpdate;
96 };
96 };
97
97
98 struct VariableController::VariableControllerPrivate {
98 struct VariableController::VariableControllerPrivate {
99 explicit VariableControllerPrivate(VariableController *parent)
99 explicit VariableControllerPrivate(VariableController *parent)
100 : m_WorkingMutex{},
100 : m_WorkingMutex{},
101 m_VariableModel{new VariableModel{parent}},
101 m_VariableModel{new VariableModel{parent}},
102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
105 CacheStrategy::SingleThreshold)},
105 CacheStrategy::SingleThreshold)},
106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
107 q{parent}
107 q{parent}
108 {
108 {
109
109
110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
112 }
112 }
113
113
114
114
115 virtual ~VariableControllerPrivate()
115 virtual ~VariableControllerPrivate()
116 {
116 {
117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
118 m_VariableAcquisitionWorkerThread.quit();
118 m_VariableAcquisitionWorkerThread.quit();
119 m_VariableAcquisitionWorkerThread.wait();
119 m_VariableAcquisitionWorkerThread.wait();
120 }
120 }
121
121
122
122
123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
124 QUuid varRequestId);
124 QUuid varRequestId);
125
125
126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
127 std::shared_ptr<IDataSeries>
127 std::shared_ptr<IDataSeries>
128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
129
129
130 void registerProvider(std::shared_ptr<IDataProvider> provider);
130 void registerProvider(std::shared_ptr<IDataProvider> provider);
131
131
132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
134 void updateVariables(QUuid varRequestId);
134 void updateVariables(QUuid varRequestId);
135 void updateVariableRequest(QUuid varRequestId);
135 void updateVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138
138
139 QMutex m_WorkingMutex;
139 QMutex m_WorkingMutex;
140 /// Variable model. The VariableController has the ownership
140 /// Variable model. The VariableController has the ownership
141 VariableModel *m_VariableModel;
141 VariableModel *m_VariableModel;
142 QItemSelectionModel *m_VariableSelectionModel;
142 QItemSelectionModel *m_VariableSelectionModel;
143
143
144
144
145 TimeController *m_TimeController{nullptr};
145 TimeController *m_TimeController{nullptr};
146 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
146 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
147 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
147 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
148 QThread m_VariableAcquisitionWorkerThread;
148 QThread m_VariableAcquisitionWorkerThread;
149
149
150 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
150 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
151 m_VariableToProviderMap;
151 m_VariableToProviderMap;
152 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
152 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
153 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
153 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
154 m_GroupIdToVariableSynchronizationGroupMap;
154 m_GroupIdToVariableSynchronizationGroupMap;
155 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
155 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
156 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
156 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
157
157
158 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
158 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
159 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
159 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
160
160
161 VariableController *q;
161 VariableController *q;
162 };
162 };
163
163
164
164
165 VariableController::VariableController(QObject *parent)
165 VariableController::VariableController(QObject *parent)
166 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
166 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
167 {
167 {
168 qCDebug(LOG_VariableController()) << tr("VariableController construction")
168 qCDebug(LOG_VariableController()) << tr("VariableController construction")
169 << QThread::currentThread();
169 << QThread::currentThread();
170
170
171 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
171 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
172 &VariableController::onAbortProgressRequested);
172 &VariableController::onAbortProgressRequested);
173
173
174 connect(impl->m_VariableAcquisitionWorker.get(),
174 connect(impl->m_VariableAcquisitionWorker.get(),
175 &VariableAcquisitionWorker::variableCanceledRequested, this,
175 &VariableAcquisitionWorker::variableCanceledRequested, this,
176 &VariableController::onAbortAcquisitionRequested);
176 &VariableController::onAbortAcquisitionRequested);
177
177
178 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
178 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
179 &VariableController::onDataProvided);
179 &VariableController::onDataProvided);
180 connect(impl->m_VariableAcquisitionWorker.get(),
180 connect(impl->m_VariableAcquisitionWorker.get(),
181 &VariableAcquisitionWorker::variableRequestInProgress, this,
181 &VariableAcquisitionWorker::variableRequestInProgress, this,
182 &VariableController::onVariableRetrieveDataInProgress);
182 &VariableController::onVariableRetrieveDataInProgress);
183
183
184
184
185 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
185 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
186 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
186 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
187 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
187 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
188 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
188 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
189
189
190 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
190 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
191 &VariableController::onUpdateDateTime);
191 &VariableController::onUpdateDateTime);
192
192
193 impl->m_VariableAcquisitionWorkerThread.start();
193 impl->m_VariableAcquisitionWorkerThread.start();
194 }
194 }
195
195
196 VariableController::~VariableController()
196 VariableController::~VariableController()
197 {
197 {
198 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
198 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
199 << QThread::currentThread();
199 << QThread::currentThread();
200 this->waitForFinish();
200 this->waitForFinish();
201 }
201 }
202
202
203 VariableModel *VariableController::variableModel() noexcept
203 VariableModel *VariableController::variableModel() noexcept
204 {
204 {
205 return impl->m_VariableModel;
205 return impl->m_VariableModel;
206 }
206 }
207
207
208 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
208 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
209 {
209 {
210 return impl->m_VariableSelectionModel;
210 return impl->m_VariableSelectionModel;
211 }
211 }
212
212
213 void VariableController::setTimeController(TimeController *timeController) noexcept
213 void VariableController::setTimeController(TimeController *timeController) noexcept
214 {
214 {
215 impl->m_TimeController = timeController;
215 impl->m_TimeController = timeController;
216 }
216 }
217
217
218 std::shared_ptr<Variable>
218 std::shared_ptr<Variable>
219 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
219 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
220 {
220 {
221 if (impl->m_VariableModel->containsVariable(variable)) {
221 if (impl->m_VariableModel->containsVariable(variable)) {
222 // Clones variable
222 // Clones variable
223 auto duplicate = variable->clone();
223 auto duplicate = variable->clone();
224
224
225 // Adds clone to model
225 // Adds clone to model
226 impl->m_VariableModel->addVariable(duplicate);
226 impl->m_VariableModel->addVariable(duplicate);
227
227
228 // Generates clone identifier
228 // Generates clone identifier
229 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
229 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
230
230
231 // Registers provider
231 // Registers provider
232 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
232 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
233 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
233 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
234
234
235 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
235 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
236 if (duplicateProvider) {
236 if (duplicateProvider) {
237 impl->registerProvider(duplicateProvider);
237 impl->registerProvider(duplicateProvider);
238 }
238 }
239
239
240 return duplicate;
240 return duplicate;
241 }
241 }
242 else {
242 else {
243 qCCritical(LOG_VariableController())
243 qCCritical(LOG_VariableController())
244 << tr("Can't create duplicate of variable %1: variable not registered in the model")
244 << tr("Can't create duplicate of variable %1: variable not registered in the model")
245 .arg(variable->name());
245 .arg(variable->name());
246 return nullptr;
246 return nullptr;
247 }
247 }
248 }
248 }
249
249
250 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
250 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
251 {
251 {
252 if (!variable) {
252 if (!variable) {
253 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
253 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
254 return;
254 return;
255 }
255 }
256
256
257 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
257 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
258 // make some treatments before the deletion
258 // make some treatments before the deletion
259 emit variableAboutToBeDeleted(variable);
259 emit variableAboutToBeDeleted(variable);
260
260
261 // Deletes identifier
261 // Deletes identifier
262 impl->m_VariableToIdentifierMap.erase(variable);
262 impl->m_VariableToIdentifierMap.erase(variable);
263
263
264 // Deletes provider
264 // Deletes provider
265 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
265 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
266 qCDebug(LOG_VariableController())
266 qCDebug(LOG_VariableController())
267 << tr("Number of providers deleted for variable %1: %2")
267 << tr("Number of providers deleted for variable %1: %2")
268 .arg(variable->name(), QString::number(nbProvidersDeleted));
268 .arg(variable->name(), QString::number(nbProvidersDeleted));
269
269
270
270
271 // Deletes from model
271 // Deletes from model
272 impl->m_VariableModel->deleteVariable(variable);
272 impl->m_VariableModel->deleteVariable(variable);
273 }
273 }
274
274
275 void VariableController::deleteVariables(
275 void VariableController::deleteVariables(
276 const QVector<std::shared_ptr<Variable> > &variables) noexcept
276 const QVector<std::shared_ptr<Variable> > &variables) noexcept
277 {
277 {
278 for (auto variable : qAsConst(variables)) {
278 for (auto variable : qAsConst(variables)) {
279 deleteVariable(variable);
279 deleteVariable(variable);
280 }
280 }
281 }
281 }
282
282
283 QByteArray
283 QByteArray
284 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
284 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
285 {
285 {
286 auto encodedData = QByteArray{};
286 auto encodedData = QByteArray{};
287
287
288 QVariantList ids;
288 QVariantList ids;
289 for (auto &var : variables) {
289 for (auto &var : variables) {
290 auto itVar = impl->m_VariableToIdentifierMap.find(var);
290 auto itVar = impl->m_VariableToIdentifierMap.find(var);
291 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
291 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
292 qCCritical(LOG_VariableController())
292 qCCritical(LOG_VariableController())
293 << tr("Impossible to find the data for an unknown variable.");
293 << tr("Impossible to find the data for an unknown variable.");
294 }
294 }
295
295
296 ids << itVar->second.toByteArray();
296 ids << itVar->second.toByteArray();
297 }
297 }
298
298
299 QDataStream stream{&encodedData, QIODevice::WriteOnly};
299 QDataStream stream{&encodedData, QIODevice::WriteOnly};
300 stream << ids;
300 stream << ids;
301
301
302 return encodedData;
302 return encodedData;
303 }
303 }
304
304
305 QList<std::shared_ptr<Variable> >
305 QList<std::shared_ptr<Variable> >
306 VariableController::variablesForMimeData(const QByteArray &mimeData) const
306 VariableController::variablesForMimeData(const QByteArray &mimeData) const
307 {
307 {
308 auto variables = QList<std::shared_ptr<Variable> >{};
308 auto variables = QList<std::shared_ptr<Variable> >{};
309 QDataStream stream{mimeData};
309 QDataStream stream{mimeData};
310
310
311 QVariantList ids;
311 QVariantList ids;
312 stream >> ids;
312 stream >> ids;
313
313
314 for (auto id : ids) {
314 for (auto id : ids) {
315 auto uuid = QUuid{id.toByteArray()};
315 auto uuid = QUuid{id.toByteArray()};
316 auto var = impl->findVariable(uuid);
316 auto var = impl->findVariable(uuid);
317 variables << var;
317 variables << var;
318 }
318 }
319
319
320 return variables;
320 return variables;
321 }
321 }
322
322
323 std::shared_ptr<Variable>
323 std::shared_ptr<Variable>
324 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
324 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
325 std::shared_ptr<IDataProvider> provider) noexcept
325 std::shared_ptr<IDataProvider> provider) noexcept
326 {
326 {
327 if (!impl->m_TimeController) {
327 if (!impl->m_TimeController) {
328 qCCritical(LOG_VariableController())
328 qCCritical(LOG_VariableController())
329 << tr("Impossible to create variable: The time controller is null");
329 << tr("Impossible to create variable: The time controller is null");
330 return nullptr;
330 return nullptr;
331 }
331 }
332
332
333 auto range = impl->m_TimeController->dateTime();
333 auto range = impl->m_TimeController->dateTime();
334
334
335 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
335 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
336 auto varId = QUuid::createUuid();
336 auto varId = QUuid::createUuid();
337
337
338 // Create the handler
338 // Create the handler
339 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
339 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
340 varRequestHandler->m_VarId = varId;
340 varRequestHandler->m_VarId = varId;
341
341
342 impl->m_VarIdToVarRequestHandler.insert(
342 impl->m_VarIdToVarRequestHandler.insert(
343 std::make_pair(varId, std::move(varRequestHandler)));
343 std::make_pair(varId, std::move(varRequestHandler)));
344
344
345 // store the provider
345 // store the provider
346 impl->registerProvider(provider);
346 impl->registerProvider(provider);
347
347
348 // Associate the provider
348 // Associate the provider
349 impl->m_VariableToProviderMap[newVariable] = provider;
349 impl->m_VariableToProviderMap[newVariable] = provider;
350 impl->m_VariableToIdentifierMap[newVariable] = varId;
350 impl->m_VariableToIdentifierMap[newVariable] = varId;
351
351
352 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
352 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
353
353
354 // auto varRequestId = QUuid::createUuid();
354 // auto varRequestId = QUuid::createUuid();
355 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
355 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
356 // impl->processRequest(newVariable, range, varRequestId);
356 // impl->processRequest(newVariable, range, varRequestId);
357 // impl->updateVariableRequest(varRequestId);
357 // impl->updateVariableRequest(varRequestId);
358
358
359 return newVariable;
359 return newVariable;
360 }
360 }
361
361
362 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
362 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
363 return nullptr;
363 return nullptr;
364 }
364 }
365
365
366 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
366 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
367 {
367 {
368 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
368 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
369 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
369 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
370 << QThread::currentThread()->objectName();
370 << QThread::currentThread()->objectName();
371 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
371 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
372
372
373 // NOTE we only permit the time modification for one variable
373 // NOTE we only permit the time modification for one variable
374 // DEPRECATED
374 // DEPRECATED
375 // auto variables = QVector<std::shared_ptr<Variable> >{};
375 // auto variables = QVector<std::shared_ptr<Variable> >{};
376 // for (const auto &selectedRow : qAsConst(selectedRows)) {
376 // for (const auto &selectedRow : qAsConst(selectedRows)) {
377 // if (auto selectedVariable =
377 // if (auto selectedVariable =
378 // impl->m_VariableModel->variable(selectedRow.row())) {
378 // impl->m_VariableModel->variable(selectedRow.row())) {
379 // variables << selectedVariable;
379 // variables << selectedVariable;
380
380
381 // // notify that rescale operation has to be done
381 // // notify that rescale operation has to be done
382 // emit rangeChanged(selectedVariable, dateTime);
382 // emit rangeChanged(selectedVariable, dateTime);
383 // }
383 // }
384 // }
384 // }
385 // if (!variables.isEmpty()) {
385 // if (!variables.isEmpty()) {
386 // this->onRequestDataLoading(variables, dateTime, synchro);
386 // this->onRequestDataLoading(variables, dateTime, synchro);
387 // }
387 // }
388 if (selectedRows.size() == 1) {
388 if (selectedRows.size() == 1) {
389
389
390 if (auto selectedVariable
390 if (auto selectedVariable
391 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
391 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
392
392
393 onUpdateDateTime(selectedVariable, dateTime);
393 onUpdateDateTime(selectedVariable, dateTime);
394 }
394 }
395 }
395 }
396 else if (selectedRows.size() > 1) {
396 else if (selectedRows.size() > 1) {
397 qCCritical(LOG_VariableController())
397 qCCritical(LOG_VariableController())
398 << tr("Impossible to set time for more than 1 variable in the same time");
398 << tr("Impossible to set time for more than 1 variable in the same time");
399 }
399 }
400 else {
400 else {
401 qCWarning(LOG_VariableController())
401 qCWarning(LOG_VariableController())
402 << tr("There is no variable selected to set the time one");
402 << tr("There is no variable selected to set the time one");
403 }
403 }
404 }
404 }
405
405
406 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
406 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
407 const SqpRange &dateTime)
407 const SqpRange &dateTime)
408 {
408 {
409 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
409 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
410 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
410 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
411 qCCritical(LOG_VariableController())
411 qCCritical(LOG_VariableController())
412 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
412 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
413 return;
413 return;
414 }
414 }
415
415
416 // notify that rescale operation has to be done
416 // notify that rescale operation has to be done
417 emit rangeChanged(variable, dateTime);
417 emit rangeChanged(variable, dateTime);
418
418
419 auto synchro
419 auto synchro
420 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
420 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
421
421
422 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
422 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
423 }
423 }
424
424
425 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
425 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
426 const SqpRange &cacheRangeRequested,
426 const SqpRange &cacheRangeRequested,
427 QVector<AcquisitionDataPacket> dataAcquired)
427 QVector<AcquisitionDataPacket> dataAcquired)
428 {
428 {
429 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
429 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
430 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
430 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
431 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
431 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
432 if (!varRequestId.isNull()) {
432 if (!varRequestId.isNull()) {
433 impl->updateVariables(varRequestId);
433 impl->updateVariables(varRequestId);
434 }
434 }
435 }
435 }
436
436
437 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
437 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
438 {
438 {
439 qCDebug(LOG_VariableController())
439 qCDebug(LOG_VariableController())
440 << "TORM: variableController::onVariableRetrieveDataInProgress"
440 << "TORM: variableController::onVariableRetrieveDataInProgress"
441 << QThread::currentThread()->objectName() << progress;
441 << QThread::currentThread()->objectName() << progress;
442 if (auto var = impl->findVariable(identifier)) {
442 if (auto var = impl->findVariable(identifier)) {
443 impl->m_VariableModel->setDataProgress(var, progress);
443 impl->m_VariableModel->setDataProgress(var, progress);
444 }
444 }
445 else {
445 else {
446 qCCritical(LOG_VariableController())
446 qCCritical(LOG_VariableController())
447 << tr("Impossible to notify progression of a null variable");
447 << tr("Impossible to notify progression of a null variable");
448 }
448 }
449 }
449 }
450
450
451 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
451 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
452 {
452 {
453 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
453 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
454 << QThread::currentThread()->objectName() << variable->name();
454 << QThread::currentThread()->objectName() << variable->name();
455
455
456 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
456 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
457 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
457 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
458 qCCritical(LOG_VariableController())
458 qCCritical(LOG_VariableController())
459 << tr("Impossible to onAbortProgressRequested request for unknown variable");
459 << tr("Impossible to onAbortProgressRequested request for unknown variable");
460 return;
460 return;
461 }
461 }
462
462
463 auto varId = itVar->second;
463 auto varId = itVar->second;
464
464
465 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
465 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
466 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
466 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
467 qCCritical(LOG_VariableController())
467 qCCritical(LOG_VariableController())
468 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
468 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
469 return;
469 return;
470 }
470 }
471
471
472 auto varHandler = itVarHandler->second.get();
472 auto varHandler = itVarHandler->second.get();
473
473
474 // case where a variable has a running request
474 // case where a variable has a running request
475 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
475 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
476 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
476 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
477 }
477 }
478 }
478 }
479
479
480 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
480 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
481 {
481 {
482 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
482 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
483 << QThread::currentThread()->objectName() << vIdentifier;
483 << QThread::currentThread()->objectName() << vIdentifier;
484
484
485 if (auto var = impl->findVariable(vIdentifier)) {
485 if (auto var = impl->findVariable(vIdentifier)) {
486 this->onAbortProgressRequested(var);
486 this->onAbortProgressRequested(var);
487 }
487 }
488 else {
488 else {
489 qCCritical(LOG_VariableController())
489 qCCritical(LOG_VariableController())
490 << tr("Impossible to abort Acquisition Requestof a null variable");
490 << tr("Impossible to abort Acquisition Requestof a null variable");
491 }
491 }
492 }
492 }
493
493
494 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
494 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
495 {
495 {
496 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
496 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
497 << QThread::currentThread()->objectName()
497 << QThread::currentThread()->objectName()
498 << synchronizationGroupId;
498 << synchronizationGroupId;
499 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
499 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
500 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
500 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
501 std::make_pair(synchronizationGroupId, vSynchroGroup));
501 std::make_pair(synchronizationGroupId, vSynchroGroup));
502 }
502 }
503
503
504 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
504 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
505 {
505 {
506 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
506 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
507 }
507 }
508
508
509 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
509 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
510 QUuid synchronizationGroupId)
510 QUuid synchronizationGroupId)
511
511
512 {
512 {
513 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
513 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
514 << synchronizationGroupId;
514 << synchronizationGroupId;
515 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
515 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
516 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
516 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
517 auto groupIdToVSGIt
517 auto groupIdToVSGIt
518 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
518 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
519 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
519 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
520 impl->m_VariableIdGroupIdMap.insert(
520 impl->m_VariableIdGroupIdMap.insert(
521 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
521 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
522 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
522 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
523 }
523 }
524 else {
524 else {
525 qCCritical(LOG_VariableController())
525 qCCritical(LOG_VariableController())
526 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
526 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
527 << variable->name();
527 << variable->name();
528 }
528 }
529 }
529 }
530 else {
530 else {
531 qCCritical(LOG_VariableController())
531 qCCritical(LOG_VariableController())
532 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
532 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
533 }
533 }
534 }
534 }
535
535
536 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
536 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
537 QUuid synchronizationGroupId)
537 QUuid synchronizationGroupId)
538 {
538 {
539 // Gets variable id
539 // Gets variable id
540 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
540 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
541 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
541 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
542 qCCritical(LOG_VariableController())
542 qCCritical(LOG_VariableController())
543 << tr("Can't desynchronize variable %1: variable identifier not found")
543 << tr("Can't desynchronize variable %1: variable identifier not found")
544 .arg(variable->name());
544 .arg(variable->name());
545 return;
545 return;
546 }
546 }
547
547
548 // Gets synchronization group
548 // Gets synchronization group
549 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
549 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
550 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
550 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
551 qCCritical(LOG_VariableController())
551 qCCritical(LOG_VariableController())
552 << tr("Can't desynchronize variable %1: unknown synchronization group")
552 << tr("Can't desynchronize variable %1: unknown synchronization group")
553 .arg(variable->name());
553 .arg(variable->name());
554 return;
554 return;
555 }
555 }
556
556
557 auto variableId = variableIt->second;
557 auto variableId = variableIt->second;
558
558
559 // Removes variable from synchronization group
559 // Removes variable from synchronization group
560 auto synchronizationGroup = groupIt->second;
560 auto synchronizationGroup = groupIt->second;
561 synchronizationGroup->removeVariableId(variableId);
561 synchronizationGroup->removeVariableId(variableId);
562
562
563 // Removes link between variable and synchronization group
563 // Removes link between variable and synchronization group
564 impl->m_VariableIdGroupIdMap.erase(variableId);
564 impl->m_VariableIdGroupIdMap.erase(variableId);
565 }
565 }
566
566
567 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
567 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
568 const SqpRange &range, bool synchronise)
568 const SqpRange &range, bool synchronise)
569 {
569 {
570 // variables is assumed synchronized
570 // variables is assumed synchronized
571 // TODO: Asser variables synchronization
571 // TODO: Asser variables synchronization
572 // we want to load data of the variable for the dateTime.
572 // we want to load data of the variable for the dateTime.
573 if (variables.isEmpty()) {
573 if (variables.isEmpty()) {
574 return;
574 return;
575 }
575 }
576
576
577 auto varRequestId = QUuid::createUuid();
577 auto varRequestId = QUuid::createUuid();
578 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
578 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
579 << QThread::currentThread()->objectName() << varRequestId
579 << QThread::currentThread()->objectName() << varRequestId
580 << range << synchronise;
580 << range << synchronise;
581
581
582 if (!synchronise) {
582 if (!synchronise) {
583 auto varIds = std::list<QUuid>{};
583 auto varIds = std::list<QUuid>{};
584 for (const auto &var : variables) {
584 for (const auto &var : variables) {
585 auto vId = impl->m_VariableToIdentifierMap.at(var);
585 auto vId = impl->m_VariableToIdentifierMap.at(var);
586 varIds.push_back(vId);
586 varIds.push_back(vId);
587 }
587 }
588 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
588 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
589 for (const auto &var : variables) {
589 for (const auto &var : variables) {
590 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
590 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
591 << varIds.size();
591 << varIds.size();
592 impl->processRequest(var, range, varRequestId);
592 impl->processRequest(var, range, varRequestId);
593 }
593 }
594 }
594 }
595 else {
595 else {
596 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
596 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
597 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
597 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
598 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
598 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
599 auto groupId = varIdToGroupIdIt->second;
599 auto groupId = varIdToGroupIdIt->second;
600
600
601 auto vSynchronizationGroup
601 auto vSynchronizationGroup
602 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
602 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
603 auto vSyncIds = vSynchronizationGroup->getIds();
603 auto vSyncIds = vSynchronizationGroup->getIds();
604
604
605 auto varIds = std::list<QUuid>{};
605 auto varIds = std::list<QUuid>{};
606 for (auto vId : vSyncIds) {
606 for (auto vId : vSyncIds) {
607 varIds.push_back(vId);
607 varIds.push_back(vId);
608 }
608 }
609 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
609 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
610
610
611 for (auto vId : vSyncIds) {
611 for (auto vId : vSyncIds) {
612 auto var = impl->findVariable(vId);
612 auto var = impl->findVariable(vId);
613
613
614 // Don't process already processed var
614 // Don't process already processed var
615 if (var != nullptr) {
615 if (var != nullptr) {
616 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
616 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
617 << varRequestId;
617 << varRequestId;
618 auto vSyncRangeRequested
618 auto vSyncRangeRequested
619 = variables.contains(var)
619 = variables.contains(var)
620 ? range
620 ? range
621 : computeSynchroRangeRequested(var->range(), range,
621 : computeSynchroRangeRequested(var->range(), range,
622 variables.first()->range());
622 variables.first()->range());
623 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
623 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
624 impl->processRequest(var, vSyncRangeRequested, varRequestId);
624 impl->processRequest(var, vSyncRangeRequested, varRequestId);
625 }
625 }
626 else {
626 else {
627 qCCritical(LOG_VariableController())
627 qCCritical(LOG_VariableController())
628
628
629 << tr("Impossible to synchronize a null variable");
629 << tr("Impossible to synchronize a null variable");
630 }
630 }
631 }
631 }
632 }
632 }
633 }
633 }
634
634
635 impl->updateVariables(varRequestId);
635 impl->updateVariables(varRequestId);
636 }
636 }
637
637
638
638
639 void VariableController::initialize()
639 void VariableController::initialize()
640 {
640 {
641 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
641 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
642 impl->m_WorkingMutex.lock();
642 impl->m_WorkingMutex.lock();
643 qCDebug(LOG_VariableController()) << tr("VariableController init END");
643 qCDebug(LOG_VariableController()) << tr("VariableController init END");
644 }
644 }
645
645
646 void VariableController::finalize()
646 void VariableController::finalize()
647 {
647 {
648 impl->m_WorkingMutex.unlock();
648 impl->m_WorkingMutex.unlock();
649 }
649 }
650
650
651 void VariableController::waitForFinish()
651 void VariableController::waitForFinish()
652 {
652 {
653 QMutexLocker locker{&impl->m_WorkingMutex};
653 QMutexLocker locker{&impl->m_WorkingMutex};
654 }
654 }
655
655
656 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
656 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
657 {
657 {
658 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
658 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
659 auto zoomType = AcquisitionZoomType::Unknown;
659 auto zoomType = AcquisitionZoomType::Unknown;
660 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
660 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
661 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
661 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
662 zoomType = AcquisitionZoomType::ZoomOut;
662 zoomType = AcquisitionZoomType::ZoomOut;
663 }
663 }
664 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
664 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
665 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
665 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
666 zoomType = AcquisitionZoomType::PanRight;
666 zoomType = AcquisitionZoomType::PanRight;
667 }
667 }
668 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
668 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
669 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
669 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
670 zoomType = AcquisitionZoomType::PanLeft;
670 zoomType = AcquisitionZoomType::PanLeft;
671 }
671 }
672 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
672 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
673 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
673 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
674 zoomType = AcquisitionZoomType::ZoomIn;
674 zoomType = AcquisitionZoomType::ZoomIn;
675 }
675 }
676 else {
676 else {
677 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
677 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
678 }
678 }
679 return zoomType;
679 return zoomType;
680 }
680 }
681
681
682 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
682 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
683 const SqpRange &rangeRequested,
683 const SqpRange &rangeRequested,
684 QUuid varRequestId)
684 QUuid varRequestId)
685 {
685 {
686 auto itVar = m_VariableToIdentifierMap.find(var);
686 auto itVar = m_VariableToIdentifierMap.find(var);
687 if (itVar == m_VariableToIdentifierMap.cend()) {
687 if (itVar == m_VariableToIdentifierMap.cend()) {
688 qCCritical(LOG_VariableController())
688 qCCritical(LOG_VariableController())
689 << tr("Impossible to process request for unknown variable");
689 << tr("Impossible to process request for unknown variable");
690 return;
690 return;
691 }
691 }
692
692
693 auto varId = itVar->second;
693 auto varId = itVar->second;
694
694
695 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
695 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
696 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
696 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
697 qCCritical(LOG_VariableController())
697 qCCritical(LOG_VariableController())
698 << tr("Impossible to process request for variable with unknown handler");
698 << tr("Impossible to process request for variable with unknown handler");
699 return;
699 return;
700 }
700 }
701
701
702 auto oldRange = var->range();
702 auto oldRange = var->range();
703
703
704 auto varHandler = itVarHandler->second.get();
704 auto varHandler = itVarHandler->second.get();
705
705
706 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
706 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
707 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
707 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
708 }
708 }
709
709
710 auto varRequest = VariableRequest{};
710 auto varRequest = VariableRequest{};
711 varRequest.m_VariableGroupId = varRequestId;
711 varRequest.m_VariableGroupId = varRequestId;
712 auto varStrategyRangesRequested
712 auto varStrategyRangesRequested
713 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
713 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
714 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
714 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
715 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
715 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
716
716
717 switch (varHandler->m_State) {
717 switch (varHandler->m_State) {
718 case VariableRequestHandlerState::OFF: {
718 case VariableRequestHandlerState::OFF: {
719 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
719 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
720 << varRequest.m_RangeRequested
720 << varRequest.m_RangeRequested
721 << varRequest.m_CacheRangeRequested;
721 << varRequest.m_CacheRangeRequested;
722 varHandler->m_RunningVarRequest = varRequest;
722 varHandler->m_RunningVarRequest = varRequest;
723 varHandler->m_State = VariableRequestHandlerState::RUNNING;
723 varHandler->m_State = VariableRequestHandlerState::RUNNING;
724 executeVarRequest(var, varRequest);
724 executeVarRequest(var, varRequest);
725 break;
725 break;
726 }
726 }
727 case VariableRequestHandlerState::RUNNING: {
727 case VariableRequestHandlerState::RUNNING: {
728 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
728 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
729 << varRequest.m_RangeRequested
729 << varRequest.m_RangeRequested
730 << varRequest.m_CacheRangeRequested;
730 << varRequest.m_CacheRangeRequested;
731 varHandler->m_State = VariableRequestHandlerState::PENDING;
731 varHandler->m_State = VariableRequestHandlerState::PENDING;
732 varHandler->m_PendingVarRequest = varRequest;
732 varHandler->m_PendingVarRequest = varRequest;
733 break;
733 break;
734 }
734 }
735 case VariableRequestHandlerState::PENDING: {
735 case VariableRequestHandlerState::PENDING: {
736 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
736 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
737 << varRequest.m_RangeRequested
737 << varRequest.m_RangeRequested
738 << varRequest.m_CacheRangeRequested;
738 << varRequest.m_CacheRangeRequested;
739 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
739 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
740 cancelVariableRequest(variableGroupIdToCancel);
740 cancelVariableRequest(variableGroupIdToCancel);
741 // Cancel variable can make state downgrade
741 // Cancel variable can make state downgrade
742 varHandler->m_State = VariableRequestHandlerState::PENDING;
742 varHandler->m_State = VariableRequestHandlerState::PENDING;
743 varHandler->m_PendingVarRequest = varRequest;
743 varHandler->m_PendingVarRequest = varRequest;
744
744
745 break;
745 break;
746 }
746 }
747 default:
747 default:
748 qCCritical(LOG_VariableController())
748 qCCritical(LOG_VariableController())
749 << QObject::tr("Unknown VariableRequestHandlerState");
749 << QObject::tr("Unknown VariableRequestHandlerState");
750 }
750 }
751 }
751 }
752
752
753 std::shared_ptr<Variable>
753 std::shared_ptr<Variable>
754 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
754 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
755 {
755 {
756 std::shared_ptr<Variable> var;
756 std::shared_ptr<Variable> var;
757 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
757 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
758
758
759 auto end = m_VariableToIdentifierMap.cend();
759 auto end = m_VariableToIdentifierMap.cend();
760 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
760 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
761 if (it != end) {
761 if (it != end) {
762 var = it->first;
762 var = it->first;
763 }
763 }
764 else {
764 else {
765 qCCritical(LOG_VariableController())
765 qCCritical(LOG_VariableController())
766 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
766 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
767 }
767 }
768
768
769 return var;
769 return var;
770 }
770 }
771
771
772 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
772 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
773 const QVector<AcquisitionDataPacket> acqDataPacketVector)
773 const QVector<AcquisitionDataPacket> acqDataPacketVector)
774 {
774 {
775 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
775 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
776 << acqDataPacketVector.size();
776 << acqDataPacketVector.size();
777 std::shared_ptr<IDataSeries> dataSeries;
777 std::shared_ptr<IDataSeries> dataSeries;
778 if (!acqDataPacketVector.isEmpty()) {
778 if (!acqDataPacketVector.isEmpty()) {
779 dataSeries = acqDataPacketVector[0].m_DateSeries;
779 dataSeries = acqDataPacketVector[0].m_DateSeries;
780 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
780 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
781 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
781 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
782 }
782 }
783 }
783 }
784 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
784 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
785 << acqDataPacketVector.size();
785 << acqDataPacketVector.size();
786 return dataSeries;
786 return dataSeries;
787 }
787 }
788
788
789 void VariableController::VariableControllerPrivate::registerProvider(
789 void VariableController::VariableControllerPrivate::registerProvider(
790 std::shared_ptr<IDataProvider> provider)
790 std::shared_ptr<IDataProvider> provider)
791 {
791 {
792 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
792 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
793 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
793 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
794 << provider->objectName();
794 << provider->objectName();
795 m_ProviderSet.insert(provider);
795 m_ProviderSet.insert(provider);
796 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
796 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
797 &VariableAcquisitionWorker::onVariableDataAcquired);
797 &VariableAcquisitionWorker::onVariableDataAcquired);
798 connect(provider.get(), &IDataProvider::dataProvidedProgress,
798 connect(provider.get(), &IDataProvider::dataProvidedProgress,
799 m_VariableAcquisitionWorker.get(),
799 m_VariableAcquisitionWorker.get(),
800 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
800 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
801 connect(provider.get(), &IDataProvider::dataProvidedFailed,
801 connect(provider.get(), &IDataProvider::dataProvidedFailed,
802 m_VariableAcquisitionWorker.get(),
802 m_VariableAcquisitionWorker.get(),
803 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
803 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
804 }
804 }
805 else {
805 else {
806 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
806 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
807 }
807 }
808 }
808 }
809
809
810 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
810 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
811 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
811 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
812 {
812 {
813 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
813 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
814 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
814 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
815 return QUuid();
815 return QUuid();
816 }
816 }
817
817
818 auto varHandler = itVarHandler->second.get();
818 auto varHandler = itVarHandler->second.get();
819 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
819 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
820 qCCritical(LOG_VariableController())
820 qCCritical(LOG_VariableController())
821 << tr("acceptVariableRequest impossible on a variable with OFF state");
821 << tr("acceptVariableRequest impossible on a variable with OFF state");
822 }
822 }
823
823
824 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
824 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
825 varHandler->m_CanUpdate = true;
825 varHandler->m_CanUpdate = true;
826
826
827 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
827 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
828 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
828 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
829 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
829 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
830 << m_VarGroupIdToVarIds.size();
830 << m_VarGroupIdToVarIds.size();
831
831
832 return varHandler->m_RunningVarRequest.m_VariableGroupId;
832 return varHandler->m_RunningVarRequest.m_VariableGroupId;
833 }
833 }
834
834
835 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
835 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
836 {
836 {
837 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
837 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
838 << QThread::currentThread()->objectName() << varRequestId;
838 << QThread::currentThread()->objectName() << varRequestId;
839
839
840 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
840 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
841 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
841 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
842 qCWarning(LOG_VariableController())
842 qCWarning(LOG_VariableController())
843 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
843 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
844 return;
844 return;
845 }
845 }
846
846
847 auto &varIds = varGroupIdToVarIdsIt->second;
847 auto &varIds = varGroupIdToVarIdsIt->second;
848 auto varIdsEnd = varIds.end();
848 auto varIdsEnd = varIds.end();
849 bool processVariableUpdate = true;
849 bool processVariableUpdate = true;
850 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
850 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
851 << varRequestId << varIds.size();
851 << varRequestId << varIds.size();
852 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
852 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
853 ++varIdsIt) {
853 ++varIdsIt) {
854 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
854 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
855 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
855 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
856 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
856 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
857 }
857 }
858 }
858 }
859
859
860 if (processVariableUpdate) {
860 if (processVariableUpdate) {
861 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
861 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
862 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
862 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
863 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
863 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
864 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
864 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
865 if (auto var = findVariable(*varIdsIt)) {
865 if (auto var = findVariable(*varIdsIt)) {
866 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
866 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
867 var->setRange(varRequest.m_RangeRequested);
867 var->setRange(varRequest.m_RangeRequested);
868 var->setCacheRange(varRequest.m_CacheRangeRequested);
868 var->setCacheRange(varRequest.m_CacheRangeRequested);
869 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
869 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
870 << varRequest.m_RangeRequested
870 << varRequest.m_RangeRequested
871 << varRequest.m_CacheRangeRequested;
871 << varRequest.m_CacheRangeRequested;
872 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
872 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
873 << var->nbPoints()
873 << var->nbPoints()
874 << varRequest.m_DataSeries->nbPoints();
874 << varRequest.m_DataSeries->nbPoints();
875 var->mergeDataSeries(varRequest.m_DataSeries);
875 var->mergeDataSeries(varRequest.m_DataSeries);
876 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
876 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
877 << var->nbPoints();
877 << var->nbPoints();
878
878
879 emit var->updated();
879 emit var->updated();
880 qCDebug(LOG_VariableController()) << tr("Update OK");
880 qCDebug(LOG_VariableController()) << tr("Update OK");
881 }
881 }
882 else {
882 else {
883 qCCritical(LOG_VariableController())
883 qCCritical(LOG_VariableController())
884 << tr("Impossible to update data to a null variable");
884 << tr("Impossible to update data to a null variable");
885 }
885 }
886 }
886 }
887 }
887 }
888 updateVariableRequest(varRequestId);
888 updateVariableRequest(varRequestId);
889
889
890 // cleaning varRequestId
890 // cleaning varRequestId
891 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
891 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
892 m_VarGroupIdToVarIds.erase(varRequestId);
892 m_VarGroupIdToVarIds.erase(varRequestId);
893 if (m_VarGroupIdToVarIds.empty()) {
894 emit q->acquisitionFinished();
895 }
893 }
896 }
894 }
897 }
895
898
896
899
897 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
900 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
898 {
901 {
899 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
902 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
900 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
903 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
901 qCCritical(LOG_VariableController()) << QObject::tr(
904 qCCritical(LOG_VariableController()) << QObject::tr(
902 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
905 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
903
906
904 return;
907 return;
905 }
908 }
906
909
907 auto &varIds = varGroupIdToVarIdsIt->second;
910 auto &varIds = varGroupIdToVarIdsIt->second;
908 auto varIdsEnd = varIds.end();
911 auto varIdsEnd = varIds.end();
909 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
912 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
910 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
913 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
911 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
914 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
912
915
913 auto varHandler = itVarHandler->second.get();
916 auto varHandler = itVarHandler->second.get();
914 varHandler->m_CanUpdate = false;
917 varHandler->m_CanUpdate = false;
915
918
916
919
917 switch (varHandler->m_State) {
920 switch (varHandler->m_State) {
918 case VariableRequestHandlerState::OFF: {
921 case VariableRequestHandlerState::OFF: {
919 qCCritical(LOG_VariableController())
922 qCCritical(LOG_VariableController())
920 << QObject::tr("Impossible to update a variable with handler in OFF state");
923 << QObject::tr("Impossible to update a variable with handler in OFF state");
921 } break;
924 } break;
922 case VariableRequestHandlerState::RUNNING: {
925 case VariableRequestHandlerState::RUNNING: {
923 varHandler->m_State = VariableRequestHandlerState::OFF;
926 varHandler->m_State = VariableRequestHandlerState::OFF;
924 varHandler->m_RunningVarRequest = VariableRequest{};
927 varHandler->m_RunningVarRequest = VariableRequest{};
925 break;
928 break;
926 }
929 }
927 case VariableRequestHandlerState::PENDING: {
930 case VariableRequestHandlerState::PENDING: {
928 varHandler->m_State = VariableRequestHandlerState::RUNNING;
931 varHandler->m_State = VariableRequestHandlerState::RUNNING;
929 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
932 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
930 varHandler->m_PendingVarRequest = VariableRequest{};
933 varHandler->m_PendingVarRequest = VariableRequest{};
931 auto var = findVariable(itVarHandler->first);
934 auto var = findVariable(itVarHandler->first);
932 executeVarRequest(var, varHandler->m_RunningVarRequest);
935 executeVarRequest(var, varHandler->m_RunningVarRequest);
933 break;
936 break;
934 }
937 }
935 default:
938 default:
936 qCCritical(LOG_VariableController())
939 qCCritical(LOG_VariableController())
937 << QObject::tr("Unknown VariableRequestHandlerState");
940 << QObject::tr("Unknown VariableRequestHandlerState");
938 }
941 }
939 }
942 }
940 }
943 }
941 }
944 }
942
945
943
946
944 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
947 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
945 {
948 {
946 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
949 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
947
950
948 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
951 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
949 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
952 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
950 qCCritical(LOG_VariableController())
953 qCCritical(LOG_VariableController())
951 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
954 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
952 return;
955 return;
953 }
956 }
954
957
955 auto &varIds = varGroupIdToVarIdsIt->second;
958 auto &varIds = varGroupIdToVarIdsIt->second;
956 auto varIdsEnd = varIds.end();
959 auto varIdsEnd = varIds.end();
957 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
960 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
958 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
961 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
959 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
962 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
960
963
961 auto varHandler = itVarHandler->second.get();
964 auto varHandler = itVarHandler->second.get();
962 varHandler->m_VarId = QUuid{};
965 varHandler->m_VarId = QUuid{};
963 switch (varHandler->m_State) {
966 switch (varHandler->m_State) {
964 case VariableRequestHandlerState::OFF: {
967 case VariableRequestHandlerState::OFF: {
965 qCWarning(LOG_VariableController())
968 qCWarning(LOG_VariableController())
966 << QObject::tr("Impossible to cancel a variable with no running request");
969 << QObject::tr("Impossible to cancel a variable with no running request");
967 break;
970 break;
968 }
971 }
969 case VariableRequestHandlerState::RUNNING: {
972 case VariableRequestHandlerState::RUNNING: {
970
973
971 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
974 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
972 auto var = findVariable(itVarHandler->first);
975 auto var = findVariable(itVarHandler->first);
973 auto varProvider = m_VariableToProviderMap.at(var);
976 auto varProvider = m_VariableToProviderMap.at(var);
974 if (varProvider != nullptr) {
977 if (varProvider != nullptr) {
975 m_VariableAcquisitionWorker->abortProgressRequested(
978 m_VariableAcquisitionWorker->abortProgressRequested(
976 itVarHandler->first);
979 itVarHandler->first);
977 }
980 }
978 m_VariableModel->setDataProgress(var, 0.0);
981 m_VariableModel->setDataProgress(var, 0.0);
979 varHandler->m_CanUpdate = false;
982 varHandler->m_CanUpdate = false;
980 varHandler->m_State = VariableRequestHandlerState::OFF;
983 varHandler->m_State = VariableRequestHandlerState::OFF;
981 varHandler->m_RunningVarRequest = VariableRequest{};
984 varHandler->m_RunningVarRequest = VariableRequest{};
982 }
985 }
983 else {
986 else {
984 // TODO: log Impossible to cancel the running variable request beacause its
987 // TODO: log Impossible to cancel the running variable request beacause its
985 // varRequestId isn't not the canceled one
988 // varRequestId isn't not the canceled one
986 }
989 }
987 break;
990 break;
988 }
991 }
989 case VariableRequestHandlerState::PENDING: {
992 case VariableRequestHandlerState::PENDING: {
990 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
993 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
991 auto var = findVariable(itVarHandler->first);
994 auto var = findVariable(itVarHandler->first);
992 auto varProvider = m_VariableToProviderMap.at(var);
995 auto varProvider = m_VariableToProviderMap.at(var);
993 if (varProvider != nullptr) {
996 if (varProvider != nullptr) {
994 m_VariableAcquisitionWorker->abortProgressRequested(
997 m_VariableAcquisitionWorker->abortProgressRequested(
995 itVarHandler->first);
998 itVarHandler->first);
996 }
999 }
997 m_VariableModel->setDataProgress(var, 0.0);
1000 m_VariableModel->setDataProgress(var, 0.0);
998 varHandler->m_CanUpdate = false;
1001 varHandler->m_CanUpdate = false;
999 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1002 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1000 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1003 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1001 varHandler->m_PendingVarRequest = VariableRequest{};
1004 varHandler->m_PendingVarRequest = VariableRequest{};
1002 executeVarRequest(var, varHandler->m_RunningVarRequest);
1005 executeVarRequest(var, varHandler->m_RunningVarRequest);
1003 }
1006 }
1004 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1007 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1005 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1008 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1006 varHandler->m_PendingVarRequest = VariableRequest{};
1009 varHandler->m_PendingVarRequest = VariableRequest{};
1007 }
1010 }
1008 else {
1011 else {
1009 // TODO: log Impossible to cancel the variable request beacause its
1012 // TODO: log Impossible to cancel the variable request beacause its
1010 // varRequestId isn't not the canceled one
1013 // varRequestId isn't not the canceled one
1011 }
1014 }
1012 break;
1015 break;
1013 }
1016 }
1014 default:
1017 default:
1015 qCCritical(LOG_VariableController())
1018 qCCritical(LOG_VariableController())
1016 << QObject::tr("Unknown VariableRequestHandlerState");
1019 << QObject::tr("Unknown VariableRequestHandlerState");
1017 }
1020 }
1018 }
1021 }
1019 }
1022 }
1020 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1023 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1021 m_VarGroupIdToVarIds.erase(varRequestId);
1024 m_VarGroupIdToVarIds.erase(varRequestId);
1025 if (m_VarGroupIdToVarIds.empty()) {
1026 emit q->acquisitionFinished();
1027 }
1022 }
1028 }
1023
1029
1024 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1030 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1025 VariableRequest &varRequest)
1031 VariableRequest &varRequest)
1026 {
1032 {
1027 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1033 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1028
1034
1029 auto varId = m_VariableToIdentifierMap.at(var);
1035 auto varId = m_VariableToIdentifierMap.at(var);
1030
1036
1031 auto varCacheRange = var->cacheRange();
1037 auto varCacheRange = var->cacheRange();
1032 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1038 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1033 auto notInCacheRangeList
1039 auto notInCacheRangeList
1034 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1040 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1035 auto inCacheRangeList
1041 auto inCacheRangeList
1036 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1042 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1037
1043
1038 if (!notInCacheRangeList.empty()) {
1044 if (!notInCacheRangeList.empty()) {
1039
1045
1040 auto varProvider = m_VariableToProviderMap.at(var);
1046 auto varProvider = m_VariableToProviderMap.at(var);
1041 if (varProvider != nullptr) {
1047 if (varProvider != nullptr) {
1042 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1048 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1043 << varRequest.m_CacheRangeRequested;
1049 << varRequest.m_CacheRangeRequested;
1044 m_VariableAcquisitionWorker->pushVariableRequest(
1050 m_VariableAcquisitionWorker->pushVariableRequest(
1045 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1051 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1046 varRequest.m_CacheRangeRequested,
1052 varRequest.m_CacheRangeRequested,
1047 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1053 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1048 varProvider);
1054 varProvider);
1049 }
1055 }
1050 else {
1056 else {
1051 qCCritical(LOG_VariableController())
1057 qCCritical(LOG_VariableController())
1052 << "Impossible to provide data with a null provider";
1058 << "Impossible to provide data with a null provider";
1053 }
1059 }
1054
1060
1055 if (!inCacheRangeList.empty()) {
1061 if (!inCacheRangeList.empty()) {
1056 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1062 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1057 }
1063 }
1058 }
1064 }
1059 else {
1065 else {
1060 acceptVariableRequest(varId,
1066 acceptVariableRequest(varId,
1061 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1067 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1062 }
1068 }
1063 }
1069 }
@@ -1,87 +1,89
1
1
2 amdaplugin_moc_headers = [
2 amdaplugin_moc_headers = [
3 'include/AmdaPlugin.h',
3 'include/AmdaPlugin.h',
4 'include/AmdaProvider.h'
4 'include/AmdaProvider.h'
5 ]
5 ]
6
6
7 amdaplugin_sources = [
7 amdaplugin_sources = [
8 'src/AmdaDefs.cpp',
8 'src/AmdaDefs.cpp',
9 'src/AmdaParser.cpp',
9 'src/AmdaParser.cpp',
10 'src/AmdaPlugin.cpp',
10 'src/AmdaPlugin.cpp',
11 'src/AmdaProvider.cpp',
11 'src/AmdaProvider.cpp',
12 'src/AmdaResultParser.cpp',
12 'src/AmdaResultParser.cpp',
13 'src/AmdaResultParserDefs.cpp',
13 'src/AmdaResultParserDefs.cpp',
14 'src/AmdaResultParserHelper.cpp',
14 'src/AmdaResultParserHelper.cpp',
15 'src/AmdaServer.cpp'
15 'src/AmdaServer.cpp'
16 ]
16 ]
17
17
18 amdaplugin_ui_files = []
18 amdaplugin_ui_files = []
19 amdaplugin_resources_files = [
19 amdaplugin_resources_files = [
20 'resources/amdaresources.qrc'
20 'resources/amdaresources.qrc'
21 ]
21 ]
22
22
23 amdaplugin_inc = include_directories(['include', '../../plugin/include'])
23 amdaplugin_inc = include_directories(['include', '../../plugin/include'])
24
24
25 moc_gen = generator(moc,
25 moc_gen = generator(moc,
26 output : 'moc_@BASENAME@.cpp',
26 output : 'moc_@BASENAME@.cpp',
27 arguments : ['@INPUT@',
27 arguments : ['@INPUT@',
28 '-DSCIQLOP_PLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/amda/resources/amda.json"',
28 '-DSCIQLOP_PLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/amda/resources/amda.json"',
29 '-I', meson.current_source_dir()+'/include',
29 '-I', meson.current_source_dir()+'/include',
30 '-I', meson.current_source_dir()+'/../../plugin/include',
30 '-I', meson.current_source_dir()+'/../../plugin/include',
31 '-o', '@OUTPUT@'])
31 '-o', '@OUTPUT@'])
32
32
33 rcc_gen = generator(rcc,
33 rcc_gen = generator(rcc,
34 output : 'qrc_@BASENAME@.cpp',
34 output : 'qrc_@BASENAME@.cpp',
35 arguments : ['--name=@BASENAME@"',
35 arguments : ['--name=@BASENAME@"',
36 '--output',
36 '--output',
37 '@OUTPUT@',
37 '@OUTPUT@',
38 '@INPUT@'])
38 '@INPUT@'])
39
39
40 amdaplugin_moc_plugin_files = moc_gen.process(amdaplugin_moc_headers)
40 amdaplugin_moc_plugin_files = moc_gen.process(amdaplugin_moc_headers)
41
41
42 amdaplugin_rcc_plugin_files = rcc_gen.process(amdaplugin_resources_files)
42 amdaplugin_rcc_plugin_files = rcc_gen.process(amdaplugin_resources_files)
43
43
44 #amdaplugin_rcc_plugin_files = qt5.preprocess(
44 #amdaplugin_rcc_plugin_files = qt5.preprocess(
45 # qresources : amdaplugin_resources_files)
45 # qresources : amdaplugin_resources_files)
46
46
47 amdaplugin_moc_files = qt5.preprocess(
47 amdaplugin_moc_files = qt5.preprocess(
48 ui_files : amdaplugin_ui_files)
48 ui_files : amdaplugin_ui_files)
49
49
50 sciqlop_amdaplugin = library('amdaplugin',
50 sciqlop_amdaplugin = library('amdaplugin',
51 amdaplugin_sources,
51 amdaplugin_sources,
52 amdaplugin_moc_files,
52 amdaplugin_moc_files,
53 amdaplugin_rcc_plugin_files,
53 amdaplugin_rcc_plugin_files,
54 amdaplugin_moc_plugin_files,
54 amdaplugin_moc_plugin_files,
55 cpp_args : ['-DAMDA_LIB','-DQT_PLUGIN'],
55 cpp_args : ['-DAMDA_LIB','-DQT_PLUGIN'],
56 include_directories : [amdaplugin_inc],
56 include_directories : [amdaplugin_inc],
57 dependencies : [sciqlop_core, sciqlop_gui],
57 dependencies : [sciqlop_core, sciqlop_gui],
58 install : true
58 install : true
59 )
59 )
60
60
61
61
62 tests = [
62 tests = [
63 [['tests/TestAmdaParser.cpp'],'test_amda_parser','AMDA parser test'],
63 [['tests/TestAmdaParser.cpp'],'test_amda_parser','AMDA parser test'],
64 [['tests/TestAmdaResultParser.cpp'],'test_amda_result_parser','AMDA result parser test'],
64 [['tests/TestAmdaResultParser.cpp'],'test_amda_result_parser','AMDA result parser test'],
65 [['tests/TestAmdaAcquisition.cpp'],'test_amda_acquisition','AMDA Acquisition test'],
65 [['tests/TestAmdaAcquisition.cpp'],'test_amda_acquisition','AMDA Acquisition test'],
66 [['tests/TestAmdaFuzzing.cpp'],'test_amda_fuzzing','AMDA fuzzing test']
66 [['tests/TestAmdaFuzzing.cpp'],'test_amda_fuzzing','AMDA fuzzing test']
67 ]
67 ]
68
68
69 tests_sources = [
69 tests_sources = [
70 'tests/FuzzingDefs.h',
70 'tests/FuzzingDefs.h',
71 'tests/FuzzingDefs.cpp',
71 'tests/FuzzingDefs.cpp',
72 'tests/FuzzingOperations.h',
72 'tests/FuzzingOperations.h',
73 'tests/FuzzingOperations.cpp',
73 'tests/FuzzingOperations.cpp',
74 'tests/FuzzingUtils.h',
74 'tests/FuzzingUtils.h',
75 'tests/FuzzingUtils.cpp'
75 'tests/FuzzingUtils.cpp',
76 'tests/FuzzingValidators.h',
77 'tests/FuzzingValidators.cpp'
76 ]
78 ]
77
79
78 foreach unit_test : tests
80 foreach unit_test : tests
79 test_moc_files = qt5.preprocess(moc_sources : unit_test[0])
81 test_moc_files = qt5.preprocess(moc_sources : unit_test[0])
80 test_exe = executable(unit_test[1],unit_test[0] , test_moc_files,
82 test_exe = executable(unit_test[1],unit_test[0] , test_moc_files,
81 link_with : [sciqlop_amdaplugin],
83 link_with : [sciqlop_amdaplugin],
82 include_directories : [amdaplugin_inc],
84 include_directories : [amdaplugin_inc],
83 cpp_args : ['-DAMDA_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/tests-resources"'],
85 cpp_args : ['-DAMDA_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/tests-resources"'],
84 sources : [tests_sources],
86 sources : [tests_sources],
85 dependencies : [sciqlop_core, sciqlop_gui, qt5test])
87 dependencies : [sciqlop_core, sciqlop_gui, qt5test])
86 test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])], timeout: 3 * 60)
88 test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])], timeout: 3 * 60)
87 endforeach
89 endforeach
@@ -1,8 +1,109
1 #include "FuzzingDefs.h"
1 #include "FuzzingDefs.h"
2
2
3 const QString ACQUISITION_TIMEOUT_PROPERTY = QStringLiteral("acquisitionTimeout");
3 const QString NB_MAX_OPERATIONS_PROPERTY = QStringLiteral("component");
4 const QString NB_MAX_OPERATIONS_PROPERTY = QStringLiteral("component");
5 const QString NB_MAX_SYNC_GROUPS_PROPERTY = QStringLiteral("nbSyncGroups");
4 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
6 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
5 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
7 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
8 const QString CACHE_TOLERANCE_PROPERTY = QStringLiteral("cacheTolerance");
9 const QString INITIAL_RANGE_PROPERTY = QStringLiteral("initialRange");
6 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
10 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
7 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
11 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
8 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
12 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
13 const QString OPERATION_DELAY_BOUNDS_PROPERTY = QStringLiteral("operationDelays");
14 const QString VALIDATORS_PROPERTY = QStringLiteral("validators");
15 const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY = QStringLiteral("validationFrequencyBounds");
16
17 // //////////// //
18 // FuzzingState //
19 // //////////// //
20
21 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
22 {
23 return m_SyncGroupsPool.at(id);
24 }
25
26 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
27 {
28 return m_SyncGroupsPool.at(id);
29 }
30
31 const VariableState &FuzzingState::variableState(VariableId id) const
32 {
33 return m_VariablesPool.at(id);
34 }
35
36 VariableState &FuzzingState::variableState(VariableId id)
37 {
38 return m_VariablesPool.at(id);
39 }
40
41 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
42 {
43 auto end = m_SyncGroupsPool.cend();
44 auto it
45 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
46 const auto &syncGroup = syncGroupEntry.second;
47 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
48 });
49
50 return it != end ? it->first : SyncGroupId{};
51 }
52
53 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
54 {
55 std::vector<SyncGroupId> result{};
56
57 for (const auto &entry : m_SyncGroupsPool) {
58 result.push_back(entry.first);
59 }
60
61 return result;
62 }
63
64 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
65 {
66 if (syncGroupId.isNull()) {
67 return;
68 }
69
70 // Registers variable into sync group: if it's the first variable, sets the variable range as
71 // the sync group range
72 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
73 syncGroup.m_Variables.insert(variableId);
74 if (syncGroup.m_Variables.size() == 1) {
75 auto &variableState = m_VariablesPool.at(variableId);
76 syncGroup.m_Range = variableState.m_Range;
77 }
78 }
79
80 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
81 {
82 if (syncGroupId.isNull()) {
83 return;
84 }
85
86 // Unregisters variable from sync group: if there is no more variable in the group, resets the
87 // range
88 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
89 syncGroup.m_Variables.erase(variableId);
90 if (syncGroup.m_Variables.empty()) {
91 syncGroup.m_Range = INVALID_RANGE;
92 }
93 }
94
95 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
96 {
97 auto syncGroupId = this->syncGroupId(variableId);
98
99 // Retrieves the variables to update:
100 // - if the variable is synchronized to others, updates all synchronized variables
101 // - otherwise, updates only the variable
102 auto variablesToUpdate = syncGroupId.isNull() ? std::set<VariableId>{variableId}
103 : m_SyncGroupsPool.at(syncGroupId).m_Variables;
104
105 // Sets new range
106 for (const auto &variableId : variablesToUpdate) {
107 m_VariablesPool.at(variableId).m_Range = newRange;
108 }
109 }
@@ -1,38 +1,128
1 #ifndef SCIQLOP_FUZZINGDEFS_H
1 #ifndef SCIQLOP_FUZZINGDEFS_H
2 #define SCIQLOP_FUZZINGDEFS_H
2 #define SCIQLOP_FUZZINGDEFS_H
3
3
4 #include <Data/SqpRange.h>
5
4 #include <QString>
6 #include <QString>
7 #include <QUuid>
5 #include <QVariantHash>
8 #include <QVariantHash>
6
9
10 #include <memory>
11 #include <set>
12
7 // /////// //
13 // /////// //
8 // Aliases //
14 // Aliases //
9 // /////// //
15 // /////// //
10
16
11 using MetadataPool = std::vector<QVariantHash>;
17 using MetadataPool = std::vector<QVariantHash>;
12 Q_DECLARE_METATYPE(MetadataPool)
18 Q_DECLARE_METATYPE(MetadataPool)
13
19
14 using Properties = QVariantHash;
20 using Properties = QVariantHash;
15
21
16 // ///////// //
22 // ///////// //
17 // Constants //
23 // Constants //
18 // ///////// //
24 // ///////// //
19
25
26 /// Timeout set for data acquisition for an operation (in ms)
27 extern const QString ACQUISITION_TIMEOUT_PROPERTY;
28
20 /// Max number of operations to generate
29 /// Max number of operations to generate
21 extern const QString NB_MAX_OPERATIONS_PROPERTY;
30 extern const QString NB_MAX_OPERATIONS_PROPERTY;
22
31
32 /// Max number of sync groups to create through operations
33 extern const QString NB_MAX_SYNC_GROUPS_PROPERTY;
34
23 /// Max number of variables to manipulate through operations
35 /// Max number of variables to manipulate through operations
24 extern const QString NB_MAX_VARIABLES_PROPERTY;
36 extern const QString NB_MAX_VARIABLES_PROPERTY;
25
37
26 /// Set of operations available for the test
38 /// Set of operations available for the test
27 extern const QString AVAILABLE_OPERATIONS_PROPERTY;
39 extern const QString AVAILABLE_OPERATIONS_PROPERTY;
28
40
41 /// Tolerance used for variable's cache (in ratio)
42 extern const QString CACHE_TOLERANCE_PROPERTY;
43
44 /// Range with which the timecontroller is initialized
45 extern const QString INITIAL_RANGE_PROPERTY;
46
29 /// Max range that an operation can reach
47 /// Max range that an operation can reach
30 extern const QString MAX_RANGE_PROPERTY;
48 extern const QString MAX_RANGE_PROPERTY;
31
49
32 /// Set of metadata that can be associated to a variable
50 /// Set of metadata that can be associated to a variable
33 extern const QString METADATA_POOL_PROPERTY;
51 extern const QString METADATA_POOL_PROPERTY;
34
52
35 /// Provider used to retrieve data
53 /// Provider used to retrieve data
36 extern const QString PROVIDER_PROPERTY;
54 extern const QString PROVIDER_PROPERTY;
37
55
56 /// Min/max times left for an operation to execute
57 extern const QString OPERATION_DELAY_BOUNDS_PROPERTY;
58
59 /// Validators used to validate an operation
60 extern const QString VALIDATORS_PROPERTY;
61
62 /// Min/max number of operations to execute before calling validation of the current test's state
63 extern const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY;
64
65 // /////// //
66 // Structs //
67 // /////// //
68
69 class Variable;
70 struct VariableState {
71 std::shared_ptr<Variable> m_Variable{nullptr};
72 SqpRange m_Range{INVALID_RANGE};
73 };
74
75 using VariableId = int;
76 using VariablesPool = std::map<VariableId, VariableState>;
77
78 /**
79 * Defines a synchronization group for a fuzzing state. A group reports the variables synchronized
80 * with each other, and the current range of the group (i.e. range of the last synchronized variable
81 * that has been moved)
82 */
83 struct SyncGroup {
84 std::set<VariableId> m_Variables{};
85 SqpRange m_Range{INVALID_RANGE};
86 };
87
88 using SyncGroupId = QUuid;
89 using SyncGroupsPool = std::map<SyncGroupId, SyncGroup>;
90
91 /**
92 * Defines a current state during a fuzzing state. It contains all the variables manipulated during
93 * the test, as well as the synchronization status of these variables.
94 */
95 struct FuzzingState {
96 const SyncGroup &syncGroup(SyncGroupId id) const;
97 SyncGroup &syncGroup(SyncGroupId id);
98
99 const VariableState &variableState(VariableId id) const;
100 VariableState &variableState(VariableId id);
101
102 /// @return the identifier of the synchronization group in which the variable passed in
103 /// parameter is located. If the variable is not in any group, returns an invalid identifier
104 SyncGroupId syncGroupId(VariableId variableId) const;
105
106 /// @return the set of synchronization group identifiers
107 std::vector<SyncGroupId> syncGroupsIds() const;
108
109 /// Updates fuzzing state according to a variable synchronization
110 /// @param variableId the variable that is synchronized
111 /// @param syncGroupId the synchronization group
112 void synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
113
114 /// Updates fuzzing state according to a variable desynchronization
115 /// @param variableId the variable that is desynchronized
116 /// @param syncGroupId the synchronization group from which to remove the variable
117 void desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
118
119 /// Updates the range of a variable and all variables to which it is synchronized
120 /// @param the variable for which to affect the range
121 /// @param the range to affect
122 void updateRanges(VariableId variableId, const SqpRange &newRange);
123
124 VariablesPool m_VariablesPool;
125 SyncGroupsPool m_SyncGroupsPool;
126 };
127
38 #endif // SCIQLOP_FUZZINGDEFS_H
128 #endif // SCIQLOP_FUZZINGDEFS_H
@@ -1,74 +1,265
1 #include "FuzzingOperations.h"
1 #include "FuzzingOperations.h"
2 #include "FuzzingUtils.h"
2 #include "FuzzingUtils.h"
3
3
4 #include <Data/IDataProvider.h>
4 #include <Data/IDataProvider.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7 #include <Variable/VariableController.h>
7 #include <Variable/VariableController.h>
8
8
9 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <functional>
12
11 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
12
14
13 namespace {
15 namespace {
14
16
15 struct CreateOperation : public IFuzzingOperation {
17 struct CreateOperation : public IFuzzingOperation {
16 bool canExecute(std::shared_ptr<Variable> variable) const override
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
17 {
19 {
18 // A variable can be created only if it doesn't exist yet
20 // A variable can be created only if it doesn't exist yet
19 return variable == nullptr;
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
20 }
22 }
21
23
22 void execute(std::shared_ptr<Variable> &variable, VariableController &variableController,
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
25 VariableController &variableController,
23 const Properties &properties) const override
26 const Properties &properties) const override
24 {
27 {
25 // Retrieves metadata pool from properties, and choose one of the metadata entries to
28 // Retrieves metadata pool from properties, and choose one of the metadata entries to
26 // associate it with the variable
29 // associate it with the variable
27 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
28 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
29
32
30 // Retrieves provider
33 // Retrieves provider
31 auto variableProvider
34 auto variableProvider
32 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
33
36
34 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
35 qCInfo(LOG_FuzzingOperations())
38 qCInfo(LOG_FuzzingOperations()).noquote()
36 << "Creating variable" << variableName << "(metadata:" << variableMetadata << ")";
39 << "Creating variable" << variableName << "(metadata:" << variableMetadata << ")...";
37
40
38 auto newVariable
41 auto newVariable
39 = variableController.createVariable(variableName, variableMetadata, variableProvider);
42 = variableController.createVariable(variableName, variableMetadata, variableProvider);
40 std::swap(variable, newVariable);
43
44 // Updates variable's state
45 auto &variableState = fuzzingState.variableState(variableId);
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>();
47 std::swap(variableState.m_Variable, newVariable);
41 }
48 }
42 };
49 };
43
50
44 struct UnknownOperation : public IFuzzingOperation {
51 struct DeleteOperation : public IFuzzingOperation {
45 bool canExecute(std::shared_ptr<Variable> variable) const override
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
46 {
53 {
47 Q_UNUSED(variable);
54 // A variable can be delete only if it exists
48 return false;
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
49 }
56 }
50
57
51 void execute(std::shared_ptr<Variable> &variable, VariableController &variableController,
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
59 VariableController &variableController, const Properties &) const override
60 {
61 auto &variableState = fuzzingState.variableState(variableId);
62
63 qCInfo(LOG_FuzzingOperations()).noquote()
64 << "Deleting variable" << variableState.m_Variable->name() << "...";
65 variableController.deleteVariable(variableState.m_Variable);
66
67 // Updates variable's state
68 variableState.m_Range = INVALID_RANGE;
69 variableState.m_Variable = nullptr;
70
71 // Desynchronizes the variable if it was in a sync group
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
74 }
75 };
76
77 /**
78 * Defines a move operation through a range.
79 *
80 * A move operation is determined by three functions:
81 * - Two 'move' functions, used to indicate in which direction the beginning and the end of a range
82 * are going during the operation. These functions will be:
83 * -- {<- / <-} for pan left
84 * -- {-> / ->} for pan right
85 * -- {-> / <-} for zoom in
86 * -- {<- / ->} for zoom out
87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
88 * range, according to a max range. For exemple, for a range of {1, 5} and a max range of {0, 10},
89 * max deltas will be:
90 * -- {0, 4} for pan left
91 * -- {6, 10} for pan right
92 * -- {3, 3} for zoom in
93 * -- {0, 6} for zoom out (same spacing left and right)
94 */
95 struct MoveOperation : public IFuzzingOperation {
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
97 using MaxMoveFunction = std::function<double(const SqpRange &range, const SqpRange &maxRange)>;
98
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
100 MaxMoveFunction maxMoveFun,
101 const QString &label = QStringLiteral("Move operation"))
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
105 m_Label{label}
106 {
107 }
108
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
110 {
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
112 }
113
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
115 VariableController &variableController,
52 const Properties &properties) const override
116 const Properties &properties) const override
53 {
117 {
54 Q_UNUSED(variable);
118 auto &variableState = fuzzingState.variableState(variableId);
55 Q_UNUSED(variableController);
119 auto variable = variableState.m_Variable;
56 Q_UNUSED(properties);
120
57 // Does nothing
121 // Gets the max range defined
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
123 .value<SqpRange>();
124 auto variableRange = variableState.m_Range;
125
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
129 return;
130 }
131
132 // Computes the max delta at which the variable can move, up to the limits of the max range
133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
134
135 // Generates random delta that will be used to move variable
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
137
138 // Moves variable to its new range
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
140 auto newVariableRange = SqpRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
142 qCInfo(LOG_FuzzingOperations()).noquote()
143 << "Performing" << m_Label << "on" << variable->name() << "(from" << variableRange
144 << "to" << newVariableRange << ")...";
145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
146
147 // Updates state
148 fuzzingState.updateRanges(variableId, newVariableRange);
149 }
150
151 MoveFunction m_RangeStartMoveFun;
152 MoveFunction m_RangeEndMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
154 QString m_Label;
155 };
156
157 struct SynchronizeOperation : public IFuzzingOperation {
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
159 {
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
162 && fuzzingState.syncGroupId(variableId).isNull();
163 }
164
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
166 VariableController &variableController, const Properties &) const override
167 {
168 auto &variableState = fuzzingState.variableState(variableId);
169
170 // Chooses a random synchronization group and adds the variable into sync group
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
172 qCInfo(LOG_FuzzingOperations()).noquote()
173 << "Adding" << variableState.m_Variable->name() << "into synchronization group"
174 << syncGroupId << "...";
175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
176
177 // Updates state
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
179 }
180 };
181
182 struct DesynchronizeOperation : public IFuzzingOperation {
183 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
184 {
185 auto variable = fuzzingState.variableState(variableId).m_Variable;
186 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
187 }
188
189 void execute(VariableId variableId, FuzzingState &fuzzingState,
190 VariableController &variableController, const Properties &) const override
191 {
192 auto &variableState = fuzzingState.variableState(variableId);
193
194 // Gets the sync group of the variable
195 auto syncGroupId = fuzzingState.syncGroupId(variableId);
196
197 qCInfo(LOG_FuzzingOperations()).noquote()
198 << "Removing" << variableState.m_Variable->name() << "from synchronization group"
199 << syncGroupId << "...";
200 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
201
202 // Updates state
203 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
204 }
205 };
206
207 struct UnknownOperation : public IFuzzingOperation {
208 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
209
210 void execute(VariableId, FuzzingState &, VariableController &,
211 const Properties &) const override
212 {
58 }
213 }
59 };
214 };
60
215
61 } // namespace
216 } // namespace
62
217
63 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
218 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
64 {
219 {
65 switch (type) {
220 switch (type) {
66 case FuzzingOperationType::CREATE:
221 case FuzzingOperationType::CREATE:
67 return std::make_unique<CreateOperation>();
222 return std::make_unique<CreateOperation>();
223 case FuzzingOperationType::DELETE:
224 return std::make_unique<DeleteOperation>();
225 case FuzzingOperationType::PAN_LEFT:
226 return std::make_unique<MoveOperation>(
227 std::minus<double>(), std::minus<double>(),
228 [](const SqpRange &range, const SqpRange &maxRange) {
229 return range.m_TStart - maxRange.m_TStart;
230 },
231 QStringLiteral("Pan left operation"));
232 case FuzzingOperationType::PAN_RIGHT:
233 return std::make_unique<MoveOperation>(
234 std::plus<double>(), std::plus<double>(),
235 [](const SqpRange &range, const SqpRange &maxRange) {
236 return maxRange.m_TEnd - range.m_TEnd;
237 },
238 QStringLiteral("Pan right operation"));
239 case FuzzingOperationType::ZOOM_IN:
240 return std::make_unique<MoveOperation>(
241 std::plus<double>(), std::minus<double>(),
242 [](const SqpRange &range, const SqpRange &maxRange) {
243 Q_UNUSED(maxRange)
244 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
245 },
246 QStringLiteral("Zoom in operation"));
247 case FuzzingOperationType::ZOOM_OUT:
248 return std::make_unique<MoveOperation>(
249 std::minus<double>(), std::plus<double>(),
250 [](const SqpRange &range, const SqpRange &maxRange) {
251 return std::min(range.m_TStart - maxRange.m_TStart,
252 maxRange.m_TEnd - range.m_TEnd);
253 },
254 QStringLiteral("Zoom out operation"));
255 case FuzzingOperationType::SYNCHRONIZE:
256 return std::make_unique<SynchronizeOperation>();
257 case FuzzingOperationType::DESYNCHRONIZE:
258 return std::make_unique<DesynchronizeOperation>();
68 default:
259 default:
69 // Default case returns unknown operation
260 // Default case returns unknown operation
70 break;
261 break;
71 }
262 }
72
263
73 return std::make_unique<UnknownOperation>();
264 return std::make_unique<UnknownOperation>();
74 }
265 }
@@ -1,49 +1,56
1 #ifndef SCIQLOP_FUZZINGOPERATIONS_H
1 #ifndef SCIQLOP_FUZZINGOPERATIONS_H
2 #define SCIQLOP_FUZZINGOPERATIONS_H
2 #define SCIQLOP_FUZZINGOPERATIONS_H
3
3
4 #include "FuzzingDefs.h"
4 #include "FuzzingDefs.h"
5
5
6 #include <memory>
6 #include <memory>
7 #include <set>
7 #include <set>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QMetaType>
10 #include <QMetaType>
11
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_FuzzingOperations)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_FuzzingOperations)
13
13
14 class Variable;
15 class VariableController;
14 class VariableController;
16
15
17 /**
16 /**
18 * Enumeration of types of existing fuzzing operations
17 * Enumeration of types of existing fuzzing operations
19 */
18 */
20 enum class FuzzingOperationType { CREATE };
19 enum class FuzzingOperationType {
20 CREATE,
21 DELETE,
22 PAN_LEFT,
23 PAN_RIGHT,
24 ZOOM_IN,
25 ZOOM_OUT,
26 SYNCHRONIZE,
27 DESYNCHRONIZE
28 };
21
29
22 /// Interface that represents an operation that can be executed during a fuzzing test
30 /// Interface that represents an operation that can be executed during a fuzzing test
23 struct IFuzzingOperation {
31 struct IFuzzingOperation {
24 virtual ~IFuzzingOperation() noexcept = default;
32 virtual ~IFuzzingOperation() noexcept = default;
25
33
26 /// Checks if the operation can be executed according to the current state of the variable
34 /// Checks if the operation can be executed according to the current test's state for the
27 /// passed in parameter
35 /// variable passed in parameter
28 virtual bool canExecute(std::shared_ptr<Variable> variable) const = 0;
36 virtual bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const = 0;
29 /// Executes the operation on the variable passed in parameter
37 /// Executes the operation on the variable for which its identifier is passed in parameter
30 /// @param variable the variable on which to execute the operation
38 /// @param variableId the variable identifier
39 /// @param fuzzingState the current test's state on which to find the variable and execute the
40 /// operation
31 /// @param variableController the controller associated to the operation
41 /// @param variableController the controller associated to the operation
32 /// @param properties properties that can be used to configure the operation
42 /// @param properties properties that can be used to configure the operation
33 /// @remarks variable is passed as a reference because, according to the operation, it can be
43 /// @remarks fuzzingState is passed as a reference because, according to the operation, it can
34 /// modified (in/out parameter)
44 /// be modified (in/out parameter)
35 virtual void execute(std::shared_ptr<Variable> &variable,
45 virtual void execute(VariableId variableId, FuzzingState &fuzzingState,
36 VariableController &variableController,
46 VariableController &variableController,
37 const Properties &properties = {}) const = 0;
47 const Properties &properties = {}) const = 0;
38 };
48 };
39
49
40 /// Factory of @sa IFuzzingOperation
50 /// Factory of @sa IFuzzingOperation
41 struct FuzzingOperationFactory {
51 struct FuzzingOperationFactory {
42 /// Creates a fuzzing operation from a type
52 /// Creates a fuzzing operation from a type
43 static std::unique_ptr<IFuzzingOperation> create(FuzzingOperationType type);
53 static std::unique_ptr<IFuzzingOperation> create(FuzzingOperationType type);
44 };
54 };
45
55
46 using OperationsTypes = std::set<FuzzingOperationType>;
47 Q_DECLARE_METATYPE(OperationsTypes)
48
49 #endif // SCIQLOP_FUZZINGOPERATIONS_H
56 #endif // SCIQLOP_FUZZINGOPERATIONS_H
@@ -1,41 +1,63
1 #ifndef SCIQLOP_FUZZINGUTILS_H
1 #ifndef SCIQLOP_FUZZINGUTILS_H
2 #define SCIQLOP_FUZZINGUTILS_H
2 #define SCIQLOP_FUZZINGUTILS_H
3
3
4 #include <algorithm>
4 #include <random>
5 #include <random>
5
6
6 /**
7 /**
7 * Class that proposes random utility methods
8 * Class that proposes random utility methods
8 */
9 */
9 class RandomGenerator {
10 class RandomGenerator {
10 public:
11 public:
11 /// @return the unique instance of the random generator
12 /// @return the unique instance of the random generator
12 static RandomGenerator &instance();
13 static RandomGenerator &instance();
13
14
14 /// Generates a random double between [min, max]
15 /// Generates a random double between [min, max]
15 double generateDouble(double min, double max);
16 double generateDouble(double min, double max);
16 /// Generates a random int between [min, max]
17 /// Generates a random int between [min, max]
17 int generateInt(int min, int max);
18 int generateInt(int min, int max);
18
19
19 /// Returns a random element among the elements of a container. If the container is empty,
20 /**
20 /// returns an element built by default
21 * Returns a random element among the elements of a container. An item may be more likely to be
22 * selected if it has an associated weight greater than other items
23 * @param container the container from which to retrieve an element
24 * @param weights the weight associated to each element of the container. The vector must have
25 * the same size of the container for the weights to be effective
26 * @param nbDraws the number of random draws to perform
27 * @return the random element retrieved, an element built by default if the container is empty
28 */
21 template <typename T, typename ValueType = typename T::value_type>
29 template <typename T, typename ValueType = typename T::value_type>
22 ValueType randomChoice(const T &container);
30 ValueType randomChoice(const T &container, const std::vector<double> &weights = {});
23
31
24 private:
32 private:
25 std::mt19937 m_Mt;
33 std::mt19937 m_Mt;
26
34
27 explicit RandomGenerator();
35 explicit RandomGenerator();
28 };
36 };
29
37
30 template <typename T, typename ValueType>
38 template <typename T, typename ValueType>
31 ValueType RandomGenerator::randomChoice(const T &container)
39 ValueType RandomGenerator::randomChoice(const T &container, const std::vector<double> &weights)
32 {
40 {
33 if (container.empty()) {
41 if (container.empty()) {
34 return ValueType{};
42 return ValueType{};
35 }
43 }
36
44
37 auto randomIndex = generateInt(0, container.size() - 1);
45 // Generates weights for each element: if the weights passed in parameter are malformed (the
38 return container.at(randomIndex);
46 // number of weights defined is inconsistent with the number of elements in the container, or
47 // all weights are zero), default weights are used
48 auto nbIndexes = container.size();
49 std::vector<double> indexWeights(nbIndexes);
50 if (weights.size() != nbIndexes || std::all_of(weights.cbegin(), weights.cend(),
51 [](const auto &val) { return val == 0.; })) {
52 std::fill(indexWeights.begin(), indexWeights.end(), 1.);
53 }
54 else {
55 std::copy(weights.begin(), weights.end(), indexWeights.begin());
56 }
57
58 // Performs a draw to determine the index to return
59 std::discrete_distribution<> d{indexWeights.cbegin(), indexWeights.cend()};
60 return container.at(d(m_Mt));
39 }
61 }
40
62
41 #endif // SCIQLOP_FUZZINGUTILS
63 #endif // SCIQLOP_FUZZINGUTILS
@@ -1,241 +1,391
1 #include "FuzzingDefs.h"
1 #include "FuzzingDefs.h"
2 #include "FuzzingOperations.h"
2 #include "FuzzingOperations.h"
3 #include "FuzzingUtils.h"
3 #include "FuzzingUtils.h"
4 #include "FuzzingValidators.h"
4
5
5 #include "AmdaProvider.h"
6 #include "AmdaProvider.h"
6
7
8 #include <Common/SignalWaiter.h>
7 #include <Network/NetworkController.h>
9 #include <Network/NetworkController.h>
10 #include <Settings/SqpSettingsDefs.h>
8 #include <SqpApplication.h>
11 #include <SqpApplication.h>
9 #include <Time/TimeController.h>
12 #include <Time/TimeController.h>
13 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
14 #include <Variable/VariableController.h>
11
15
12 #include <QLoggingCategory>
16 #include <QLoggingCategory>
13 #include <QObject>
17 #include <QObject>
14 #include <QtTest>
18 #include <QtTest>
15
19
16 #include <memory>
20 #include <memory>
17
21
18 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
19
23
24 /**
25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
26 * attribute that is initialized by searching in properties the property and use a default value if
27 * it's not present. Macro arguments are:
28 * - GETTER_NAME : name of the getter
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
31 * - TYPE : return type of the getter
32 */
33 // clang-format off
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
35 TYPE GETTER_NAME() const \
36 { \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
38 return result; \
39 } \
40 // clang-format on
41
20 namespace {
42 namespace {
21
43
22 // /////// //
44 // /////// //
23 // Aliases //
45 // Aliases //
24 // /////// //
46 // /////// //
25
47
26 using VariableId = int;
48 using IntPair = std::pair<int, int>;
49 using Weight = double;
50 using Weights = std::vector<Weight>;
51
52 struct OperationProperty {
53 Weight m_Weight{1.};
54 bool m_WaitAcquisition{false};
55 };
27
56
28 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
29 using VariablesOperations = std::vector<VariableOperation>;
58 using VariablesOperations = std::vector<VariableOperation>;
30
59
31 using OperationsPool = std::set<std::shared_ptr<IFuzzingOperation> >;
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
32 using VariablesPool = std::map<VariableId, std::shared_ptr<Variable> >;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
62
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
33
64
34 // ///////// //
65 // ///////// //
35 // Constants //
66 // Constants //
36 // ///////// //
67 // ///////// //
37
68
38 // Defaults values used when the associated properties have not been set for the test
69 // Defaults values used when the associated properties have not been set for the test
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
39 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
40 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
41 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
42 = QVariant::fromValue(OperationsTypes{FuzzingOperationType::CREATE});
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
77 {FuzzingOperationType::PAN_LEFT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
84
85 /// Min/max delays between each operation (in ms)
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
87
88 /// Validators for the tests (executed in the order in which they're defined)
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
91
92 /// Min/max number of operations to execute before calling validation
93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
43
94
44 // /////// //
95 // /////// //
45 // Methods //
96 // Methods //
46 // /////// //
97 // /////// //
47
98
48 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
99 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
49 /// pairs that are valid (i.e. operation that can be executed on variable)
100 /// pairs that are valid (i.e. operation that can be executed on variable)
50 VariablesOperations availableOperations(const VariablesPool &variablesPool,
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
51 const OperationsPool &operationsPool)
102 const OperationsPool &operationsPool)
52 {
103 {
53 VariablesOperations result{};
104 VariablesOperations result{};
105 Weights weights{};
54
106
55 for (const auto &variablesPoolEntry : variablesPool) {
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
56 auto variableId = variablesPoolEntry.first;
108 auto variableId = variablesPoolEntry.first;
57 auto variable = variablesPoolEntry.second;
58
109
59 for (const auto &operation : operationsPool) {
110 for (const auto &operationsPoolEntry : operationsPool) {
111 auto operation = operationsPoolEntry.first;
112 auto operationProperty = operationsPoolEntry.second;
113
60 // A pair is valid if the current operation can be executed on the current variable
114 // A pair is valid if the current operation can be executed on the current variable
61 if (operation->canExecute(variable)) {
115 if (operation->canExecute(variableId, fuzzingState)) {
62 result.push_back({variableId, operation});
116 result.push_back({variableId, operation});
117 weights.push_back(operationProperty.m_Weight);
63 }
118 }
64 }
119 }
65 }
120 }
66
121
67 return result;
122 return {result, weights};
68 }
123 }
69
124
70 OperationsPool createOperationsPool(const OperationsTypes &types)
125 OperationsPool createOperationsPool(const OperationsTypes &types)
71 {
126 {
72 OperationsPool result{};
127 OperationsPool result{};
73
128
129 std::transform(
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
132 });
133
134 return result;
135 }
136
137 Validators createValidators(const ValidatorsTypes &types)
138 {
139 Validators result{};
140
74 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
75 [](const auto &type) { return FuzzingOperationFactory::create(type); });
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
76
143
77 return result;
144 return result;
78 }
145 }
79
146
80 /**
147 /**
148 * Validates all the variables' states passed in parameter, according to a set of validators
149 * @param variablesPool the variables' states
150 * @param validators the validators used for validation
151 */
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
153 {
154 for (const auto &variablesPoolEntry : variablesPool) {
155 auto variableId = variablesPoolEntry.first;
156 const auto &variableState = variablesPoolEntry.second;
157
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
159 : QStringLiteral("null variable");
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
161 << variableId << "(" << variableMessage << ")...";
162
163 for (const auto &validator : validators) {
164 validator->validate(VariableState{variableState});
165 }
166
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
168 }
169 }
170
171 /**
81 * Class to run random tests
172 * Class to run random tests
82 */
173 */
83 class FuzzingTest {
174 class FuzzingTest {
84 public:
175 public:
85 explicit FuzzingTest(VariableController &variableController, Properties properties)
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
86 : m_VariableController{variableController},
177 : m_VariableController{variableController},
87 m_Properties{std::move(properties)},
178 m_Properties{std::move(properties)},
88 m_VariablesPool{}
179 m_FuzzingState{}
89 {
180 {
90 // Inits variables pool: at init, all variables are null
181 // Inits variables pool: at init, all variables are null
91 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
92 m_VariablesPool[variableId] = nullptr;
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
184 }
185
186 // Inits sync groups and registers them into the variable controller
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
188 auto syncGroupId = SyncGroupId::createUuid();
189 variableController.onAddSynchronizationGroupId(syncGroupId);
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
93 }
191 }
94 }
192 }
95
193
96 void execute()
194 void execute()
97 {
195 {
98 qCInfo(LOG_TestAmdaFuzzing()) << "Running" << nbMaxOperations() << "operations on"
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
99 << nbMaxVariables() << "variable(s)...";
197 << nbMaxVariables() << "variable(s)...";
198
199
200 // Inits the count of the number of operations before the next validation
201 int nextValidationCounter = 0;
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
203 nextValidationCounter = RandomGenerator::instance().generateInt(
204 validationFrequencies().first, validationFrequencies().second);
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
207 };
208 updateValidationCounter();
100
209
101 auto canExecute = true;
210 auto canExecute = true;
102 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
103 // Retrieves all operations that can be executed in the current context
212 // Retrieves all operations that can be executed in the current context
104 auto variableOperations = availableOperations(m_VariablesPool, operationsPool());
213 VariablesOperations variableOperations{};
214 Weights weights{};
215 std::tie(variableOperations, weights)
216 = availableOperations(m_FuzzingState, operationsPool());
105
217
106 canExecute = !variableOperations.empty();
218 canExecute = !variableOperations.empty();
107 if (canExecute) {
219 if (canExecute) {
220 --nextValidationCounter;
221
108 // Of the operations available, chooses a random operation and executes it
222 // Of the operations available, chooses a random operation and executes it
109 auto variableOperation
223 auto variableOperation
110 = RandomGenerator::instance().randomChoice(variableOperations);
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
111
225
112 auto variableId = variableOperation.first;
226 auto variableId = variableOperation.first;
113 auto variable = m_VariablesPool.at(variableId);
114 auto fuzzingOperation = variableOperation.second;
227 auto fuzzingOperation = variableOperation.second;
115
228
116 fuzzingOperation->execute(variable, m_VariableController, m_Properties);
229 auto waitAcquisition = nextValidationCounter == 0
117
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
118 // Updates variable pool with the new state of the variable after operation
231
119 m_VariablesPool[variableId] = variable;
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
233 m_Properties);
234
235 if (waitAcquisition) {
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
238 acquisitionTimeout());
239
240 // Validates variables
241 if (nextValidationCounter == 0) {
242 validate(m_FuzzingState.m_VariablesPool, validators());
243 updateValidationCounter();
244 }
245 }
246 else {
247 // Delays the next operation with a randomly generated time
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
249 operationDelays().second);
250 qCDebug(LOG_TestAmdaFuzzing())
251 << "Waiting " << delay << "ms before the next operation...";
252 QTest::qWait(delay);
253 }
120 }
254 }
121 else {
255 else {
122 qCInfo(LOG_TestAmdaFuzzing())
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
123 << "No more operations are available, the execution of the test will stop...";
257 << "No more operations are available, the execution of the test will stop...";
124 }
258 }
125 }
259 }
126
260
127 qCInfo(LOG_TestAmdaFuzzing()) << "Execution of the test completed.";
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
128 }
262 }
129
263
130 private:
264 private:
131 int nbMaxOperations() const
265 OperationsPool operationsPool() const
132 {
266 {
133 static auto result
267 static auto result = createOperationsPool(
134 = m_Properties.value(NB_MAX_OPERATIONS_PROPERTY, NB_MAX_OPERATIONS_DEFAULT_VALUE)
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
135 .toInt();
269 .value<OperationsTypes>());
136 return result;
270 return result;
137 }
271 }
138
272
139 int nbMaxVariables() const
273 Validators validators() const
140 {
274 {
141 static auto result
275 static auto result
142 = m_Properties.value(NB_MAX_VARIABLES_PROPERTY, NB_MAX_VARIABLES_DEFAULT_VALUE).toInt();
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
277 .value<ValidatorsTypes>());
143 return result;
278 return result;
144 }
279 }
145
280
146 OperationsPool operationsPool() const
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
147 {
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
148 static auto result = createOperationsPool(
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
149 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
150 .value<OperationsTypes>());
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
151 return result;
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
152 }
153
287
154 VariableController &m_VariableController;
288 VariableController &m_VariableController;
155 Properties m_Properties;
289 Properties m_Properties;
156 VariablesPool m_VariablesPool;
290 FuzzingState m_FuzzingState;
157 };
291 };
158
292
159 } // namespace
293 } // namespace
160
294
295 Q_DECLARE_METATYPE(OperationsTypes)
296
161 class TestAmdaFuzzing : public QObject {
297 class TestAmdaFuzzing : public QObject {
162 Q_OBJECT
298 Q_OBJECT
163
299
164 private slots:
300 private slots:
165 /// Input data for @sa testFuzzing()
301 /// Input data for @sa testFuzzing()
166 void testFuzzing_data();
302 void testFuzzing_data();
167 void testFuzzing();
303 void testFuzzing();
168 };
304 };
169
305
170 void TestAmdaFuzzing::testFuzzing_data()
306 void TestAmdaFuzzing::testFuzzing_data()
171 {
307 {
308 // Note: Comment this line to run fuzzing tests
309 QSKIP("Fuzzing tests are disabled by default");
310
172 // ////////////// //
311 // ////////////// //
173 // Test structure //
312 // Test structure //
174 // ////////////// //
313 // ////////////// //
175
314
176 QTest::addColumn<Properties>("properties"); // Properties for random test
315 QTest::addColumn<Properties>("properties"); // Properties for random test
177
316
178 // ////////// //
317 // ////////// //
179 // Test cases //
318 // Test cases //
180 // ////////// //
319 // ////////// //
181
320
182 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
321 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
183 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
184
323
185 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
186 // QVariant
325 // QVariant
187 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
188
327
189 QTest::newRow("fuzzingTest") << Properties{
328 QTest::newRow("fuzzingTest") << Properties{
190 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
191 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
192 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
193 }
332 }
194
333
195 void TestAmdaFuzzing::testFuzzing()
334 void TestAmdaFuzzing::testFuzzing()
196 {
335 {
197 QFETCH(Properties, properties);
336 QFETCH(Properties, properties);
198
337
338 // Sets cache property
339 QSettings settings{};
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
343
199 auto &variableController = sqpApp->variableController();
344 auto &variableController = sqpApp->variableController();
200 auto &timeController = sqpApp->timeController();
345 auto &timeController = sqpApp->timeController();
201
346
202 // Generates random initial range (bounded to max range)
347 // Generates random initial range (bounded to max range)
203 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
204 .value<SqpRange>();
349 .value<SqpRange>();
205
350
206 QVERIFY(maxRange != INVALID_RANGE);
351 QVERIFY(maxRange != INVALID_RANGE);
207
352
208 auto initialRangeStart
353 auto initialRangeStart
209 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
210 auto initialRangeEnd
355 auto initialRangeEnd
211 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
212 if (initialRangeStart > initialRangeEnd) {
357 if (initialRangeStart > initialRangeEnd) {
213 std::swap(initialRangeStart, initialRangeEnd);
358 std::swap(initialRangeStart, initialRangeEnd);
214 }
359 }
215
360
216 // Sets initial range on time controller
361 // Sets initial range on time controller
217 SqpRange initialRange{initialRangeStart, initialRangeEnd};
362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
218 qCInfo(LOG_TestAmdaFuzzing()) << "Setting initial range to" << initialRange << "...";
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
219 timeController.onTimeToUpdate(initialRange);
364 timeController.onTimeToUpdate(initialRange);
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
220
366
221 FuzzingTest test{variableController, properties};
367 FuzzingTest test{variableController, properties};
222 test.execute();
368 test.execute();
223 }
369 }
224
370
225 int main(int argc, char *argv[])
371 int main(int argc, char *argv[])
226 {
372 {
227 QLoggingCategory::setFilterRules(
373 QLoggingCategory::setFilterRules(
228 "*.warning=false\n"
374 "*.warning=false\n"
229 "*.info=false\n"
375 "*.info=false\n"
230 "*.debug=false\n"
376 "*.debug=false\n"
231 "FuzzingOperations.info=true\n"
377 "FuzzingOperations.info=true\n"
378 "FuzzingValidators.info=true\n"
232 "TestAmdaFuzzing.info=true\n");
379 "TestAmdaFuzzing.info=true\n");
233
380
234 SqpApplication app{argc, argv};
381 SqpApplication app{argc, argv};
382 SqpApplication::setOrganizationName("LPP");
383 SqpApplication::setOrganizationDomain("lpp.fr");
384 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
235 app.setAttribute(Qt::AA_Use96Dpi, true);
385 app.setAttribute(Qt::AA_Use96Dpi, true);
236 TestAmdaFuzzing testObject{};
386 TestAmdaFuzzing testObject{};
237 QTEST_SET_MAIN_SOURCE_PATH
387 QTEST_SET_MAIN_SOURCE_PATH
238 return QTest::qExec(&testObject, argc, argv);
388 return QTest::qExec(&testObject, argc, argv);
239 }
389 }
240
390
241 #include "TestAmdaFuzzing.moc"
391 #include "TestAmdaFuzzing.moc"
General Comments 0
You need to be logged in to leave comments. Login now