##// END OF EJS Templates
Adds the ability to force an acquisition pending for an operation (1)...
Adds the ability to force an acquisition pending for an operation (1) Creates struct that contains operation properties: - its weight - the flag to force acquisition waiting

File last commit:

r1249:b9a47ff1b9cc
r1249:b9a47ff1b9cc
Show More
TestAmdaFuzzing.cpp
385 lines | 14.1 KiB | text/x-c | CppLexer
/ plugins / amda / tests / TestAmdaFuzzing.cpp
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1201 #include "FuzzingDefs.h"
Alexandre Leroux
Defines fuzzing operations...
r1202 #include "FuzzingOperations.h"
Alexandre Leroux
Adds utility class to get random values
r1206 #include "FuzzingUtils.h"
Alexandre Leroux
Adds validators to the fuzzing test...
r1228 #include "FuzzingValidators.h"
Alexandre Leroux
Adds utility class to get random values
r1206
Alexandre Leroux
Adds initial test case
r1210 #include "AmdaProvider.h"
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (1)...
r1246 #include <Common/SignalWaiter.h>
Alexandre Leroux
Inits test structure
r1199 #include <Network/NetworkController.h>
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1224 #include <Settings/SqpSettingsDefs.h>
Alexandre Leroux
Inits test structure
r1199 #include <SqpApplication.h>
#include <Time/TimeController.h>
Alexandre Leroux
Defines VariableState struct (3)...
r1222 #include <Variable/Variable.h>
Alexandre Leroux
Inits test structure
r1199 #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
r1245 /**
* 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
r1199 namespace {
Alexandre Leroux
Defines fuzzing operations...
r1202 // /////// //
// Aliases //
// /////// //
Alexandre Leroux
(Minor) Defines macro to simplify writing getters in the FuzzingTest class
r1245 using IntPair = std::pair<int, int>;
Alexandre Leroux
Adds weights to operations (2)...
r1216 using Weight = double;
using Weights = std::vector<Weight>;
Alexandre Leroux
Defines variable pool...
r1203
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 struct OperationProperty {
Weight m_Weight{1.};
bool m_WaitAcquisition{false};
};
Alexandre Leroux
Implements test execute() method...
r1205 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)...
r1249 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
Alexandre Leroux
Adds validators to the fuzzing test...
r1228 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
Alexandre Leroux
Defines variable pool...
r1203
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1201 // ///////// //
// 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)...
r1248 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1201 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
Alexandre Leroux
Sets the number of sync groups to create for fuzzing tests
r1237 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
Alexandre Leroux
Adds "number of operations" and "number of variables" properties for the tests
r1201 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
Alexandre Leroux
Adds delete operation
r1225 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(WeightedOperationsTypes{
{FuzzingOperationType::CREATE, 1.},
{FuzzingOperationType::DELETE, 0.1}, // Delete operation is less frequent
{FuzzingOperationType::PAN_LEFT, 1.},
{FuzzingOperationType::PAN_RIGHT, 1.},
{FuzzingOperationType::ZOOM_IN, 1.},
Alexandre Leroux
Creates sync and desync operations and adds them to the fuzzing tests
r1238 {FuzzingOperationType::ZOOM_OUT, 1.},
{FuzzingOperationType::SYNCHRONIZE, 0.8},
{FuzzingOperationType::DESYNCHRONIZE, 0.4}});
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1224 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
Alexandre Leroux
Implements move operations (3)...
r1219
Alexandre Leroux
Randomizes the time to wait between each operations (defines min/max delays)
r1243 /// 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
r1209
Alexandre Leroux
Adds validators to the fuzzing test...
r1228 /// 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)
r1244 /// 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...
r1205 // /////// //
// 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)...
r1249 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
const OperationsPool &operationsPool)
Alexandre Leroux
Implements test execute() method...
r1205 {
VariablesOperations result{};
Alexandre Leroux
Adds weights to operations (2)...
r1216 Weights weights{};
Alexandre Leroux
Implements test execute() method...
r1205
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1236 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
Alexandre Leroux
Implements test execute() method...
r1205 auto variableId = variablesPoolEntry.first;
Alexandre Leroux
Adds weights to operations (2)...
r1216 for (const auto &operationsPoolEntry : operationsPool) {
auto operation = operationsPoolEntry.first;
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 auto operationProperty = operationsPoolEntry.second;
Alexandre Leroux
Adds weights to operations (2)...
r1216
Alexandre Leroux
Implements test execute() method...
r1205 // 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
r1236 if (operation->canExecute(variableId, fuzzingState)) {
Alexandre Leroux
Implements test execute() method...
r1205 result.push_back({variableId, operation});
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 weights.push_back(operationProperty.m_Weight);
Alexandre Leroux
Implements test execute() method...
r1205 }
}
}
Alexandre Leroux
Adds weights to operations (2)...
r1216 return {result, weights};
Alexandre Leroux
Implements test execute() method...
r1205 }
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 OperationsPool createOperationsPool(const OperationsTypes &types)
Alexandre Leroux
Defines operations pool...
r1204 {
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 OperationsPool result{};
Alexandre Leroux
Defines operations pool...
r1204
Alexandre Leroux
Adds weights to operations (2)...
r1216 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...
r1204
return result;
}
Alexandre Leroux
Adds validators to the fuzzing test...
r1228 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
r1229 /**
* 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
r1199 /**
* Class to run random tests
*/
class FuzzingTest {
public:
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200 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
r1236 m_FuzzingState{}
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200 {
Alexandre Leroux
Defines variable pool...
r1203 // 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
r1236 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
Alexandre Leroux
Defines variable pool...
r1203 }
Alexandre Leroux
Sets the number of sync groups to create for fuzzing tests
r1237
// 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...
r1200 }
Alexandre Leroux
Inits test structure
r1199 void execute()
{
Alexandre Leroux
Some fixes...
r1223 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
r1201
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1244
// 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)...
r1248 << "Next validation in " << nextValidationCounter << "operation(s)...";
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1244 };
updateValidationCounter();
Alexandre Leroux
Implements test execute() method...
r1205 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)...
r1216 VariablesOperations variableOperations{};
Weights weights{};
std::tie(variableOperations, weights)
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1236 = availableOperations(m_FuzzingState, operationsPool());
Alexandre Leroux
Implements test execute() method...
r1205
canExecute = !variableOperations.empty();
if (canExecute) {
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1244 --nextValidationCounter;
Alexandre Leroux
Implements test execute() method...
r1205 // Of the operations available, chooses a random operation and executes it
auto variableOperation
Alexandre Leroux
Adds weights to operations (2)...
r1216 = RandomGenerator::instance().randomChoice(variableOperations, weights);
Alexandre Leroux
Implements test execute() method...
r1205
auto variableId = variableOperation.first;
auto fuzzingOperation = variableOperation.second;
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1248 auto waitAcquisition = nextValidationCounter == 0;
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1236 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
m_Properties);
Alexandre Leroux
Randomizes the time to wait between each operations (defines min/max delays)
r1243
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1248 if (waitAcquisition) {
qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
acquisitionTimeout());
Alexandre Leroux
Calls validation after each operation
r1229
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1248 // Validates variables
Alexandre Leroux
Randomizes the number of operations to wait between calling validation (defines min/max frequencies)
r1244 validate(m_FuzzingState.m_VariablesPool, validators());
updateValidationCounter();
}
Alexandre Leroux
Wait for the end of an acquisition to validate an operation (3)...
r1248 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...
r1205 }
else {
Alexandre Leroux
Some fixes...
r1223 qCInfo(LOG_TestAmdaFuzzing()).noquote()
Alexandre Leroux
Implements test execute() method...
r1205 << "No more operations are available, the execution of the test will stop...";
}
}
Alexandre Leroux
Some fixes...
r1223 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
Alexandre Leroux
Inits test structure
r1199 }
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200
private:
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 OperationsPool operationsPool() const
Alexandre Leroux
Defines operations pool...
r1204 {
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)...
r1249 .value<OperationsTypes>());
Alexandre Leroux
Defines operations pool...
r1204 return result;
}
Alexandre Leroux
Adds validators to the fuzzing test...
r1228 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
r1245 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)
r1244
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200 VariableController &m_VariableController;
Properties m_Properties;
Alexandre Leroux
Passes FuzzingState and variable id instead VariableState to the methods of operations
r1236 FuzzingState m_FuzzingState;
Alexandre Leroux
Inits test structure
r1199 };
} // namespace
Alexandre Leroux
Adds the ability to force an acquisition pending for an operation (1)...
r1249 Q_DECLARE_METATYPE(OperationsTypes)
Alexandre Leroux
Inits test structure
r1199 class TestAmdaFuzzing : public QObject {
Q_OBJECT
private slots:
/// Input data for @sa testFuzzing()
void testFuzzing_data();
void testFuzzing();
};
void TestAmdaFuzzing::testFuzzing_data()
{
// ////////////// //
// Test structure //
// ////////////// //
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200 QTest::addColumn<Properties>("properties"); // Properties for random test
Alexandre Leroux
Inits test structure
r1199
// ////////// //
// Test cases //
// ////////// //
Alexandre Leroux
Adds initial test case
r1210 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
r1199 }
void TestAmdaFuzzing::testFuzzing()
{
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200 QFETCH(Properties, properties);
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1224 // 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
r1199 auto &variableController = sqpApp->variableController();
auto &timeController = sqpApp->timeController();
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1209 // 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...
r1223 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1209 timeController.onTimeToUpdate(initialRange);
Alexandre Leroux
Some fixes...
r1223 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
Alexandre Leroux
Completes fuzzing test structure by setting initial range for the time controller
r1209
Alexandre Leroux
Adds variable controller and properties to test structure...
r1200 FuzzingTest test{variableController, properties};
Alexandre Leroux
Inits test structure
r1199 test.execute();
}
int main(int argc, char *argv[])
{
QLoggingCategory::setFilterRules(
"*.warning=false\n"
"*.info=false\n"
"*.debug=false\n"
"FuzzingOperations.info=true\n"
Alexandre Leroux
Adds validators to the fuzzing test...
r1228 "FuzzingValidators.info=true\n"
Alexandre Leroux
Inits test structure
r1199 "TestAmdaFuzzing.info=true\n");
SqpApplication app{argc, argv};
Alexandre Leroux
Adds the ability to set cache tolerance for tests
r1224 SqpApplication::setOrganizationName("LPP");
SqpApplication::setOrganizationDomain("lpp.fr");
SqpApplication::setApplicationName("SciQLop-TestFuzzing");
Alexandre Leroux
Inits test structure
r1199 app.setAttribute(Qt::AA_Use96Dpi, true);
TestAmdaFuzzing testObject{};
QTEST_SET_MAIN_SOURCE_PATH
return QTest::qExec(&testObject, argc, argv);
}
#include "TestAmdaFuzzing.moc"