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