
io.qameta.allure.AllureLifecycle Maven / Gradle / Ivy
package io.qameta.allure;
import io.qameta.allure.model.Attachment;
import io.qameta.allure.model.ExecutableItem;
import io.qameta.allure.model.FixtureResult;
import io.qameta.allure.model.Stage;
import io.qameta.allure.model.StepResult;
import io.qameta.allure.model.TestResult;
import io.qameta.allure.model.TestResultContainer;
import io.qameta.allure.model.WithAttachments;
import io.qameta.allure.model.WithSteps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import static io.qameta.allure.AllureConstants.ATTACHMENT_FILE_SUFFIX;
/**
* The class contains Allure context and methods to change it.
*/
@SuppressWarnings("PMD.TooManyMethods")
public class AllureLifecycle {
private static final Logger LOGGER = LoggerFactory.getLogger(AllureLifecycle.class);
private final Map storage = new ConcurrentHashMap<>();
private final ThreadLocal> currentStepContext =
InheritableThreadLocal.withInitial(LinkedList::new);
private final AllureResultsWriter writer;
public AllureLifecycle(final AllureResultsWriter writer) {
this.writer = writer;
}
public AllureLifecycle() {
this(getDefaultWriter());
}
private static FileSystemResultsWriter getDefaultWriter() {
final String path = System.getProperty("allure.results.directory", "allure-results");
return new FileSystemResultsWriter(Paths.get(path));
}
public void startTestContainer(final String parentUuid, final TestResultContainer container) {
get(parentUuid, TestResultContainer.class)
.getChildren().add(container.getUuid());
startTestContainer(container);
}
public void startTestContainer(final TestResultContainer container) {
LOGGER.debug("Start test result container {}", container.getUuid());
put(container.getUuid(), container)
.withStart(System.currentTimeMillis());
}
public void updateTestContainer(final String uuid, final Consumer update) {
LOGGER.debug("Update test result container {}", uuid);
update.accept(get(uuid, TestResultContainer.class));
}
public void stopTestContainer(final String uuid) {
LOGGER.debug("Stop test result container {}", uuid);
get(uuid, TestResultContainer.class)
.withStop(System.currentTimeMillis());
}
public void writeTestContainer(final String uuid) {
LOGGER.debug("Stop test group {}", uuid);
writer.write(remove(uuid, TestResultContainer.class));
}
public void startBeforeFixture(final String parentUuid, final String uuid, final FixtureResult result) {
LOGGER.debug("Start test before {} with parent {}", uuid, parentUuid);
startFixture(parentUuid, uuid, result, TestResultContainer::getBefores);
}
public void startAfterFixture(final String parentUuid, final String uuid, final FixtureResult result) {
LOGGER.debug("Start test after {} with parent {}", uuid, parentUuid);
startFixture(parentUuid, uuid, result, TestResultContainer::getAfters);
}
private void startFixture(final String parentUuid, final String uuid, final FixtureResult result,
final Function> fixturesGetter) {
put(uuid, result)
.withStage(Stage.RUNNING)
.withStart(System.currentTimeMillis());
final TestResultContainer container = get(parentUuid, TestResultContainer.class);
fixturesGetter.apply(container).add(result);
currentStepContext.remove();
currentStepContext.get().push(uuid);
}
public void updateFixture(final Consumer update) {
final String uuid = currentStepContext.get().getLast();
updateFixture(uuid, update);
}
public void updateFixture(final String uuid, final Consumer update) {
LOGGER.debug("Update test group {}", uuid);
update.accept(get(uuid, FixtureResult.class));
}
public void stopFixture(final String uuid) {
LOGGER.debug("Stop test before {}", uuid);
currentStepContext.remove();
remove(uuid, FixtureResult.class)
.withStage(Stage.FINISHED)
.withStop(System.currentTimeMillis());
}
public void scheduleTestCase(final String parentUuid, final TestResult result) {
LOGGER.debug("Add test case {} to {}", result.getUuid(), parentUuid);
get(parentUuid, TestResultContainer.class)
.getChildren().add(result.getUuid());
scheduleTestCase(result);
}
public void scheduleTestCase(final TestResult result) {
LOGGER.debug("Schedule test case {}", result.getUuid());
put(result.getUuid(), result)
.withStage(Stage.SCHEDULED);
}
public void startTestCase(final String uuid) {
LOGGER.debug("Start test case {}", uuid);
get(uuid, TestResult.class)
.withStage(Stage.RUNNING)
.withStart(System.currentTimeMillis());
currentStepContext.remove();
currentStepContext.get().push(uuid);
}
public void updateTestCase(final Consumer update) {
final String uuid = currentStepContext.get().getLast();
updateTestCase(uuid, update);
}
public void updateTestCase(final String uuid, final Consumer update) {
LOGGER.debug("Update test case {}", uuid);
update.accept(get(uuid, TestResult.class));
}
public void stopTestCase(final String uuid) {
LOGGER.debug("Stop test case {}", uuid);
currentStepContext.remove();
get(uuid, TestResult.class)
.withStage(Stage.FINISHED)
.withStop(System.currentTimeMillis());
}
public void updateExecutable(final Consumer update) {
final String uuid = currentStepContext.get().getLast();
updateExecutable(uuid, update);
}
public void updateExecutable(final String uuid, final Consumer update) {
LOGGER.debug("Update executable {}", uuid);
update.accept(get(uuid, ExecutableItem.class));
}
public void writeTestCase(final String uuid) {
LOGGER.debug("Close test case {}", uuid);
writer.write(remove(uuid, TestResult.class));
}
public void addAttachment(final String name, final String type,
final String fileExtension, final byte[] body) {
addAttachment(name, type, fileExtension, new ByteArrayInputStream(body));
}
public void addAttachment(final String name, final String type,
final String fileExtension, final InputStream stream) {
writeAttachment(prepareAttachment(name, type, fileExtension), stream);
}
@SuppressWarnings({"PMD.NullAssignment", "PMD.UseObjectForClearerAPI"})
public String prepareAttachment(final String name, final String type, final String fileExtension) {
final String uuid = currentStepContext.get().getFirst();
LOGGER.debug("Adding attachment to item with uuid {}", uuid);
final String extension = Optional.ofNullable(fileExtension)
.filter(ext -> !ext.isEmpty())
.map(ext -> ext.charAt(0) == '.' ? ext : "." + ext)
.orElse("");
final String source = UUID.randomUUID().toString() + ATTACHMENT_FILE_SUFFIX + extension;
final Attachment attachment = new Attachment()
.withName(isEmpty(name) ? null : name)
.withType(isEmpty(type) ? null : type)
.withSource(source);
get(uuid, WithAttachments.class).getAttachments().add(attachment);
return attachment.getSource();
}
public void writeAttachment(final String attachmentSource, final InputStream stream) {
writer.write(attachmentSource, stream);
}
public void addStep(final StepResult result) {
get(currentStepContext.get().getFirst(), WithSteps.class).getSteps().add(result);
}
@SuppressWarnings("PMD.NullAssignment")
public void startStep(final String uuid, final StepResult result) {
final LinkedList uuids = currentStepContext.get();
startStep(uuids.isEmpty() ? null : uuids.getFirst(), uuid, result);
}
public void startStep(final String parentUuid, final String uuid, final StepResult result) {
LOGGER.debug("Start step {} with parent {}", uuid, parentUuid);
put(uuid, result)
.withStage(Stage.RUNNING)
.withStart(System.currentTimeMillis());
currentStepContext.get().push(uuid);
if (Objects.nonNull(parentUuid)) {
get(parentUuid, WithSteps.class).getSteps().add(result);
}
}
public void updateStep(final Consumer update) {
updateStep(currentStepContext.get().getFirst(), update);
}
public void updateStep(final String uuid, final Consumer update) {
LOGGER.debug("Update step {}", uuid);
update.accept(get(uuid, StepResult.class));
}
public void stopStep() {
stopStep(currentStepContext.get().getFirst());
}
public void stopStep(final String uuid) {
LOGGER.debug("Stop step {}", uuid);
remove(uuid, StepResult.class)
.withStage(Stage.FINISHED)
.withStop(System.currentTimeMillis());
currentStepContext.get().pop();
}
private T put(final String uuid, final T item) {
Objects.requireNonNull(uuid, "Can't put item to storage: uuid can't be null");
storage.put(uuid, item);
return item;
}
private T get(final String uuid, final Class clazz) {
Objects.requireNonNull(uuid, "Can't get item from storage: uuid can't be null");
final Object obj = Objects.requireNonNull(
storage.get(uuid),
String.format("Could not get %s by uuid %s", clazz, uuid)
);
return cast(obj, clazz);
}
private T remove(final String uuid, final Class clazz) {
Objects.requireNonNull(uuid, "Can't remove item from storage: uuid can't be null");
final Object obj = Objects.requireNonNull(
storage.remove(uuid),
String.format("Could not remove %s by uuid %s", clazz, uuid)
);
return cast(obj, clazz);
}
private T cast(final Object obj, final Class clazz) {
if (clazz.isInstance(obj)) {
return clazz.cast(obj);
}
throw new IllegalStateException("Can not cast " + obj + " to " + clazz);
}
private boolean isEmpty(final String s) {
return Objects.isNull(s) || s.isEmpty();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy