de.ppi.deepsampler.persistence.api.PersistentSampleManager Maven / Gradle / Ivy
Show all versions of deepsampler-persistence Show documentation
/*
* Copyright 2022 PPI AG (Hamburg, Germany)
* This program is made available under the terms of the MIT License.
*/
package de.ppi.deepsampler.persistence.api;
import de.ppi.deepsampler.core.api.Matchers;
import de.ppi.deepsampler.core.error.NoMatchingParametersFoundException;
import de.ppi.deepsampler.core.internal.SampleHandling;
import de.ppi.deepsampler.core.model.*;
import de.ppi.deepsampler.persistence.PersistentSamplerContext;
import de.ppi.deepsampler.persistence.bean.PolymorphicPersistentBean;
import de.ppi.deepsampler.persistence.bean.ReflectionTools;
import de.ppi.deepsampler.persistence.bean.ext.BeanConverterExtension;
import de.ppi.deepsampler.persistence.error.PersistenceException;
import de.ppi.deepsampler.persistence.error.NoMatchingSamplerFoundException;
import de.ppi.deepsampler.persistence.model.PersistentMethodCall;
import de.ppi.deepsampler.persistence.model.PersistentModel;
import de.ppi.deepsampler.persistence.model.PersistentSampleMethod;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;
/**
* The {@link PersistentSampleManager} is used to handle any provided {@link SourceManager} and to act
* as a bridge between this manager and the DeepSampler repositories.
*/
public class PersistentSampleManager {
private final List sourceManagerList = new ArrayList<>();
private final PersistentSamplerContext persistentSamplerContext = new PersistentSamplerContext();
public PersistentSampleManager(final SourceManager sourceManager) {
addSourceProvider(sourceManager);
}
/**
* Add another {@link SourceManager} to this builder.
*
* @param sourceManager the {@link SourceManager}
* @return this
*/
public PersistentSampleManager addSource(final SourceManager sourceManager) {
addSourceProvider(sourceManager);
return this;
}
/**
* Add a {@link BeanConverterExtension} to the sample manager.
*
* @param beanConverterExtension {@link BeanConverterExtension}
* @return this
*/
public PersistentSampleManager addBeanExtension(final BeanConverterExtension beanConverterExtension) {
persistentSamplerContext.addBeanConverterExtension(beanConverterExtension);
return this;
}
/**
* End of chain method: call {@link SourceManager#save(Map, PersistentSamplerContext)} on all added {@link SourceManager}s.
*/
public void recordSamples() {
for (final SourceManager sourceManager : sourceManagerList) {
sourceManager.save(ExecutionRepository.getInstance().getAll(), persistentSamplerContext);
}
}
/**
* End of chain method: call {@link SourceManager#load()} on all {@link SourceManager}s and write
* all loaded samples to the DeepSampler repositories.
*/
public void load() {
for (final SourceManager sourceManager : sourceManagerList) {
final PersistentModel persistentModel = sourceManager.load();
mergeSamplesFromPersistenceIntoSampleRepository(persistentModel);
}
if (SampleRepository.getInstance().isEmpty()) {
throw new PersistenceException("No Samples from the file could be matched to predefined sampled methods. " +
"Did you define sampled methods using Sample.of() in your test?");
}
}
/**
* This method merges the samples from the persistence (e.g. JSON-File) into manually defined Samplers and Samples. The order of the
* Samplers is defined by the Samplers in the test class or the compound. Samples from the file will be inserted in the list of Samples
* at the position where the matching samplers have been defined.
*
* E.G. Someone could now first define a matcher that matches only on a particular parameter of the value
* "Picard". The second matcher could then by anyString(). The first Sample would then be used only if the correct parameter is supplied and in all
* other cases the second sampler would be used.
*
* @param persistentSamples Contains the Samples from the persistence i.e. JSON
*/
private void mergeSamplesFromPersistenceIntoSampleRepository(final PersistentModel persistentSamples) {
SampleRepository sampleRepository = SampleRepository.getInstance();
List originallyDefinedSamplers = new ArrayList<>(sampleRepository.getSamples());
// This is a Set of all SampleIds from the persistence. Everytime, when a SampleId could be matched to a Sampler from the SampleRepository,
// the SampleId will be removed from this Set. The remaining SampleIds are unmatched and will be reported by an Exception.
Set unusedPersistentSampleIds = getPersistentSampleIds(persistentSamples);
for (int i = 0; i < sampleRepository.size(); i++) {
SampleDefinition sampler = sampleRepository.get(i);
if (!sampler.isMarkedForPersistence()) {
continue;
}
List mergedPersistentSamples = createSampleDefinitionForEachPersistentSample(persistentSamples, sampler);
sampleRepository.replace(i, mergedPersistentSamples);
i += mergedPersistentSamples.size() - 1;
unusedPersistentSampleIds = filterUsedSampleIds(unusedPersistentSampleIds, mergedPersistentSamples);
}
if (!unusedPersistentSampleIds.isEmpty()) {
throw new NoMatchingSamplerFoundException(unusedPersistentSampleIds, originallyDefinedSamplers);
}
}
private Set filterUsedSampleIds(Set unusedPersistentSampleIds, List mergedPersistentCalls) {
List mergedSampleIds = mergedPersistentCalls.stream().map(SampleDefinition::getSampleId).collect(Collectors.toList());
return unusedPersistentSampleIds.stream()
.filter(s -> !mergedSampleIds.contains(s))
.collect(Collectors.toSet());
}
private Set getPersistentSampleIds(PersistentModel persistentSamples) {
return persistentSamples.getSampleMethodToSampleMap().keySet().stream()
.map(PersistentSampleMethod::getSampleMethodId)
.collect(Collectors.toSet());
}
private List createSampleDefinitionForEachPersistentSample(PersistentModel persistentSamples, SampleDefinition sampler) {
List usedPersistentCalls = new ArrayList<>();
List unusedPersistentCalls = new ArrayList<>();
for (PersistentSampleMethod persistentSampleMethod : persistentSamples.getSampleMethodToSampleMap().keySet()) {
if (persistentSampleMethod.getSampleMethodId().equals(sampler.getSampleId())) {
List calls = persistentSamples.getSampleMethodToSampleMap().get(persistentSampleMethod).getAllCalls();
for (PersistentMethodCall call : calls) {
SampleDefinition combinedSampleDefinition = combinePersistentSampleAndDefinedSampler(sampler, persistentSampleMethod, call);
// We use the parameter values from combinedSampleDefinition because combinePersistentSampleAndDefinedSampler() unwraps the
// parameters from persistence containers.
Object[] actualParameterValues = combinedSampleDefinition.getParameterValues().toArray();
unusedPersistentCalls.add(combinedSampleDefinition);
if (SampleHandling.argumentsMatch(sampler, actualParameterValues)) {
usedPersistentCalls.add(combinedSampleDefinition);
unusedPersistentCalls.remove(combinedSampleDefinition);
}
}
}
}
if (!unusedPersistentCalls.isEmpty()) {
throw new NoMatchingParametersFoundException(unusedPersistentCalls);
}
return usedPersistentCalls;
}
private SampleDefinition combinePersistentSampleAndDefinedSampler(final SampleDefinition matchingSample, final PersistentSampleMethod persistentSampleMethod,
final PersistentMethodCall call) {
final List