net.thucydides.core.requirements.RequirementsServiceImplementation Maven / Gradle / Ivy
package net.thucydides.core.requirements;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.thucydides.core.ThucydidesSystemProperty;
import net.thucydides.core.guice.Injectors;
import net.thucydides.core.model.Release;
import net.thucydides.core.model.TestOutcome;
import net.thucydides.core.model.TestTag;
import net.thucydides.core.releases.ReleaseManager;
import net.thucydides.core.reports.html.ReportNameProvider;
import net.thucydides.core.requirements.model.Requirement;
import net.thucydides.core.statistics.service.AnnotationBasedTagProvider;
import net.thucydides.core.statistics.service.FeatureStoryTagProvider;
import net.thucydides.core.util.EnvironmentVariables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.EMPTY_LIST;
public class RequirementsServiceImplementation implements RequirementsService {
private List requirementsTagProviders;
private List requirements;
private List releases;
private Map> requirementAncestors;
private final EnvironmentVariables environmentVariables;
private static final Logger LOGGER = LoggerFactory.getLogger(RequirementsTagProvider.class);
private static final List NO_REQUIREMENTS = Lists.newArrayList();
private static final List LOW_PRIORITY_PROVIDERS =
ImmutableList.of(FileSystemRequirementsTagProvider.class.getCanonicalName(),
PackageAnnotationBasedTagProvider.class.getCanonicalName(),
AnnotationBasedTagProvider.class.getCanonicalName(),
FeatureStoryTagProvider.class.getCanonicalName()
);
public RequirementsServiceImplementation() {
environmentVariables = Injectors.getInjector().getProvider(EnvironmentVariables.class).get() ;
}
@Override
public List getRequirements() {
RequirementsMerger merger = new RequirementsMerger();
if (requirements == null) {
requirements = newArrayList();
for (RequirementsTagProvider tagProvider : getRequirementsTagProviders()) {
LOGGER.debug("Reading requirements from " + tagProvider);
List newRequirements = tagProvider.getRequirements();
requirements = merger.merge(requirements, newRequirements);
}
requirements = addParentsTo(requirements);
indexRequirements();
LOGGER.debug("Requirements found:" + requirements);
}
return requirements;
}
private List addParentsTo(List requirements) {
return addParentsTo(requirements, null);
}
private List addParentsTo(List requirements, String parent) {
List augmentedRequirements = Lists.newArrayList();
for(Requirement requirement : requirements) {
List children = requirement.hasChildren()
? addParentsTo(requirement.getChildren(),requirement.getName()) : NO_REQUIREMENTS;
augmentedRequirements.add(requirement.withParent(parent).withChildren(children));
}
return augmentedRequirements;
}
private void indexRequirements() {
requirementAncestors = Maps.newHashMap();
for (Requirement requirement : requirements) {
List requirementPath = ImmutableList.of(requirement);
requirementAncestors.put(requirement, ImmutableList.of(requirement));
LOGGER.debug("Requirement ancestors for:" + requirement + " = " + requirementPath);
indexChildRequirements(requirementPath, requirement.getChildren());
}
}
ReleaseManager releaseManager;
private ReleaseManager getReleaseManager() {
if (releaseManager == null) {
ReportNameProvider defaultNameProvider = new ReportNameProvider();
releaseManager = new ReleaseManager(environmentVariables, defaultNameProvider);
}
return releaseManager;
}
private Map> getRequirementAncestors() {
if (requirementAncestors == null) {
getRequirements();
}
return requirementAncestors;
}
private void indexChildRequirements(List ancestors, List children) {
for (Requirement requirement : children) {
List requirementPath = newArrayList(ancestors);
requirementPath.add(requirement);
requirementAncestors.put(requirement, ImmutableList.copyOf(requirementPath));
LOGGER.debug("Requirement ancestors for:" + requirement + " = " + requirementPath);
indexChildRequirements(requirementPath, requirement.getChildren());
}
}
@Override
public Optional getParentRequirementFor(TestOutcome testOutcome) {
try {
for (RequirementsTagProvider tagProvider : getRequirementsTagProviders()) {
Optional requirement = getParentRequirementOf(testOutcome, tagProvider);
if (requirement.isPresent()) {
return requirement;
}
}
} catch (RuntimeException handleTagProvidersElegantly) {
LOGGER.error("Tag provider failure", handleTagProvidersElegantly);
}
return Optional.absent();
}
@Override
public Optional getRequirementFor(TestTag tag) {
try {
for (RequirementsTagProvider tagProvider : getRequirementsTagProviders()) {
Optional requirement = tagProvider.getRequirementFor(tag);
if (requirement.isPresent()) {
return requirement;
}
}
} catch (RuntimeException handleTagProvidersElegantly) {
LOGGER.error("Tag provider failure", handleTagProvidersElegantly);
}
return Optional.absent();
}
@Override
public boolean isRequirementsTag(TestTag tag) {
return getRequirementTypes().contains(tag.getType());
}
@Override
public List getAncestorRequirementsFor(TestOutcome testOutcome) {
for (RequirementsTagProvider tagProvider : getRequirementsTagProviders()) {
Optional requirement = getParentRequirementOf(testOutcome, tagProvider);
if (requirement.isPresent()) {
LOGGER.debug("Requirement found for test outcome " + testOutcome.getTitle() + "-" + testOutcome.getIssueKeys() + ": " + requirement);
if (getRequirementAncestors().containsKey(requirement.get())) {
return getRequirementAncestors().get(requirement.get());
} else {
LOGGER.warn("Requirement without identified ancestors found:" + requirement.get().getCardNumber());
}
}
}
return EMPTY_LIST;
}
Map> requirementCache = Maps.newConcurrentMap();
private Optional getParentRequirementOf(TestOutcome testOutcome, RequirementsTagProvider tagProvider) {
if (requirementCache.containsKey(testOutcome)) {
return requirementCache.get(testOutcome);
} else {
Optional parentRequirement = findMatchingIndexedRequirement(tagProvider.getParentRequirementOf(testOutcome));
requirementCache.put(testOutcome, parentRequirement);
return parentRequirement;
}
}
private Optional findMatchingIndexedRequirement(Optional requirement) {
if (!requirement.isPresent()) {
return requirement;
}
for(Requirement indexedRequirement : getAllRequirements()) {
if (requirement.get().matches(indexedRequirement)) {
return Optional.of(indexedRequirement);
}
}
return Optional.absent();
}
@Override
public List getReleaseVersionsFor(TestOutcome testOutcome) {
List releases = newArrayList(testOutcome.getVersions());
for (Requirement parentRequirement : getAncestorRequirementsFor(testOutcome)) {
releases.addAll(parentRequirement.getReleaseVersions());
}
return releases;
}
@Override
public List getReleasesFromRequirements() {
if (releases == null) {
if (getReleaseProvider().isPresent() && (getReleaseProvider().get().isActive())) {
releases = getReleaseProvider().get().getReleases();
} else {
List> releaseVersions = getReleaseVersionsFrom(getRequirements());
releases = getReleaseManager().extractReleasesFrom(releaseVersions);
}
}
return releases;
}
private Optional getReleaseProvider() {
List requirementsTagProviders = getRequirementsTagProviders();
for (RequirementsTagProvider provider : requirementsTagProviders) {
if ((provider instanceof ReleaseProvider) && ((ReleaseProvider) provider).isActive()) {
return Optional.of((ReleaseProvider) provider);
}
}
return Optional.absent();
}
@Override
public List getRequirementTypes() {
Set requirementTypes = Sets.newHashSet();
for(Requirement requirement : getAllRequirements()) {
requirementTypes.add(requirement.getType());
}
return ImmutableList.copyOf(requirementTypes);
}
private List> getReleaseVersionsFrom(List requirements) {
List> releaseVersions = newArrayList();
for (Requirement requirement : requirements) {
releaseVersions.add(requirement.getReleaseVersions());
releaseVersions.addAll(getReleaseVersionsFrom(requirement.getChildren()));
}
return releaseVersions;
}
private List getRequirementsTagProviders() {
if (requirementsTagProviders == null) {
RequirementsProviderService requirementsProviderService = Injectors.getInjector().getInstance(RequirementsProviderService.class);
requirementsTagProviders = reprioritizeProviders(active(requirementsProviderService.getRequirementsProviders()));
}
return requirementsTagProviders;
}
private List active(List requirementsProviders) {
boolean useDirectoryBasedRequirements =
ThucydidesSystemProperty.THUCYDIDES_USE_REQUIREMENTS_DIRECTORIES.booleanFrom(environmentVariables, true);
if (useDirectoryBasedRequirements) {
return requirementsProviders;
} else {
List activeRequirementsProviders = newArrayList();
for (RequirementsTagProvider provider : requirementsProviders) {
if (!(provider instanceof FileSystemRequirementsTagProvider)) {
activeRequirementsProviders.add(provider);
}
}
return activeRequirementsProviders;
}
}
private List reprioritizeProviders(List requirementsTagProviders) {
Map lowPriorityProviders = Maps.newHashMap();
List prioritizedProviders = newArrayList();
for (RequirementsTagProvider provider : requirementsTagProviders) {
if (LOW_PRIORITY_PROVIDERS.contains(provider.getClass().getCanonicalName())) {
lowPriorityProviders.put(provider.getClass().getCanonicalName(), provider);
} else {
prioritizedProviders.add(provider);
}
}
addLowPriorityProviders(lowPriorityProviders, prioritizedProviders);
return prioritizedProviders;
}
private void addLowPriorityProviders(Map lowPriorityProviders, List prioritizedProviders) {
for(String lowPriorityProvider : LOW_PRIORITY_PROVIDERS) {
if (lowPriorityProviders.containsKey(lowPriorityProvider)) {
prioritizedProviders.add(lowPriorityProviders.get(lowPriorityProvider));
}
}
}
public List getAllRequirements() {
List allRequirements = newArrayList();
addRequirementsFrom(getRequirements(), allRequirements);
return allRequirements;
}
private void addRequirementsFrom(List requirements, List allRequirements) {
allRequirements.addAll(requirements);
for (Requirement requirement : requirements) {
addRequirementsFrom(requirement.getChildren(), allRequirements);
}
}
}