##// END OF EJS Templates
Sets the number of sync groups to create for fuzzing tests
Alexandre Leroux -
r1237:d97a694e6326
parent child
Show More
@@ -1,37 +1,38
1 1 #include "FuzzingDefs.h"
2 2
3 3 const QString NB_MAX_OPERATIONS_PROPERTY = QStringLiteral("component");
4 const QString NB_MAX_SYNC_GROUPS_PROPERTY = QStringLiteral("nbSyncGroups");
4 5 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
5 6 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
6 7 const QString CACHE_TOLERANCE_PROPERTY = QStringLiteral("cacheTolerance");
7 8 const QString INITIAL_RANGE_PROPERTY = QStringLiteral("initialRange");
8 9 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
9 10 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
10 11 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
11 12 const QString OPERATION_DELAY_PROPERTY = QStringLiteral("operationDelay");
12 13 const QString VALIDATORS_PROPERTY = QStringLiteral("validators");
13 14
14 15 // //////////// //
15 16 // FuzzingState //
16 17 // //////////// //
17 18
18 19 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
19 20 {
20 21 return m_SyncGroupsPool.at(id);
21 22 }
22 23
23 24 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
24 25 {
25 26 return m_SyncGroupsPool.at(id);
26 27 }
27 28
28 29 const VariableState &FuzzingState::variableState(VariableId id) const
29 30 {
30 31 return m_VariablesPool.at(id);
31 32 }
32 33
33 34 VariableState &FuzzingState::variableState(VariableId id)
34 35 {
35 36 return m_VariablesPool.at(id);
36 37 }
37 38
@@ -1,98 +1,101
1 1 #ifndef SCIQLOP_FUZZINGDEFS_H
2 2 #define SCIQLOP_FUZZINGDEFS_H
3 3
4 4 #include <Data/SqpRange.h>
5 5
6 6 #include <QString>
7 7 #include <QUuid>
8 8 #include <QVariantHash>
9 9
10 10 #include <memory>
11 11 #include <set>
12 12
13 13 // /////// //
14 14 // Aliases //
15 15 // /////// //
16 16
17 17 using MetadataPool = std::vector<QVariantHash>;
18 18 Q_DECLARE_METATYPE(MetadataPool)
19 19
20 20 using Properties = QVariantHash;
21 21
22 22 // ///////// //
23 23 // Constants //
24 24 // ///////// //
25 25
26 26 /// Max number of operations to generate
27 27 extern const QString NB_MAX_OPERATIONS_PROPERTY;
28 28
29 /// Max number of sync groups to create through operations
30 extern const QString NB_MAX_SYNC_GROUPS_PROPERTY;
31
29 32 /// Max number of variables to manipulate through operations
30 33 extern const QString NB_MAX_VARIABLES_PROPERTY;
31 34
32 35 /// Set of operations available for the test
33 36 extern const QString AVAILABLE_OPERATIONS_PROPERTY;
34 37
35 38 /// Tolerance used for variable's cache (in ratio)
36 39 extern const QString CACHE_TOLERANCE_PROPERTY;
37 40
38 41 /// Range with which the timecontroller is initialized
39 42 extern const QString INITIAL_RANGE_PROPERTY;
40 43
41 44 /// Max range that an operation can reach
42 45 extern const QString MAX_RANGE_PROPERTY;
43 46
44 47 /// Set of metadata that can be associated to a variable
45 48 extern const QString METADATA_POOL_PROPERTY;
46 49
47 50 /// Provider used to retrieve data
48 51 extern const QString PROVIDER_PROPERTY;
49 52
50 53 /// Time left for an operation to execute
51 54 extern const QString OPERATION_DELAY_PROPERTY;
52 55
53 56 /// Validators used to validate an operation
54 57 extern const QString VALIDATORS_PROPERTY;
55 58
56 59 // /////// //
57 60 // Structs //
58 61 // /////// //
59 62
60 63 class Variable;
61 64 struct VariableState {
62 65 std::shared_ptr<Variable> m_Variable{nullptr};
63 66 SqpRange m_Range{INVALID_RANGE};
64 67 };
65 68
66 69 using VariableId = int;
67 70 using VariablesPool = std::map<VariableId, VariableState>;
68 71
69 72 /**
70 73 * Defines a synchronization group for a fuzzing state. A group reports the variables synchronized
71 74 * with each other, and the current range of the group (i.e. range of the last synchronized variable
72 75 * that has been moved)
73 76 */
74 77 struct SyncGroup {
75 78 std::set<VariableId> m_Variables{};
76 79 SqpRange m_Range{INVALID_RANGE};
77 80 };
78 81
79 82 using SyncGroupId = QUuid;
80 83 using SyncGroupsPool = std::map<SyncGroupId, SyncGroup>;
81 84
82 85 /**
83 86 * Defines a current state during a fuzzing state. It contains all the variables manipulated during
84 87 * the test, as well as the synchronization status of these variables.
85 88 */
86 89 struct FuzzingState {
87 90 const SyncGroup &syncGroup(SyncGroupId id) const;
88 91 SyncGroup &syncGroup(SyncGroupId id);
89 92
90 93 const VariableState &variableState(VariableId id) const;
91 94 VariableState &variableState(VariableId id);
92 95
93 96
94 97 VariablesPool m_VariablesPool;
95 98 SyncGroupsPool m_SyncGroupsPool;
96 99 };
97 100
98 101 #endif // SCIQLOP_FUZZINGDEFS_H
@@ -1,328 +1,344
1 1 #include "FuzzingDefs.h"
2 2 #include "FuzzingOperations.h"
3 3 #include "FuzzingUtils.h"
4 4 #include "FuzzingValidators.h"
5 5
6 6 #include "AmdaProvider.h"
7 7
8 8 #include <Network/NetworkController.h>
9 9 #include <Settings/SqpSettingsDefs.h>
10 10 #include <SqpApplication.h>
11 11 #include <Time/TimeController.h>
12 12 #include <Variable/Variable.h>
13 13 #include <Variable/VariableController.h>
14 14
15 15 #include <QLoggingCategory>
16 16 #include <QObject>
17 17 #include <QtTest>
18 18
19 19 #include <memory>
20 20
21 21 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
22 22
23 23 namespace {
24 24
25 25 // /////// //
26 26 // Aliases //
27 27 // /////// //
28 28
29 29 using Weight = double;
30 30 using Weights = std::vector<Weight>;
31 31
32 32 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
33 33 using VariablesOperations = std::vector<VariableOperation>;
34 34
35 35 using WeightedOperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, Weight>;
36 36 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
37 37
38 38 // ///////// //
39 39 // Constants //
40 40 // ///////// //
41 41
42 42 // Defaults values used when the associated properties have not been set for the test
43 43 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
44 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
44 45 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
45 46 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(WeightedOperationsTypes{
46 47 {FuzzingOperationType::CREATE, 1.},
47 48 {FuzzingOperationType::DELETE, 0.1}, // Delete operation is less frequent
48 49 {FuzzingOperationType::PAN_LEFT, 1.},
49 50 {FuzzingOperationType::PAN_RIGHT, 1.},
50 51 {FuzzingOperationType::ZOOM_IN, 1.},
51 52 {FuzzingOperationType::ZOOM_OUT, 1.}});
52 53 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
53 54
54 55 /// Delay between each operation (in ms)
55 56 const auto OPERATION_DELAY_DEFAULT_VALUE = 3000;
56 57
57 58 /// Validators for the tests (executed in the order in which they're defined)
58 59 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
59 60 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
60 61
61 62 // /////// //
62 63 // Methods //
63 64 // /////// //
64 65
65 66 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
66 67 /// pairs that are valid (i.e. operation that can be executed on variable)
67 68 std::pair<VariablesOperations, Weights>
68 69 availableOperations(const FuzzingState &fuzzingState, const WeightedOperationsPool &operationsPool)
69 70 {
70 71 VariablesOperations result{};
71 72 Weights weights{};
72 73
73 74 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
74 75 auto variableId = variablesPoolEntry.first;
75 76
76 77 for (const auto &operationsPoolEntry : operationsPool) {
77 78 auto operation = operationsPoolEntry.first;
78 79 auto weight = operationsPoolEntry.second;
79 80
80 81 // A pair is valid if the current operation can be executed on the current variable
81 82 if (operation->canExecute(variableId, fuzzingState)) {
82 83 result.push_back({variableId, operation});
83 84 weights.push_back(weight);
84 85 }
85 86 }
86 87 }
87 88
88 89 return {result, weights};
89 90 }
90 91
91 92 WeightedOperationsPool createOperationsPool(const WeightedOperationsTypes &types)
92 93 {
93 94 WeightedOperationsPool result{};
94 95
95 96 std::transform(
96 97 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
97 98 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
98 99 });
99 100
100 101 return result;
101 102 }
102 103
103 104 Validators createValidators(const ValidatorsTypes &types)
104 105 {
105 106 Validators result{};
106 107
107 108 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
108 109 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
109 110
110 111 return result;
111 112 }
112 113
113 114 /**
114 115 * Validates all the variables' states passed in parameter, according to a set of validators
115 116 * @param variablesPool the variables' states
116 117 * @param validators the validators used for validation
117 118 */
118 119 void validate(const VariablesPool &variablesPool, const Validators &validators)
119 120 {
120 121 for (const auto &variablesPoolEntry : variablesPool) {
121 122 auto variableId = variablesPoolEntry.first;
122 123 const auto &variableState = variablesPoolEntry.second;
123 124
124 125 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
125 126 : QStringLiteral("null variable");
126 127 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
127 128 << variableId << "(" << variableMessage << ")...";
128 129
129 130 for (const auto &validator : validators) {
130 131 validator->validate(VariableState{variableState});
131 132 }
132 133
133 134 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
134 135 }
135 136 }
136 137
137 138 /**
138 139 * Class to run random tests
139 140 */
140 141 class FuzzingTest {
141 142 public:
142 143 explicit FuzzingTest(VariableController &variableController, Properties properties)
143 144 : m_VariableController{variableController},
144 145 m_Properties{std::move(properties)},
145 146 m_FuzzingState{}
146 147 {
147 148 // Inits variables pool: at init, all variables are null
148 149 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
149 150 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
150 151 }
152
153 // Inits sync groups and registers them into the variable controller
154 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
155 auto syncGroupId = SyncGroupId::createUuid();
156 variableController.onAddSynchronizationGroupId(syncGroupId);
157 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
158 }
151 159 }
152 160
153 161 void execute()
154 162 {
155 163 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
156 164 << nbMaxVariables() << "variable(s)...";
157 165
158 166 auto canExecute = true;
159 167 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
160 168 // Retrieves all operations that can be executed in the current context
161 169 VariablesOperations variableOperations{};
162 170 Weights weights{};
163 171 std::tie(variableOperations, weights)
164 172 = availableOperations(m_FuzzingState, operationsPool());
165 173
166 174 canExecute = !variableOperations.empty();
167 175 if (canExecute) {
168 176 // Of the operations available, chooses a random operation and executes it
169 177 auto variableOperation
170 178 = RandomGenerator::instance().randomChoice(variableOperations, weights);
171 179
172 180 auto variableId = variableOperation.first;
173 181 auto fuzzingOperation = variableOperation.second;
174 182
175 183 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
176 184 m_Properties);
177 185 QTest::qWait(operationDelay());
178 186
179 187 // Validates variables
180 188 validate(m_FuzzingState.m_VariablesPool, validators());
181 189 }
182 190 else {
183 191 qCInfo(LOG_TestAmdaFuzzing()).noquote()
184 192 << "No more operations are available, the execution of the test will stop...";
185 193 }
186 194 }
187 195
188 196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
189 197 }
190 198
191 199 private:
192 200 int nbMaxOperations() const
193 201 {
194 202 static auto result
195 203 = m_Properties.value(NB_MAX_OPERATIONS_PROPERTY, NB_MAX_OPERATIONS_DEFAULT_VALUE)
196 204 .toInt();
197 205 return result;
198 206 }
199 207
208 int nbMaxSyncGroups() const
209 {
210 static auto result
211 = m_Properties.value(NB_MAX_SYNC_GROUPS_PROPERTY, NB_MAX_SYNC_GROUPS_DEFAULT_VALUE)
212 .toInt();
213 return result;
214 }
215
200 216 int nbMaxVariables() const
201 217 {
202 218 static auto result
203 219 = m_Properties.value(NB_MAX_VARIABLES_PROPERTY, NB_MAX_VARIABLES_DEFAULT_VALUE).toInt();
204 220 return result;
205 221 }
206 222
207 223 int operationDelay() const
208 224 {
209 225 static auto result
210 226 = m_Properties.value(OPERATION_DELAY_PROPERTY, OPERATION_DELAY_DEFAULT_VALUE).toInt();
211 227 return result;
212 228 }
213 229
214 230 WeightedOperationsPool operationsPool() const
215 231 {
216 232 static auto result = createOperationsPool(
217 233 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
218 234 .value<WeightedOperationsTypes>());
219 235 return result;
220 236 }
221 237
222 238 Validators validators() const
223 239 {
224 240 static auto result
225 241 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
226 242 .value<ValidatorsTypes>());
227 243 return result;
228 244 }
229 245
230 246 VariableController &m_VariableController;
231 247 Properties m_Properties;
232 248 FuzzingState m_FuzzingState;
233 249 };
234 250
235 251 } // namespace
236 252
237 253 class TestAmdaFuzzing : public QObject {
238 254 Q_OBJECT
239 255
240 256 private slots:
241 257 /// Input data for @sa testFuzzing()
242 258 void testFuzzing_data();
243 259 void testFuzzing();
244 260 };
245 261
246 262 void TestAmdaFuzzing::testFuzzing_data()
247 263 {
248 264 // ////////////// //
249 265 // Test structure //
250 266 // ////////////// //
251 267
252 268 QTest::addColumn<Properties>("properties"); // Properties for random test
253 269
254 270 // ////////// //
255 271 // Test cases //
256 272 // ////////// //
257 273
258 274 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
259 275 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
260 276
261 277 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
262 278 // QVariant
263 279 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
264 280
265 281 QTest::newRow("fuzzingTest") << Properties{
266 282 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
267 283 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
268 284 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
269 285 }
270 286
271 287 void TestAmdaFuzzing::testFuzzing()
272 288 {
273 289 QFETCH(Properties, properties);
274 290
275 291 // Sets cache property
276 292 QSettings settings{};
277 293 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
278 294 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
279 295 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
280 296
281 297 auto &variableController = sqpApp->variableController();
282 298 auto &timeController = sqpApp->timeController();
283 299
284 300 // Generates random initial range (bounded to max range)
285 301 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
286 302 .value<SqpRange>();
287 303
288 304 QVERIFY(maxRange != INVALID_RANGE);
289 305
290 306 auto initialRangeStart
291 307 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
292 308 auto initialRangeEnd
293 309 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
294 310 if (initialRangeStart > initialRangeEnd) {
295 311 std::swap(initialRangeStart, initialRangeEnd);
296 312 }
297 313
298 314 // Sets initial range on time controller
299 315 SqpRange initialRange{initialRangeStart, initialRangeEnd};
300 316 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
301 317 timeController.onTimeToUpdate(initialRange);
302 318 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
303 319
304 320 FuzzingTest test{variableController, properties};
305 321 test.execute();
306 322 }
307 323
308 324 int main(int argc, char *argv[])
309 325 {
310 326 QLoggingCategory::setFilterRules(
311 327 "*.warning=false\n"
312 328 "*.info=false\n"
313 329 "*.debug=false\n"
314 330 "FuzzingOperations.info=true\n"
315 331 "FuzzingValidators.info=true\n"
316 332 "TestAmdaFuzzing.info=true\n");
317 333
318 334 SqpApplication app{argc, argv};
319 335 SqpApplication::setOrganizationName("LPP");
320 336 SqpApplication::setOrganizationDomain("lpp.fr");
321 337 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
322 338 app.setAttribute(Qt::AA_Use96Dpi, true);
323 339 TestAmdaFuzzing testObject{};
324 340 QTEST_SET_MAIN_SOURCE_PATH
325 341 return QTest::qExec(&testObject, argc, argv);
326 342 }
327 343
328 344 #include "TestAmdaFuzzing.moc"
General Comments 0
You need to be logged in to leave comments. Login now