##// END OF EJS Templates
Fixes on fuzzing tests
Fixes on fuzzing tests

File last commit:

r1274:6015d1ab6800
r1274:6015d1ab6800
Show More
TestAmdaFuzzing.cpp
395 lines | 14.7 KiB | text/x-c | CppLexer
/ plugins / amda / tests / TestAmdaFuzzing.cpp
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1170 #include "FuzzingDefs.h"
Alexandre Leroux
Defines fuzzing operations...
r1171 #include "FuzzingOperations.h"
Alexandre Leroux
Adds utility class to get random values
r1175 #include "FuzzingUtils.h"
Alexandre Leroux
Adds validators to the fuzzing test...
r1195 #include "FuzzingValidators.h"
Alexandre Leroux
Adds utility class to get random values
r1175
Alexandre Leroux
Adds initial test case
r1179 #include "AmdaProvider.h"
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (1)...
r1213 #include <Common/SignalWaiter.h>
Alexandre Leroux
Inits test structure
r1168 #include <Network/NetworkController.h>
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1191 #include <Settings/SqpSettingsDefs.h>
Alexandre Leroux
Inits test structure
r1168 #include <SqpApplication.h>
#include <Time/TimeController.h>
Alexandre Leroux
Defines VariableState struct (3)...
r1189 #include <Variable/Variable.h>
Alexandre Leroux
Inits test structure
r1168 #include <Variable/VariableController.h>
#include <QLoggingCategory>
#include <QObject>
#include <QtTest>
#include <memory>
Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
Alexandre Leroux
(Minor) Defines macro to simplify writing getters in the FuzzingTest class
r1212 /**
* Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
* attribute that is initialized by searching in properties the property and use a default value if
* it's not present. Macro arguments are:
* - GETTER_NAME : name of the getter
* - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
* default value ({PROPERTY_NAME}_DEFAULT_VALUE)
* - TYPE : return type of the getter
*/
// clang-format off
#define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
TYPE GETTER_NAME() const \
{ \
static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
return result; \
} \
// clang-format on
Alexandre Leroux
Inits test structure
r1168 namespace {
Alexandre Leroux
Defines fuzzing operations...
r1171 // /////// //
// Aliases //
// /////// //
Alexandre Leroux
(Minor) Defines macro to simplify writing getters in the FuzzingTest class
r1212 using IntPair = std::pair<int, int>;
Alexandre Leroux
Adds weights to operations (2)...
r1183 using Weight = double;
using Weights = std::vector<Weight>;
Alexandre Leroux
Defines variable pool...
r1172
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 struct OperationProperty {
Weight m_Weight{1.};
bool m_WaitAcquisition{false};
};
Alexandre Leroux
Implements test execute() method...
r1174 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
using VariablesOperations = std::vector<VariableOperation>;
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
Alexandre Leroux
Adds validators to the fuzzing test...
r1195 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
Alexandre Leroux
Defines variable pool...
r1172
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1170 // ///////// //
// Constants //
// ///////// //
// Defaults values used when the associated properties have not been set for the test
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1215 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1170 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
Alexandre Leroux
Sets the number of sync groups to create for fuzzing tests
r1204 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1170 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (3)...
r1218 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
{FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
{FuzzingOperationType::PAN_LEFT, {1.}},
{FuzzingOperationType::PAN_RIGHT, {1.}},
{FuzzingOperationType::ZOOM_IN, {1.}},
{FuzzingOperationType::ZOOM_OUT, {1.}},
{FuzzingOperationType::SYNCHRONIZE, {0.8}},
{FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1191 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
Alexandre Leroux
Implements move operations (3)...
r1186
Alexandre Leroux
Randomizes the time to wait between each operations (defines min/max delays)
r1210 /// Min/max delays between each operation (in ms)
const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1178
Alexandre Leroux
Adds validators to the fuzzing test...
r1195 /// Validators for the tests (executed in the order in which they're defined)
const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1211 /// Min/max number of operations to execute before calling validation
const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
Alexandre Leroux
Implements test execute() method...
r1174 // /////// //
// Methods //
// /////// //
/// Goes through the variables pool and operations pool to determine the set of {variable/operation}
/// pairs that are valid (i.e. operation that can be executed on variable)
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
const OperationsPool &operationsPool)
Alexandre Leroux
Implements test execute() method...
r1174 {
VariablesOperations result{};
Alexandre Leroux
Adds weights to operations (2)...
r1183 Weights weights{};
Alexandre Leroux
Implements test execute() method...
r1174
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
Alexandre Leroux
Implements test execute() method...
r1174 auto variableId = variablesPoolEntry.first;
Alexandre Leroux
Adds weights to operations (2)...
r1183 for (const auto &operationsPoolEntry : operationsPool) {
auto operation = operationsPoolEntry.first;
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 auto operationProperty = operationsPoolEntry.second;
Alexandre Leroux
Adds weights to operations (2)...
r1183
Alexandre Leroux
Implements test execute() method...
r1174 // A pair is valid if the current operation can be executed on the current variable
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 if (operation->canExecute(variableId, fuzzingState)) {
Alexandre Leroux
Implements test execute() method...
r1174 result.push_back({variableId, operation});
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 weights.push_back(operationProperty.m_Weight);
Alexandre Leroux
Implements test execute() method...
r1174 }
}
}
Alexandre Leroux
Adds weights to operations (2)...
r1183 return {result, weights};
Alexandre Leroux
Implements test execute() method...
r1174 }
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 OperationsPool createOperationsPool(const OperationsTypes &types)
Alexandre Leroux
Defines operations pool...
r1173 {
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 OperationsPool result{};
Alexandre Leroux
Defines operations pool...
r1173
Alexandre Leroux
Adds weights to operations (2)...
r1183 std::transform(
types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
});
Alexandre Leroux
Defines operations pool...
r1173
return result;
}
Alexandre Leroux
Adds validators to the fuzzing test...
r1195 Validators createValidators(const ValidatorsTypes &types)
{
Validators result{};
std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
[](const auto &type) { return FuzzingValidatorFactory::create(type); });
return result;
}
Alexandre Leroux
Calls validation after each operation
r1196 /**
* Validates all the variables' states passed in parameter, according to a set of validators
* @param variablesPool the variables' states
* @param validators the validators used for validation
*/
void validate(const VariablesPool &variablesPool, const Validators &validators)
{
for (const auto &variablesPoolEntry : variablesPool) {
auto variableId = variablesPoolEntry.first;
const auto &variableState = variablesPoolEntry.second;
auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
: QStringLiteral("null variable");
qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
<< variableId << "(" << variableMessage << ")...";
for (const auto &validator : validators) {
validator->validate(VariableState{variableState});
}
qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
}
}
Alexandre Leroux
Inits test structure
r1168 /**
* Class to run random tests
*/
class FuzzingTest {
public:
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 explicit FuzzingTest(VariableController &variableController, Properties properties)
: m_VariableController{variableController},
m_Properties{std::move(properties)},
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 m_FuzzingState{}
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 {
Alexandre Leroux
Defines variable pool...
r1172 // Inits variables pool: at init, all variables are null
for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
Alexandre Leroux
Defines variable pool...
r1172 }
Alexandre Leroux
Sets the number of sync groups to create for fuzzing tests
r1204
// Inits sync groups and registers them into the variable controller
for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
auto syncGroupId = SyncGroupId::createUuid();
variableController.onAddSynchronizationGroupId(syncGroupId);
m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
}
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 }
Alexandre Leroux
Inits test structure
r1168 void execute()
{
Alexandre Leroux
Some fixes...
r1190 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
<< nbMaxVariables() << "variable(s)...";
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1170
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1211
// Inits the count of the number of operations before the next validation
int nextValidationCounter = 0;
auto updateValidationCounter = [this, &nextValidationCounter]() {
nextValidationCounter = RandomGenerator::instance().generateInt(
validationFrequencies().first, validationFrequencies().second);
qCInfo(LOG_TestAmdaFuzzing()).noquote()
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1215 << "Next validation in " << nextValidationCounter << "operation(s)...";
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1211 };
updateValidationCounter();
Alexandre Leroux
Implements test execute() method...
r1174 auto canExecute = true;
for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
// Retrieves all operations that can be executed in the current context
Alexandre Leroux
Adds weights to operations (2)...
r1183 VariablesOperations variableOperations{};
Weights weights{};
std::tie(variableOperations, weights)
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 = availableOperations(m_FuzzingState, operationsPool());
Alexandre Leroux
Implements test execute() method...
r1174
canExecute = !variableOperations.empty();
if (canExecute) {
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1211 --nextValidationCounter;
Alexandre Leroux
Implements test execute() method...
r1174 // Of the operations available, chooses a random operation and executes it
auto variableOperation
Alexandre Leroux
Adds weights to operations (2)...
r1183 = RandomGenerator::instance().randomChoice(variableOperations, weights);
Alexandre Leroux
Implements test execute() method...
r1174
auto variableId = variableOperation.first;
auto fuzzingOperation = variableOperation.second;
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (2)...
r1217 auto waitAcquisition = nextValidationCounter == 0
|| operationsPool().at(fuzzingOperation).m_WaitAcquisition;
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1215
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
m_Properties);
Alexandre Leroux
Randomizes the time to wait between each operations (defines min/max delays)
r1210
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1215 if (waitAcquisition) {
qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
acquisitionTimeout());
Alexandre Leroux
Calls validation after each operation
r1196
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1215 // Validates variables
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (2)...
r1217 if (nextValidationCounter == 0) {
validate(m_FuzzingState.m_VariablesPool, validators());
updateValidationCounter();
}
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1211 }
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1215 else {
// Delays the next operation with a randomly generated time
auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
operationDelays().second);
qCDebug(LOG_TestAmdaFuzzing())
<< "Waiting " << delay << "ms before the next operation...";
QTest::qWait(delay);
}
Alexandre Leroux
Implements test execute() method...
r1174 }
else {
Alexandre Leroux
Some fixes...
r1190 qCInfo(LOG_TestAmdaFuzzing()).noquote()
Alexandre Leroux
Implements test execute() method...
r1174 << "No more operations are available, the execution of the test will stop...";
}
}
Alexandre Leroux
Some fixes...
r1190 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
Alexandre Leroux
Inits test structure
r1168 }
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169
private:
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 OperationsPool operationsPool() const
Alexandre Leroux
Defines operations pool...
r1173 {
static auto result = createOperationsPool(
m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 .value<OperationsTypes>());
Alexandre Leroux
Defines operations pool...
r1173 return result;
}
Alexandre Leroux
Adds validators to the fuzzing test...
r1195 Validators validators() const
{
static auto result
= createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
.value<ValidatorsTypes>());
return result;
}
Alexandre Leroux
(Minor) Defines macro to simplify writing getters in the FuzzingTest class
r1212 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1211
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 VariableController &m_VariableController;
Properties m_Properties;
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1203 FuzzingState m_FuzzingState;
Alexandre Leroux
Inits test structure
r1168 };
} // namespace
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1216 Q_DECLARE_METATYPE(OperationsTypes)
Alexandre Leroux
Inits test structure
r1168 class TestAmdaFuzzing : public QObject {
Q_OBJECT
private slots:
/// Input data for @sa testFuzzing()
void testFuzzing_data();
void testFuzzing();
};
void TestAmdaFuzzing::testFuzzing_data()
{
Alexandre Leroux
Disables fuzzing tests by default
r1220 // Note: Comment this line to run fuzzing tests
QSKIP("Fuzzing tests are disabled by default");
Alexandre Leroux
Inits test structure
r1168 // ////////////// //
// Test structure //
// ////////////// //
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 QTest::addColumn<Properties>("properties"); // Properties for random test
Alexandre Leroux
Inits test structure
r1168
// ////////// //
// Test cases //
// ////////// //
Alexandre Leroux
Adds initial test case
r1179 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
// Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
// QVariant
std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
QTest::newRow("fuzzingTest") << Properties{
{MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
{METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
{PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
Alexandre Leroux
Inits test structure
r1168 }
void TestAmdaFuzzing::testFuzzing()
{
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 QFETCH(Properties, properties);
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1191 // Sets cache property
QSettings settings{};
auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
Alexandre Leroux
Inits test structure
r1168 auto &variableController = sqpApp->variableController();
auto &timeController = sqpApp->timeController();
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1178 // Generates random initial range (bounded to max range)
auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
.value<SqpRange>();
QVERIFY(maxRange != INVALID_RANGE);
auto initialRangeStart
= RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
auto initialRangeEnd
= RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
if (initialRangeStart > initialRangeEnd) {
std::swap(initialRangeStart, initialRangeEnd);
}
// Sets initial range on time controller
SqpRange initialRange{initialRangeStart, initialRangeEnd};
Alexandre Leroux
Some fixes...
r1190 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1178 timeController.onTimeToUpdate(initialRange);
Alexandre Leroux
Some fixes...
r1190 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1178
Alexandre Leroux
Adds variable controller and properties to test structure...
r1169 FuzzingTest test{variableController, properties};
Alexandre Leroux
Inits test structure
r1168 test.execute();
}
int main(int argc, char *argv[])
{
Alexandre Leroux
Fixes on fuzzing tests
r1274 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
// https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
Alexandre Leroux
Inits test structure
r1168 QLoggingCategory::setFilterRules(
"*.warning=false\n"
"*.info=false\n"
"*.debug=false\n"
"FuzzingOperations.info=true\n"
Alexandre Leroux
Adds validators to the fuzzing test...
r1195 "FuzzingValidators.info=true\n"
Alexandre Leroux
Inits test structure
r1168 "TestAmdaFuzzing.info=true\n");
SqpApplication app{argc, argv};
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1191 SqpApplication::setOrganizationName("LPP");
SqpApplication::setOrganizationDomain("lpp.fr");
SqpApplication::setApplicationName("SciQLop-TestFuzzing");
Alexandre Leroux
Inits test structure
r1168 app.setAttribute(Qt::AA_Use96Dpi, true);
TestAmdaFuzzing testObject{};
QTEST_SET_MAIN_SOURCE_PATH
return QTest::qExec(&testObject, argc, argv);
}
#include "TestAmdaFuzzing.moc"