##// END OF EJS Templates
Fixes on fuzzing tests
Alexandre Leroux -
r1274:6015d1ab6800
parent child
Show More
@@ -1,109 +1,118
1 #include "FuzzingDefs.h"
1 #include "FuzzingDefs.h"
2
2
3 const QString ACQUISITION_TIMEOUT_PROPERTY = QStringLiteral("acquisitionTimeout");
3 const QString ACQUISITION_TIMEOUT_PROPERTY = QStringLiteral("acquisitionTimeout");
4 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");
5 const QString NB_MAX_SYNC_GROUPS_PROPERTY = QStringLiteral("nbSyncGroups");
6 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
6 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
7 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
7 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
8 const QString CACHE_TOLERANCE_PROPERTY = QStringLiteral("cacheTolerance");
8 const QString CACHE_TOLERANCE_PROPERTY = QStringLiteral("cacheTolerance");
9 const QString INITIAL_RANGE_PROPERTY = QStringLiteral("initialRange");
9 const QString INITIAL_RANGE_PROPERTY = QStringLiteral("initialRange");
10 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
10 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
11 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
11 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
12 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
12 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
13 const QString OPERATION_DELAY_BOUNDS_PROPERTY = QStringLiteral("operationDelays");
13 const QString OPERATION_DELAY_BOUNDS_PROPERTY = QStringLiteral("operationDelays");
14 const QString VALIDATORS_PROPERTY = QStringLiteral("validators");
14 const QString VALIDATORS_PROPERTY = QStringLiteral("validators");
15 const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY = QStringLiteral("validationFrequencyBounds");
15 const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY = QStringLiteral("validationFrequencyBounds");
16
16
17 // //////////// //
17 // //////////// //
18 // FuzzingState //
18 // FuzzingState //
19 // //////////// //
19 // //////////// //
20
20
21 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
21 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
22 {
22 {
23 return m_SyncGroupsPool.at(id);
23 return m_SyncGroupsPool.at(id);
24 }
24 }
25
25
26 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
26 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
27 {
27 {
28 return m_SyncGroupsPool.at(id);
28 return m_SyncGroupsPool.at(id);
29 }
29 }
30
30
31 const VariableState &FuzzingState::variableState(VariableId id) const
31 const VariableState &FuzzingState::variableState(VariableId id) const
32 {
32 {
33 return m_VariablesPool.at(id);
33 return m_VariablesPool.at(id);
34 }
34 }
35
35
36 VariableState &FuzzingState::variableState(VariableId id)
36 VariableState &FuzzingState::variableState(VariableId id)
37 {
37 {
38 return m_VariablesPool.at(id);
38 return m_VariablesPool.at(id);
39 }
39 }
40
40
41 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
41 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
42 {
42 {
43 auto end = m_SyncGroupsPool.cend();
43 auto end = m_SyncGroupsPool.cend();
44 auto it
44 auto it
45 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
45 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
46 const auto &syncGroup = syncGroupEntry.second;
46 const auto &syncGroup = syncGroupEntry.second;
47 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
47 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
48 });
48 });
49
49
50 return it != end ? it->first : SyncGroupId{};
50 return it != end ? it->first : SyncGroupId{};
51 }
51 }
52
52
53 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
53 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
54 {
54 {
55 std::vector<SyncGroupId> result{};
55 std::vector<SyncGroupId> result{};
56
56
57 for (const auto &entry : m_SyncGroupsPool) {
57 for (const auto &entry : m_SyncGroupsPool) {
58 result.push_back(entry.first);
58 result.push_back(entry.first);
59 }
59 }
60
60
61 return result;
61 return result;
62 }
62 }
63
63
64 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
64 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
65 {
65 {
66 if (syncGroupId.isNull()) {
66 if (syncGroupId.isNull()) {
67 return;
67 return;
68 }
68 }
69
69
70 // Registers variable into sync group: if it's the first variable, sets the variable range as
70 // Registers variable into sync group
71 // the sync group range
72 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
71 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
72 auto &variableState = m_VariablesPool.at(variableId);
73 syncGroup.m_Variables.insert(variableId);
73 syncGroup.m_Variables.insert(variableId);
74 if (syncGroup.m_Variables.size() == 1) {
74 if (syncGroup.m_Variables.size() == 1) {
75 auto &variableState = m_VariablesPool.at(variableId);
75 // If it's the first variable, sets the variable range as the sync group range
76 syncGroup.m_Range = variableState.m_Range;
76 syncGroup.m_Range = variableState.m_Range;
77 }
77 }
78 else {
79 // If a variable is added to an existing group, sets its range to the group's range
80 variableState.m_Range = syncGroup.m_Range;
81 }
78 }
82 }
79
83
80 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
84 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
81 {
85 {
82 if (syncGroupId.isNull()) {
86 if (syncGroupId.isNull()) {
83 return;
87 return;
84 }
88 }
85
89
86 // Unregisters variable from sync group: if there is no more variable in the group, resets the
90 // Unregisters variable from sync group: if there is no more variable in the group, resets the
87 // range
91 // range
88 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
92 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
89 syncGroup.m_Variables.erase(variableId);
93 syncGroup.m_Variables.erase(variableId);
90 if (syncGroup.m_Variables.empty()) {
94 if (syncGroup.m_Variables.empty()) {
91 syncGroup.m_Range = INVALID_RANGE;
95 syncGroup.m_Range = INVALID_RANGE;
92 }
96 }
93 }
97 }
94
98
95 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
99 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
96 {
100 {
97 auto syncGroupId = this->syncGroupId(variableId);
101 auto syncGroupId = this->syncGroupId(variableId);
98
102
99 // Retrieves the variables to update:
103 // Retrieves the variables to update:
100 // - if the variable is synchronized to others, updates all synchronized variables
104 // - if the variable is synchronized to others, updates the range of the group and of all
105 // synchronized variables
101 // - otherwise, updates only the variable
106 // - otherwise, updates only the variable
102 auto variablesToUpdate = syncGroupId.isNull() ? std::set<VariableId>{variableId}
107 if (syncGroupId.isNull()) {
103 : m_SyncGroupsPool.at(syncGroupId).m_Variables;
108 m_VariablesPool.at(variableId).m_Range = newRange;
109 }
110 else {
111 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
112 syncGroup.m_Range = newRange;
104
113
105 // Sets new range
114 for (const auto &variableId : syncGroup.m_Variables) {
106 for (const auto &variableId : variablesToUpdate) {
107 m_VariablesPool.at(variableId).m_Range = newRange;
115 m_VariablesPool.at(variableId).m_Range = newRange;
108 }
116 }
109 }
117 }
118 }
@@ -1,265 +1,268
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>
11 #include <functional>
12
12
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
14
14
15 namespace {
15 namespace {
16
16
17 struct CreateOperation : public IFuzzingOperation {
17 struct CreateOperation : public IFuzzingOperation {
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
19 {
19 {
20 // 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
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
22 }
22 }
23
23
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
25 VariableController &variableController,
25 VariableController &variableController,
26 const Properties &properties) const override
26 const Properties &properties) const override
27 {
27 {
28 // 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
29 // associate it with the variable
29 // associate it with the variable
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
32
32
33 // Retrieves provider
33 // Retrieves provider
34 auto variableProvider
34 auto variableProvider
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
36
36
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
39 << "(metadata:" << variableMetadata << ")...";
39 << "(metadata:" << variableMetadata << ")...";
40
40
41 auto newVariable
41 auto newVariable
42 = variableController.createVariable(variableName, variableMetadata, variableProvider);
42 = variableController.createVariable(variableName, variableMetadata, variableProvider);
43
43
44 // Updates variable's state
44 // Updates variable's state
45 auto &variableState = fuzzingState.variableState(variableId);
45 auto &variableState = fuzzingState.variableState(variableId);
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>();
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>();
47 std::swap(variableState.m_Variable, newVariable);
47 std::swap(variableState.m_Variable, newVariable);
48 }
48 }
49 };
49 };
50
50
51 struct DeleteOperation : public IFuzzingOperation {
51 struct DeleteOperation : public IFuzzingOperation {
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
53 {
53 {
54 // A variable can be delete only if it exists
54 // A variable can be delete only if it exists
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
56 }
56 }
57
57
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
59 VariableController &variableController, const Properties &) const override
59 VariableController &variableController, const Properties &) const override
60 {
60 {
61 auto &variableState = fuzzingState.variableState(variableId);
61 auto &variableState = fuzzingState.variableState(variableId);
62
62
63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
64 << variableState.m_Variable->name() << "...";
64 << variableState.m_Variable->name() << "...";
65 variableController.deleteVariable(variableState.m_Variable);
65 variableController.deleteVariable(variableState.m_Variable);
66
66
67 // Updates variable's state
67 // Updates variable's state
68 variableState.m_Range = INVALID_RANGE;
68 variableState.m_Range = INVALID_RANGE;
69 variableState.m_Variable = nullptr;
69 variableState.m_Variable = nullptr;
70
70
71 // Desynchronizes the variable if it was in a sync group
71 // Desynchronizes the variable if it was in a sync group
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
74 }
74 }
75 };
75 };
76
76
77 /**
77 /**
78 * Defines a move operation through a range.
78 * Defines a move operation through a range.
79 *
79 *
80 * A move operation is determined by three functions:
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
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:
82 * are going during the operation. These functions will be:
83 * -- {<- / <-} for pan left
83 * -- {<- / <-} for pan left
84 * -- {-> / ->} for pan right
84 * -- {-> / ->} for pan right
85 * -- {-> / <-} for zoom in
85 * -- {-> / <-} for zoom in
86 * -- {<- / ->} for zoom out
86 * -- {<- / ->} for zoom out
87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
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},
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:
89 * max deltas will be:
90 * -- {0, 4} for pan left
90 * -- {0, 4} for pan left
91 * -- {6, 10} for pan right
91 * -- {6, 10} for pan right
92 * -- {3, 3} for zoom in
92 * -- {3, 3} for zoom in
93 * -- {0, 6} for zoom out (same spacing left and right)
93 * -- {0, 6} for zoom out (same spacing left and right)
94 */
94 */
95 struct MoveOperation : public IFuzzingOperation {
95 struct MoveOperation : public IFuzzingOperation {
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
97 using MaxMoveFunction = std::function<double(const SqpRange &range, const SqpRange &maxRange)>;
97 using MaxMoveFunction = std::function<double(const SqpRange &range, const SqpRange &maxRange)>;
98
98
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
100 MaxMoveFunction maxMoveFun,
100 MaxMoveFunction maxMoveFun,
101 const QString &label = QStringLiteral("Move operation"))
101 const QString &label = QStringLiteral("Move operation"))
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
105 m_Label{label}
105 m_Label{label}
106 {
106 {
107 }
107 }
108
108
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
110 {
110 {
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
112 }
112 }
113
113
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
115 VariableController &variableController,
115 VariableController &variableController,
116 const Properties &properties) const override
116 const Properties &properties) const override
117 {
117 {
118 auto &variableState = fuzzingState.variableState(variableId);
118 auto &variableState = fuzzingState.variableState(variableId);
119 auto variable = variableState.m_Variable;
119 auto variable = variableState.m_Variable;
120
120
121 // Gets the max range defined
121 // Gets the max range defined
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
123 .value<SqpRange>();
123 .value<SqpRange>();
124 auto variableRange = variableState.m_Range;
124 auto variableRange = variableState.m_Range;
125
125
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
129 return;
129 return;
130 }
130 }
131
131
132 // Computes the max delta at which the variable can move, up to the limits of the max range
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);
133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
134
134
135 // Generates random delta that will be used to move variable
135 // Generates random delta that will be used to move variable
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
137
137
138 // Moves variable to its new range
138 // Moves variable to its new range
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
140 auto newVariableRange = SqpRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
140 auto newVariableRange = SqpRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
143 << variable->name() << "(from" << variableRange
143 << variable->name() << "(from" << variableRange
144 << "to" << newVariableRange << ")...";
144 << "to" << newVariableRange << ")...";
145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
146
146
147 // Updates state
147 // Updates state
148 fuzzingState.updateRanges(variableId, newVariableRange);
148 fuzzingState.updateRanges(variableId, newVariableRange);
149 }
149 }
150
150
151 MoveFunction m_RangeStartMoveFun;
151 MoveFunction m_RangeStartMoveFun;
152 MoveFunction m_RangeEndMoveFun;
152 MoveFunction m_RangeEndMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
154 QString m_Label;
154 QString m_Label;
155 };
155 };
156
156
157 struct SynchronizeOperation : public IFuzzingOperation {
157 struct SynchronizeOperation : public IFuzzingOperation {
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
159 {
159 {
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
162 && fuzzingState.syncGroupId(variableId).isNull();
162 && fuzzingState.syncGroupId(variableId).isNull();
163 }
163 }
164
164
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
166 VariableController &variableController, const Properties &) const override
166 VariableController &variableController, const Properties &) const override
167 {
167 {
168 auto &variableState = fuzzingState.variableState(variableId);
168 auto &variableState = fuzzingState.variableState(variableId);
169
169
170 // Chooses a random synchronization group and adds the variable into sync group
170 // Chooses a random synchronization group and adds the variable into sync group
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
173 << "into synchronization group" << syncGroupId
173 << "into synchronization group" << syncGroupId
174 << "...";
174 << "...";
175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
176
176
177 // Updates state
177 // Updates state
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
179
180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
181 false);
179 }
182 }
180 };
183 };
181
184
182 struct DesynchronizeOperation : public IFuzzingOperation {
185 struct DesynchronizeOperation : public IFuzzingOperation {
183 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
186 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
184 {
187 {
185 auto variable = fuzzingState.variableState(variableId).m_Variable;
188 auto variable = fuzzingState.variableState(variableId).m_Variable;
186 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
189 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
187 }
190 }
188
191
189 void execute(VariableId variableId, FuzzingState &fuzzingState,
192 void execute(VariableId variableId, FuzzingState &fuzzingState,
190 VariableController &variableController, const Properties &) const override
193 VariableController &variableController, const Properties &) const override
191 {
194 {
192 auto &variableState = fuzzingState.variableState(variableId);
195 auto &variableState = fuzzingState.variableState(variableId);
193
196
194 // Gets the sync group of the variable
197 // Gets the sync group of the variable
195 auto syncGroupId = fuzzingState.syncGroupId(variableId);
198 auto syncGroupId = fuzzingState.syncGroupId(variableId);
196
199
197 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
198 << "from synchronization group" << syncGroupId
201 << "from synchronization group" << syncGroupId
199 << "...";
202 << "...";
200 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
201
204
202 // Updates state
205 // Updates state
203 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
204 }
207 }
205 };
208 };
206
209
207 struct UnknownOperation : public IFuzzingOperation {
210 struct UnknownOperation : public IFuzzingOperation {
208 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
211 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
209
212
210 void execute(VariableId, FuzzingState &, VariableController &,
213 void execute(VariableId, FuzzingState &, VariableController &,
211 const Properties &) const override
214 const Properties &) const override
212 {
215 {
213 }
216 }
214 };
217 };
215
218
216 } // namespace
219 } // namespace
217
220
218 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
221 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
219 {
222 {
220 switch (type) {
223 switch (type) {
221 case FuzzingOperationType::CREATE:
224 case FuzzingOperationType::CREATE:
222 return std::make_unique<CreateOperation>();
225 return std::make_unique<CreateOperation>();
223 case FuzzingOperationType::DELETE:
226 case FuzzingOperationType::DELETE:
224 return std::make_unique<DeleteOperation>();
227 return std::make_unique<DeleteOperation>();
225 case FuzzingOperationType::PAN_LEFT:
228 case FuzzingOperationType::PAN_LEFT:
226 return std::make_unique<MoveOperation>(
229 return std::make_unique<MoveOperation>(
227 std::minus<double>(), std::minus<double>(),
230 std::minus<double>(), std::minus<double>(),
228 [](const SqpRange &range, const SqpRange &maxRange) {
231 [](const SqpRange &range, const SqpRange &maxRange) {
229 return range.m_TStart - maxRange.m_TStart;
232 return range.m_TStart - maxRange.m_TStart;
230 },
233 },
231 QStringLiteral("Pan left operation"));
234 QStringLiteral("Pan left operation"));
232 case FuzzingOperationType::PAN_RIGHT:
235 case FuzzingOperationType::PAN_RIGHT:
233 return std::make_unique<MoveOperation>(
236 return std::make_unique<MoveOperation>(
234 std::plus<double>(), std::plus<double>(),
237 std::plus<double>(), std::plus<double>(),
235 [](const SqpRange &range, const SqpRange &maxRange) {
238 [](const SqpRange &range, const SqpRange &maxRange) {
236 return maxRange.m_TEnd - range.m_TEnd;
239 return maxRange.m_TEnd - range.m_TEnd;
237 },
240 },
238 QStringLiteral("Pan right operation"));
241 QStringLiteral("Pan right operation"));
239 case FuzzingOperationType::ZOOM_IN:
242 case FuzzingOperationType::ZOOM_IN:
240 return std::make_unique<MoveOperation>(
243 return std::make_unique<MoveOperation>(
241 std::plus<double>(), std::minus<double>(),
244 std::plus<double>(), std::minus<double>(),
242 [](const SqpRange &range, const SqpRange &maxRange) {
245 [](const SqpRange &range, const SqpRange &maxRange) {
243 Q_UNUSED(maxRange)
246 Q_UNUSED(maxRange)
244 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
247 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
245 },
248 },
246 QStringLiteral("Zoom in operation"));
249 QStringLiteral("Zoom in operation"));
247 case FuzzingOperationType::ZOOM_OUT:
250 case FuzzingOperationType::ZOOM_OUT:
248 return std::make_unique<MoveOperation>(
251 return std::make_unique<MoveOperation>(
249 std::minus<double>(), std::plus<double>(),
252 std::minus<double>(), std::plus<double>(),
250 [](const SqpRange &range, const SqpRange &maxRange) {
253 [](const SqpRange &range, const SqpRange &maxRange) {
251 return std::min(range.m_TStart - maxRange.m_TStart,
254 return std::min(range.m_TStart - maxRange.m_TStart,
252 maxRange.m_TEnd - range.m_TEnd);
255 maxRange.m_TEnd - range.m_TEnd);
253 },
256 },
254 QStringLiteral("Zoom out operation"));
257 QStringLiteral("Zoom out operation"));
255 case FuzzingOperationType::SYNCHRONIZE:
258 case FuzzingOperationType::SYNCHRONIZE:
256 return std::make_unique<SynchronizeOperation>();
259 return std::make_unique<SynchronizeOperation>();
257 case FuzzingOperationType::DESYNCHRONIZE:
260 case FuzzingOperationType::DESYNCHRONIZE:
258 return std::make_unique<DesynchronizeOperation>();
261 return std::make_unique<DesynchronizeOperation>();
259 default:
262 default:
260 // Default case returns unknown operation
263 // Default case returns unknown operation
261 break;
264 break;
262 }
265 }
263
266
264 return std::make_unique<UnknownOperation>();
267 return std::make_unique<UnknownOperation>();
265 }
268 }
@@ -1,228 +1,228
1 #include "FuzzingValidators.h"
1 #include "FuzzingValidators.h"
2 #include "FuzzingDefs.h"
2 #include "FuzzingDefs.h"
3
3
4 #include <Data/DataSeries.h>
4 #include <Data/DataSeries.h>
5 #include <Variable/Variable.h>
5 #include <Variable/Variable.h>
6
6
7 #include <QTest>
7 #include <QTest>
8
8
9 #include <functional>
9 #include <functional>
10
10
11 Q_LOGGING_CATEGORY(LOG_FuzzingValidators, "FuzzingValidators")
11 Q_LOGGING_CATEGORY(LOG_FuzzingValidators, "FuzzingValidators")
12
12
13 namespace {
13 namespace {
14
14
15 // ////////////// //
15 // ////////////// //
16 // DATA VALIDATOR //
16 // DATA VALIDATOR //
17 // ////////////// //
17 // ////////////// //
18
18
19 /// Singleton used to validate data of a variable
19 /// Singleton used to validate data of a variable
20 class DataValidatorHelper {
20 class DataValidatorHelper {
21 public:
21 public:
22 /// @return the single instance of the helper
22 /// @return the single instance of the helper
23 static DataValidatorHelper &instance();
23 static DataValidatorHelper &instance();
24 virtual ~DataValidatorHelper() noexcept = default;
24 virtual ~DataValidatorHelper() noexcept = default;
25
25
26 virtual void validate(const VariableState &variableState) const = 0;
26 virtual void validate(const VariableState &variableState) const = 0;
27 };
27 };
28
28
29 /**
29 /**
30 * Default implementation of @sa DataValidatorHelper
30 * Default implementation of @sa DataValidatorHelper
31 */
31 */
32 class DefaultDataValidatorHelper : public DataValidatorHelper {
32 class DefaultDataValidatorHelper : public DataValidatorHelper {
33 public:
33 public:
34 void validate(const VariableState &variableState) const override
34 void validate(const VariableState &variableState) const override
35 {
35 {
36 Q_UNUSED(variableState);
36 Q_UNUSED(variableState);
37 qCWarning(LOG_FuzzingValidators()).noquote() << "Checking variable's data... WARN: no data "
37 qCWarning(LOG_FuzzingValidators()).noquote() << "Checking variable's data... WARN: no data "
38 "verification is available for this server";
38 "verification is available for this server";
39 }
39 }
40 };
40 };
41
41
42 /// Data resolution in local server's files
42 /// Data resolution in local server's files
43 const auto LOCALHOST_SERVER_RESOLUTION = 4;
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
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)
45 /// between the data date and this reference date)
46 const auto LOCALHOST_REFERENCE_VALUE
46 const auto LOCALHOST_REFERENCE_VALUE
47 = DateUtils::secondsSinceEpoch(QDateTime{QDate{2000, 1, 1}, QTime{}, Qt::UTC});
47 = DateUtils::secondsSinceEpoch(QDateTime{QDate{2000, 1, 1}, QTime{}, Qt::UTC});
48
48
49 /**
49 /**
50 * Implementation of @sa DataValidatorHelper for the local AMDA server
50 * Implementation of @sa DataValidatorHelper for the local AMDA server
51 */
51 */
52 class LocalhostServerDataValidatorHelper : public DataValidatorHelper {
52 class LocalhostServerDataValidatorHelper : public DataValidatorHelper {
53 public:
53 public:
54 void validate(const VariableState &variableState) const override
54 void validate(const VariableState &variableState) const override
55 {
55 {
56 // Don't check data for null variable
56 // Don't check data for null variable
57 if (!variableState.m_Variable || variableState.m_Range == INVALID_RANGE) {
57 if (!variableState.m_Variable || variableState.m_Range == INVALID_RANGE) {
58 return;
58 return;
59 }
59 }
60
60
61 auto message = "Checking variable's data...";
61 auto message = "Checking variable's data...";
62 auto toDateString = [](double value) { return DateUtils::dateTime(value).toString(); };
62 auto toDateString = [](double value) { return DateUtils::dateTime(value).toString(); };
63
63
64 // Checks that data are defined
64 // Checks that data are defined
65 auto variableDataSeries = variableState.m_Variable->dataSeries();
65 auto variableDataSeries = variableState.m_Variable->dataSeries();
66 if (variableDataSeries == nullptr && variableState.m_Range != INVALID_RANGE) {
66 if (variableDataSeries == nullptr && variableState.m_Range != INVALID_RANGE) {
67 qCInfo(LOG_FuzzingValidators()).noquote()
67 qCInfo(LOG_FuzzingValidators()).noquote()
68 << message << "FAIL: the variable has no data while a range is defined";
68 << message << "FAIL: the variable has no data while a range is defined";
69 QFAIL("");
69 QFAIL("");
70 }
70 }
71
71
72 auto dataIts = variableDataSeries->xAxisRange(variableState.m_Range.m_TStart,
72 auto dataIts = variableDataSeries->xAxisRange(variableState.m_Range.m_TStart,
73 variableState.m_Range.m_TEnd);
73 variableState.m_Range.m_TEnd);
74
74
75 // Checks that the data are well defined in the range:
75 // Checks that the data are well defined in the range:
76 // - there is at least one data
76 // - there is at least one data
77 // - the data are consistent (no data holes)
77 // - the data are consistent (no data holes)
78 if (std::distance(dataIts.first, dataIts.second) == 0) {
78 if (std::distance(dataIts.first, dataIts.second) == 0) {
79 qCInfo(LOG_FuzzingValidators()).noquote() << message
79 qCInfo(LOG_FuzzingValidators()).noquote() << message
80 << "FAIL: the variable has no data";
80 << "FAIL: the variable has no data";
81 QFAIL("");
81 QFAIL("");
82 }
82 }
83
83
84 auto firstXAxisData = dataIts.first->x();
84 auto firstXAxisData = dataIts.first->x();
85 auto lastXAxisData = (dataIts.second - 1)->x();
85 auto lastXAxisData = (dataIts.second - 1)->x();
86
86
87 if (std::abs(firstXAxisData - variableState.m_Range.m_TStart) > LOCALHOST_SERVER_RESOLUTION
87 if (std::abs(firstXAxisData - variableState.m_Range.m_TStart) > LOCALHOST_SERVER_RESOLUTION
88 || std::abs(lastXAxisData - variableState.m_Range.m_TEnd)
88 || std::abs(lastXAxisData - variableState.m_Range.m_TEnd)
89 > LOCALHOST_SERVER_RESOLUTION) {
89 > LOCALHOST_SERVER_RESOLUTION) {
90 qCInfo(LOG_FuzzingValidators()).noquote()
90 qCInfo(LOG_FuzzingValidators()).noquote()
91 << message << "FAIL: the data in the defined range are inconsistent (data hole "
91 << message << "FAIL: the data in the defined range are inconsistent (data hole "
92 "found at the beginning or the end)";
92 "found at the beginning or the end)";
93 QFAIL("");
93 QFAIL("");
94 }
94 }
95
95
96 auto dataHoleIt = std::adjacent_find(
96 auto dataHoleIt = std::adjacent_find(
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
98 /// @todo: validate resolution
98 /// @todo: validate resolution
99 return std::abs(it1.x() - it2.x()) > 2 * (LOCALHOST_SERVER_RESOLUTION - 1);
99 return std::abs(it1.x() - it2.x()) > 2 * LOCALHOST_SERVER_RESOLUTION;
100 });
100 });
101
101
102 if (dataHoleIt != dataIts.second) {
102 if (dataHoleIt != dataIts.second) {
103 qCInfo(LOG_FuzzingValidators()).noquote()
103 qCInfo(LOG_FuzzingValidators()).noquote()
104 << message << "FAIL: the data in the defined range are inconsistent (data hole "
104 << message << "FAIL: the data in the defined range are inconsistent (data hole "
105 "found between times "
105 "found between times "
106 << toDateString(dataHoleIt->x()) << "and " << toDateString((dataHoleIt + 1)->x())
106 << toDateString(dataHoleIt->x()) << "and " << toDateString((dataHoleIt + 1)->x())
107 << ")";
107 << ")";
108 QFAIL("");
108 QFAIL("");
109 }
109 }
110
110
111 // Checks values
111 // Checks values
112 auto dataIndex = 0;
112 auto dataIndex = 0;
113 for (auto dataIt = dataIts.first; dataIt != dataIts.second; ++dataIt, ++dataIndex) {
113 for (auto dataIt = dataIts.first; dataIt != dataIts.second; ++dataIt, ++dataIndex) {
114 auto xAxisData = dataIt->x();
114 auto xAxisData = dataIt->x();
115 auto valuesData = dataIt->values();
115 auto valuesData = dataIt->values();
116 for (auto valueIndex = 0, valueEnd = valuesData.size(); valueIndex < valueEnd;
116 for (auto valueIndex = 0, valueEnd = valuesData.size(); valueIndex < valueEnd;
117 ++valueIndex) {
117 ++valueIndex) {
118 auto value = valuesData.at(valueIndex);
118 auto value = valuesData.at(valueIndex);
119 auto expectedValue = xAxisData + valueIndex * LOCALHOST_SERVER_RESOLUTION
119 auto expectedValue = xAxisData + valueIndex * LOCALHOST_SERVER_RESOLUTION
120 - LOCALHOST_REFERENCE_VALUE;
120 - LOCALHOST_REFERENCE_VALUE;
121
121
122 if (value != expectedValue) {
122 if (value != expectedValue) {
123 qCInfo(LOG_FuzzingValidators()).noquote()
123 qCInfo(LOG_FuzzingValidators()).noquote()
124 << message << "FAIL: incorrect value data at time"
124 << message << "FAIL: incorrect value data at time"
125 << toDateString(xAxisData) << ", index" << valueIndex << "(found:" << value
125 << toDateString(xAxisData) << ", index" << valueIndex << "(found:" << value
126 << ", expected:" << expectedValue << ")";
126 << ", expected:" << expectedValue << ")";
127 QFAIL("");
127 QFAIL("");
128 }
128 }
129 }
129 }
130 }
130 }
131
131
132 // At this step validation is OK
132 // At this step validation is OK
133 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
133 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
134 }
134 }
135 };
135 };
136
136
137 /// Creates the @sa DataValidatorHelper according to the server passed in parameter
137 /// Creates the @sa DataValidatorHelper according to the server passed in parameter
138 std::unique_ptr<DataValidatorHelper> createDataValidatorInstance(const QString &server)
138 std::unique_ptr<DataValidatorHelper> createDataValidatorInstance(const QString &server)
139 {
139 {
140 if (server == QString{"localhost"}) {
140 if (server == QString{"localhost"}) {
141 return std::make_unique<LocalhostServerDataValidatorHelper>();
141 return std::make_unique<LocalhostServerDataValidatorHelper>();
142 }
142 }
143 else {
143 else {
144 return std::make_unique<DefaultDataValidatorHelper>();
144 return std::make_unique<DefaultDataValidatorHelper>();
145 }
145 }
146 }
146 }
147
147
148 DataValidatorHelper &DataValidatorHelper::instance()
148 DataValidatorHelper &DataValidatorHelper::instance()
149 {
149 {
150 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
150 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
151 static auto instance = createDataValidatorInstance(SCIQLOP_AMDA_SERVER);
151 static auto instance = createDataValidatorInstance(SCIQLOP_AMDA_SERVER);
152 return *instance;
152 return *instance;
153 }
153 }
154
154
155 // /////////////// //
155 // /////////////// //
156 // RANGE VALIDATOR //
156 // RANGE VALIDATOR //
157 // /////////////// //
157 // /////////////// //
158
158
159 /**
159 /**
160 * Checks that a range of a variable matches the expected range passed as a parameter
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
161 * @param variable the variable for which to check the range
162 * @param expectedRange the expected range
162 * @param expectedRange the expected range
163 * @param getVariableRangeFun the function to retrieve the range from the variable
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
164 * @remarks if the variable is null, checks that the expected range is the invalid range
165 */
165 */
166 void validateRange(std::shared_ptr<Variable> variable, const SqpRange &expectedRange,
166 void validateRange(std::shared_ptr<Variable> variable, const SqpRange &expectedRange,
167 std::function<SqpRange(const Variable &)> getVariableRangeFun)
167 std::function<SqpRange(const Variable &)> getVariableRangeFun)
168 {
168 {
169 auto compare = [](const auto &range, const auto &expectedRange, const auto &message) {
169 auto compare = [](const auto &range, const auto &expectedRange, const auto &message) {
170 if (range == expectedRange) {
170 if (range == expectedRange) {
171 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
171 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
172 }
172 }
173 else {
173 else {
174 qCInfo(LOG_FuzzingValidators()).noquote() << message << "FAIL (current range:" << range
174 qCInfo(LOG_FuzzingValidators()).noquote() << message << "FAIL (current range:" << range
175 << ", expected range:" << expectedRange
175 << ", expected range:" << expectedRange
176 << ")";
176 << ")";
177 QFAIL("");
177 QFAIL("");
178 }
178 }
179 };
179 };
180
180
181 if (variable) {
181 if (variable) {
182 compare(getVariableRangeFun(*variable), expectedRange, "Checking variable's range...");
182 compare(getVariableRangeFun(*variable), expectedRange, "Checking variable's range...");
183 }
183 }
184 else {
184 else {
185 compare(INVALID_RANGE, expectedRange, "Checking that there is no range set...");
185 compare(INVALID_RANGE, expectedRange, "Checking that there is no range set...");
186 }
186 }
187 }
187 }
188
188
189 /**
189 /**
190 * Default implementation of @sa IFuzzingValidator. This validator takes as parameter of its
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
191 * construction a function of validation which is called in the validate() method
192 */
192 */
193 class FuzzingValidator : public IFuzzingValidator {
193 class FuzzingValidator : public IFuzzingValidator {
194 public:
194 public:
195 /// Signature of a validation function
195 /// Signature of a validation function
196 using ValidationFunction = std::function<void(const VariableState &variableState)>;
196 using ValidationFunction = std::function<void(const VariableState &variableState)>;
197
197
198 explicit FuzzingValidator(ValidationFunction fun) : m_Fun(std::move(fun)) {}
198 explicit FuzzingValidator(ValidationFunction fun) : m_Fun(std::move(fun)) {}
199
199
200 void validate(const VariableState &variableState) const override { m_Fun(variableState); }
200 void validate(const VariableState &variableState) const override { m_Fun(variableState); }
201
201
202 private:
202 private:
203 ValidationFunction m_Fun;
203 ValidationFunction m_Fun;
204 };
204 };
205
205
206 } // namespace
206 } // namespace
207
207
208 std::unique_ptr<IFuzzingValidator> FuzzingValidatorFactory::create(FuzzingValidatorType type)
208 std::unique_ptr<IFuzzingValidator> FuzzingValidatorFactory::create(FuzzingValidatorType type)
209 {
209 {
210 switch (type) {
210 switch (type) {
211 case FuzzingValidatorType::DATA:
211 case FuzzingValidatorType::DATA:
212 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
212 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
213 DataValidatorHelper::instance().validate(variableState);
213 DataValidatorHelper::instance().validate(variableState);
214 });
214 });
215 case FuzzingValidatorType::RANGE:
215 case FuzzingValidatorType::RANGE:
216 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
216 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
217 auto getVariableRange = [](const Variable &variable) { return variable.range(); };
217 auto getVariableRange = [](const Variable &variable) { return variable.range(); };
218 validateRange(variableState.m_Variable, variableState.m_Range, getVariableRange);
218 validateRange(variableState.m_Variable, variableState.m_Range, getVariableRange);
219 });
219 });
220 default:
220 default:
221 // Default case returns invalid validator
221 // Default case returns invalid validator
222 break;
222 break;
223 }
223 }
224
224
225 // Invalid validator
225 // Invalid validator
226 return std::make_unique<FuzzingValidator>(
226 return std::make_unique<FuzzingValidator>(
227 [](const VariableState &) { QFAIL("Invalid validator"); });
227 [](const VariableState &) { QFAIL("Invalid validator"); });
228 }
228 }
@@ -1,391 +1,395
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 #include "FuzzingValidators.h"
5
5
6 #include "AmdaProvider.h"
6 #include "AmdaProvider.h"
7
7
8 #include <Common/SignalWaiter.h>
8 #include <Common/SignalWaiter.h>
9 #include <Network/NetworkController.h>
9 #include <Network/NetworkController.h>
10 #include <Settings/SqpSettingsDefs.h>
10 #include <Settings/SqpSettingsDefs.h>
11 #include <SqpApplication.h>
11 #include <SqpApplication.h>
12 #include <Time/TimeController.h>
12 #include <Time/TimeController.h>
13 #include <Variable/Variable.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
14 #include <Variable/VariableController.h>
15
15
16 #include <QLoggingCategory>
16 #include <QLoggingCategory>
17 #include <QObject>
17 #include <QObject>
18 #include <QtTest>
18 #include <QtTest>
19
19
20 #include <memory>
20 #include <memory>
21
21
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
23
23
24 /**
24 /**
25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
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
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:
27 * it's not present. Macro arguments are:
28 * - GETTER_NAME : name of the getter
28 * - GETTER_NAME : name of the getter
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
31 * - TYPE : return type of the getter
31 * - TYPE : return type of the getter
32 */
32 */
33 // clang-format off
33 // clang-format off
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
35 TYPE GETTER_NAME() const \
35 TYPE GETTER_NAME() const \
36 { \
36 { \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
38 return result; \
38 return result; \
39 } \
39 } \
40 // clang-format on
40 // clang-format on
41
41
42 namespace {
42 namespace {
43
43
44 // /////// //
44 // /////// //
45 // Aliases //
45 // Aliases //
46 // /////// //
46 // /////// //
47
47
48 using IntPair = std::pair<int, int>;
48 using IntPair = std::pair<int, int>;
49 using Weight = double;
49 using Weight = double;
50 using Weights = std::vector<Weight>;
50 using Weights = std::vector<Weight>;
51
51
52 struct OperationProperty {
52 struct OperationProperty {
53 Weight m_Weight{1.};
53 Weight m_Weight{1.};
54 bool m_WaitAcquisition{false};
54 bool m_WaitAcquisition{false};
55 };
55 };
56
56
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
58 using VariablesOperations = std::vector<VariableOperation>;
58 using VariablesOperations = std::vector<VariableOperation>;
59
59
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
62
62
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
64
64
65 // ///////// //
65 // ///////// //
66 // Constants //
66 // Constants //
67 // ///////// //
67 // ///////// //
68
68
69 // 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;
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
71 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;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
77 {FuzzingOperationType::PAN_LEFT, {1.}},
77 {FuzzingOperationType::PAN_LEFT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
84
84
85 /// Min/max delays between each operation (in ms)
85 /// Min/max delays between each operation (in ms)
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
87
87
88 /// Validators for the tests (executed in the order in which they're defined)
88 /// Validators for the tests (executed in the order in which they're defined)
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
91
91
92 /// Min/max number of operations to execute before calling validation
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));
93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
94
94
95 // /////// //
95 // /////// //
96 // Methods //
96 // Methods //
97 // /////// //
97 // /////// //
98
98
99 /// 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}
100 /// 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)
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
102 const OperationsPool &operationsPool)
102 const OperationsPool &operationsPool)
103 {
103 {
104 VariablesOperations result{};
104 VariablesOperations result{};
105 Weights weights{};
105 Weights weights{};
106
106
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
108 auto variableId = variablesPoolEntry.first;
108 auto variableId = variablesPoolEntry.first;
109
109
110 for (const auto &operationsPoolEntry : operationsPool) {
110 for (const auto &operationsPoolEntry : operationsPool) {
111 auto operation = operationsPoolEntry.first;
111 auto operation = operationsPoolEntry.first;
112 auto operationProperty = operationsPoolEntry.second;
112 auto operationProperty = operationsPoolEntry.second;
113
113
114 // 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
115 if (operation->canExecute(variableId, fuzzingState)) {
115 if (operation->canExecute(variableId, fuzzingState)) {
116 result.push_back({variableId, operation});
116 result.push_back({variableId, operation});
117 weights.push_back(operationProperty.m_Weight);
117 weights.push_back(operationProperty.m_Weight);
118 }
118 }
119 }
119 }
120 }
120 }
121
121
122 return {result, weights};
122 return {result, weights};
123 }
123 }
124
124
125 OperationsPool createOperationsPool(const OperationsTypes &types)
125 OperationsPool createOperationsPool(const OperationsTypes &types)
126 {
126 {
127 OperationsPool result{};
127 OperationsPool result{};
128
128
129 std::transform(
129 std::transform(
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
132 });
132 });
133
133
134 return result;
134 return result;
135 }
135 }
136
136
137 Validators createValidators(const ValidatorsTypes &types)
137 Validators createValidators(const ValidatorsTypes &types)
138 {
138 {
139 Validators result{};
139 Validators result{};
140
140
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
143
143
144 return result;
144 return result;
145 }
145 }
146
146
147 /**
147 /**
148 * Validates all the variables' states passed in parameter, according to a set of validators
148 * Validates all the variables' states passed in parameter, according to a set of validators
149 * @param variablesPool the variables' states
149 * @param variablesPool the variables' states
150 * @param validators the validators used for validation
150 * @param validators the validators used for validation
151 */
151 */
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
153 {
153 {
154 for (const auto &variablesPoolEntry : variablesPool) {
154 for (const auto &variablesPoolEntry : variablesPool) {
155 auto variableId = variablesPoolEntry.first;
155 auto variableId = variablesPoolEntry.first;
156 const auto &variableState = variablesPoolEntry.second;
156 const auto &variableState = variablesPoolEntry.second;
157
157
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
159 : QStringLiteral("null variable");
159 : QStringLiteral("null variable");
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
161 << variableId << "(" << variableMessage << ")...";
161 << variableId << "(" << variableMessage << ")...";
162
162
163 for (const auto &validator : validators) {
163 for (const auto &validator : validators) {
164 validator->validate(VariableState{variableState});
164 validator->validate(VariableState{variableState});
165 }
165 }
166
166
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
168 }
168 }
169 }
169 }
170
170
171 /**
171 /**
172 * Class to run random tests
172 * Class to run random tests
173 */
173 */
174 class FuzzingTest {
174 class FuzzingTest {
175 public:
175 public:
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
177 : m_VariableController{variableController},
177 : m_VariableController{variableController},
178 m_Properties{std::move(properties)},
178 m_Properties{std::move(properties)},
179 m_FuzzingState{}
179 m_FuzzingState{}
180 {
180 {
181 // Inits variables pool: at init, all variables are null
181 // Inits variables pool: at init, all variables are null
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
184 }
184 }
185
185
186 // Inits sync groups and registers them into the variable controller
186 // Inits sync groups and registers them into the variable controller
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
188 auto syncGroupId = SyncGroupId::createUuid();
188 auto syncGroupId = SyncGroupId::createUuid();
189 variableController.onAddSynchronizationGroupId(syncGroupId);
189 variableController.onAddSynchronizationGroupId(syncGroupId);
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
191 }
191 }
192 }
192 }
193
193
194 void execute()
194 void execute()
195 {
195 {
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
197 << nbMaxVariables() << "variable(s)...";
197 << nbMaxVariables() << "variable(s)...";
198
198
199
199
200 // Inits the count of the number of operations before the next validation
200 // Inits the count of the number of operations before the next validation
201 int nextValidationCounter = 0;
201 int nextValidationCounter = 0;
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
203 nextValidationCounter = RandomGenerator::instance().generateInt(
203 nextValidationCounter = RandomGenerator::instance().generateInt(
204 validationFrequencies().first, validationFrequencies().second);
204 validationFrequencies().first, validationFrequencies().second);
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
207 };
207 };
208 updateValidationCounter();
208 updateValidationCounter();
209
209
210 auto canExecute = true;
210 auto canExecute = true;
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
212 // Retrieves all operations that can be executed in the current context
212 // Retrieves all operations that can be executed in the current context
213 VariablesOperations variableOperations{};
213 VariablesOperations variableOperations{};
214 Weights weights{};
214 Weights weights{};
215 std::tie(variableOperations, weights)
215 std::tie(variableOperations, weights)
216 = availableOperations(m_FuzzingState, operationsPool());
216 = availableOperations(m_FuzzingState, operationsPool());
217
217
218 canExecute = !variableOperations.empty();
218 canExecute = !variableOperations.empty();
219 if (canExecute) {
219 if (canExecute) {
220 --nextValidationCounter;
220 --nextValidationCounter;
221
221
222 // Of the operations available, chooses a random operation and executes it
222 // Of the operations available, chooses a random operation and executes it
223 auto variableOperation
223 auto variableOperation
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
225
225
226 auto variableId = variableOperation.first;
226 auto variableId = variableOperation.first;
227 auto fuzzingOperation = variableOperation.second;
227 auto fuzzingOperation = variableOperation.second;
228
228
229 auto waitAcquisition = nextValidationCounter == 0
229 auto waitAcquisition = nextValidationCounter == 0
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
231
231
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
233 m_Properties);
233 m_Properties);
234
234
235 if (waitAcquisition) {
235 if (waitAcquisition) {
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
238 acquisitionTimeout());
238 acquisitionTimeout());
239
239
240 // Validates variables
240 // Validates variables
241 if (nextValidationCounter == 0) {
241 if (nextValidationCounter == 0) {
242 validate(m_FuzzingState.m_VariablesPool, validators());
242 validate(m_FuzzingState.m_VariablesPool, validators());
243 updateValidationCounter();
243 updateValidationCounter();
244 }
244 }
245 }
245 }
246 else {
246 else {
247 // Delays the next operation with a randomly generated time
247 // Delays the next operation with a randomly generated time
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
249 operationDelays().second);
249 operationDelays().second);
250 qCDebug(LOG_TestAmdaFuzzing())
250 qCDebug(LOG_TestAmdaFuzzing())
251 << "Waiting " << delay << "ms before the next operation...";
251 << "Waiting " << delay << "ms before the next operation...";
252 QTest::qWait(delay);
252 QTest::qWait(delay);
253 }
253 }
254 }
254 }
255 else {
255 else {
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
257 << "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...";
258 }
258 }
259 }
259 }
260
260
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
262 }
262 }
263
263
264 private:
264 private:
265 OperationsPool operationsPool() const
265 OperationsPool operationsPool() const
266 {
266 {
267 static auto result = createOperationsPool(
267 static auto result = createOperationsPool(
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
269 .value<OperationsTypes>());
269 .value<OperationsTypes>());
270 return result;
270 return result;
271 }
271 }
272
272
273 Validators validators() const
273 Validators validators() const
274 {
274 {
275 static auto result
275 static auto result
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
277 .value<ValidatorsTypes>());
277 .value<ValidatorsTypes>());
278 return result;
278 return result;
279 }
279 }
280
280
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
287
287
288 VariableController &m_VariableController;
288 VariableController &m_VariableController;
289 Properties m_Properties;
289 Properties m_Properties;
290 FuzzingState m_FuzzingState;
290 FuzzingState m_FuzzingState;
291 };
291 };
292
292
293 } // namespace
293 } // namespace
294
294
295 Q_DECLARE_METATYPE(OperationsTypes)
295 Q_DECLARE_METATYPE(OperationsTypes)
296
296
297 class TestAmdaFuzzing : public QObject {
297 class TestAmdaFuzzing : public QObject {
298 Q_OBJECT
298 Q_OBJECT
299
299
300 private slots:
300 private slots:
301 /// Input data for @sa testFuzzing()
301 /// Input data for @sa testFuzzing()
302 void testFuzzing_data();
302 void testFuzzing_data();
303 void testFuzzing();
303 void testFuzzing();
304 };
304 };
305
305
306 void TestAmdaFuzzing::testFuzzing_data()
306 void TestAmdaFuzzing::testFuzzing_data()
307 {
307 {
308 // Note: Comment this line to run fuzzing tests
308 // Note: Comment this line to run fuzzing tests
309 QSKIP("Fuzzing tests are disabled by default");
309 QSKIP("Fuzzing tests are disabled by default");
310
310
311 // ////////////// //
311 // ////////////// //
312 // Test structure //
312 // Test structure //
313 // ////////////// //
313 // ////////////// //
314
314
315 QTest::addColumn<Properties>("properties"); // Properties for random test
315 QTest::addColumn<Properties>("properties"); // Properties for random test
316
316
317 // ////////// //
317 // ////////// //
318 // Test cases //
318 // Test cases //
319 // ////////// //
319 // ////////// //
320
320
321 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});
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
323
323
324 // 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
325 // QVariant
325 // QVariant
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
327
327
328 QTest::newRow("fuzzingTest") << Properties{
328 QTest::newRow("fuzzingTest") << Properties{
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
332 }
332 }
333
333
334 void TestAmdaFuzzing::testFuzzing()
334 void TestAmdaFuzzing::testFuzzing()
335 {
335 {
336 QFETCH(Properties, properties);
336 QFETCH(Properties, properties);
337
337
338 // Sets cache property
338 // Sets cache property
339 QSettings settings{};
339 QSettings settings{};
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
343
343
344 auto &variableController = sqpApp->variableController();
344 auto &variableController = sqpApp->variableController();
345 auto &timeController = sqpApp->timeController();
345 auto &timeController = sqpApp->timeController();
346
346
347 // Generates random initial range (bounded to max range)
347 // Generates random initial range (bounded to max range)
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
349 .value<SqpRange>();
349 .value<SqpRange>();
350
350
351 QVERIFY(maxRange != INVALID_RANGE);
351 QVERIFY(maxRange != INVALID_RANGE);
352
352
353 auto initialRangeStart
353 auto initialRangeStart
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
355 auto initialRangeEnd
355 auto initialRangeEnd
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
357 if (initialRangeStart > initialRangeEnd) {
357 if (initialRangeStart > initialRangeEnd) {
358 std::swap(initialRangeStart, initialRangeEnd);
358 std::swap(initialRangeStart, initialRangeEnd);
359 }
359 }
360
360
361 // Sets initial range on time controller
361 // Sets initial range on time controller
362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
364 timeController.onTimeToUpdate(initialRange);
364 timeController.onTimeToUpdate(initialRange);
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
366
366
367 FuzzingTest test{variableController, properties};
367 FuzzingTest test{variableController, properties};
368 test.execute();
368 test.execute();
369 }
369 }
370
370
371 int main(int argc, char *argv[])
371 int main(int argc, char *argv[])
372 {
372 {
373 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
374 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
376
373 QLoggingCategory::setFilterRules(
377 QLoggingCategory::setFilterRules(
374 "*.warning=false\n"
378 "*.warning=false\n"
375 "*.info=false\n"
379 "*.info=false\n"
376 "*.debug=false\n"
380 "*.debug=false\n"
377 "FuzzingOperations.info=true\n"
381 "FuzzingOperations.info=true\n"
378 "FuzzingValidators.info=true\n"
382 "FuzzingValidators.info=true\n"
379 "TestAmdaFuzzing.info=true\n");
383 "TestAmdaFuzzing.info=true\n");
380
384
381 SqpApplication app{argc, argv};
385 SqpApplication app{argc, argv};
382 SqpApplication::setOrganizationName("LPP");
386 SqpApplication::setOrganizationName("LPP");
383 SqpApplication::setOrganizationDomain("lpp.fr");
387 SqpApplication::setOrganizationDomain("lpp.fr");
384 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
388 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
385 app.setAttribute(Qt::AA_Use96Dpi, true);
389 app.setAttribute(Qt::AA_Use96Dpi, true);
386 TestAmdaFuzzing testObject{};
390 TestAmdaFuzzing testObject{};
387 QTEST_SET_MAIN_SOURCE_PATH
391 QTEST_SET_MAIN_SOURCE_PATH
388 return QTest::qExec(&testObject, argc, argv);
392 return QTest::qExec(&testObject, argc, argv);
389 }
393 }
390
394
391 #include "TestAmdaFuzzing.moc"
395 #include "TestAmdaFuzzing.moc"
General Comments 0
You need to be logged in to leave comments. Login now