org.gradle.integtests.fixtures.executer.InProcessGradleExecuter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.integtests.fixtures.executer;
import com.google.common.base.Joiner;
import junit.framework.AssertionFailedError;
import org.apache.commons.io.output.TeeOutputStream;
import org.gradle.BuildResult;
import org.gradle.StartParameter;
import org.gradle.api.Task;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.execution.TaskExecutionListener;
import org.gradle.api.internal.StartParameterInternal;
import org.gradle.api.internal.TaskInternal;
import org.gradle.api.internal.classpath.ModuleRegistry;
import org.gradle.api.internal.file.FileCollectionFactory;
import org.gradle.api.internal.file.TestFiles;
import org.gradle.api.logging.configuration.ConsoleOutput;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.TaskState;
import org.gradle.cli.CommandLineParser;
import org.gradle.configuration.GradleLauncherMetaData;
import org.gradle.execution.MultipleBuildFailures;
import org.gradle.initialization.BuildRequestContext;
import org.gradle.initialization.DefaultBuildCancellationToken;
import org.gradle.initialization.DefaultBuildRequestContext;
import org.gradle.initialization.DefaultBuildRequestMetaData;
import org.gradle.initialization.NoOpBuildEventConsumer;
import org.gradle.initialization.layout.BuildLayoutFactory;
import org.gradle.integtests.fixtures.FileSystemWatchingHelper;
import org.gradle.integtests.fixtures.logging.GroupedOutputFixture;
import org.gradle.internal.Factory;
import org.gradle.internal.InternalListener;
import org.gradle.internal.IoActions;
import org.gradle.internal.SystemProperties;
import org.gradle.internal.UncheckedException;
import org.gradle.internal.agents.AgentInitializer;
import org.gradle.internal.agents.AgentUtils;
import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.deprecation.DeprecationLogger;
import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.exceptions.LocationAwareException;
import org.gradle.internal.invocation.BuildAction;
import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.logging.LoggingManagerInternal;
import org.gradle.internal.nativeintegration.ProcessEnvironment;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.internal.time.Time;
import org.gradle.launcher.Main;
import org.gradle.launcher.cli.Parameters;
import org.gradle.launcher.cli.ParametersConverter;
import org.gradle.launcher.daemon.configuration.DaemonBuildOptions;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.launcher.exec.BuildActionParameters;
import org.gradle.launcher.exec.BuildActionResult;
import org.gradle.launcher.exec.DefaultBuildActionParameters;
import org.gradle.process.internal.JavaExecHandleBuilder;
import org.gradle.test.fixtures.file.TestDirectoryProvider;
import org.gradle.test.fixtures.file.TestFile;
import org.gradle.testfixtures.internal.NativeServicesTestFixture;
import org.gradle.tooling.internal.provider.action.ExecuteBuildAction;
import org.gradle.tooling.internal.provider.serialization.DeserializeMap;
import org.gradle.tooling.internal.provider.serialization.PayloadClassLoaderRegistry;
import org.gradle.tooling.internal.provider.serialization.PayloadSerializer;
import org.gradle.tooling.internal.provider.serialization.SerializeMap;
import org.gradle.util.GradleVersion;
import org.gradle.util.internal.CollectionUtils;
import org.gradle.util.internal.GUtil;
import org.gradle.util.internal.IncubationLogger;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.gradle.integtests.fixtures.executer.OutputScrapingExecutionResult.flattenTaskPaths;
import static org.gradle.integtests.fixtures.executer.OutputScrapingExecutionResult.normalizeLambdaIds;
import static org.gradle.internal.hash.Hashing.hashString;
import static org.gradle.util.Matchers.normalizedLineSeparators;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
public class InProcessGradleExecuter extends DaemonGradleExecuter {
private final ProcessEnvironment processEnvironment = GLOBAL_SERVICES.get(ProcessEnvironment.class);
public static final TestFile COMMON_TMP = new TestFile(new File("build/tmp"));
static {
LoggingManagerInternal loggingManager = GLOBAL_SERVICES.getFactory(LoggingManagerInternal.class).create();
loggingManager.start();
GLOBAL_SERVICES.get(AgentInitializer.class).maybeConfigureInstrumentationAgent();
}
public InProcessGradleExecuter(GradleDistribution distribution, TestDirectoryProvider testDirectoryProvider) {
super(distribution, testDirectoryProvider);
}
public InProcessGradleExecuter(GradleDistribution distribution, TestDirectoryProvider testDirectoryProvider, GradleVersion gradleVersion, IntegrationTestBuildContext buildContext) {
super(distribution, testDirectoryProvider, gradleVersion, buildContext);
waitForChangesToBePickedUpBeforeExecution();
}
private void waitForChangesToBePickedUpBeforeExecution() {
// File system watching is now on by default, so we need to wait for changes to be picked up before each execution.
beforeExecute(executer -> {
try {
FileSystemWatchingHelper.waitForChangesToBePickedUp();
} catch (InterruptedException e) {
throw UncheckedException.throwAsUncheckedException(e);
}
});
}
@Override
public GradleExecuter reset() {
DeprecationLogger.reset();
IncubationLogger.reset();
return super.reset();
}
@Override
protected ExecutionResult doRun() {
if (isForkRequired()) {
return createGradleHandle().waitForFinish();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
BuildListenerImpl buildListener = new BuildListenerImpl();
BuildResult result = doRun(outputStream, errorStream, buildListener);
if (result.getFailure() != null) {
throw new UnexpectedBuildFailure(result.getFailure());
}
return assertResult(new InProcessExecutionResult(buildListener.executedTasks, buildListener.skippedTasks,
OutputScrapingExecutionResult.from(outputStream.toString(), errorStream.toString())));
}
@Override
protected ExecutionFailure doRunWithFailure() {
if (isForkRequired()) {
return createGradleHandle().waitForFailure();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
BuildListenerImpl buildListener = new BuildListenerImpl();
BuildResult result = doRun(outputStream, errorStream, buildListener);
if (result.getFailure() == null) {
throw new AssertionError("expected build to fail but it did not.");
}
return assertResult(new InProcessExecutionFailure(buildListener.executedTasks, buildListener.skippedTasks,
OutputScrapingExecutionFailure.from(outputStream.toString(), errorStream.toString()), result.getFailure()));
}
private boolean isForkRequired() {
if (isDaemonExplicitlyRequired() || !getJavaHomeLocation().equals(Jvm.current().getJavaHome())) {
return true;
}
File gradleProperties = new File(getWorkingDir(), "gradle.properties");
if (gradleProperties.isFile()) {
Properties properties = GUtil.loadProperties(gradleProperties);
return properties.getProperty("org.gradle.java.home") != null || properties.getProperty("org.gradle.jvmargs") != null;
}
boolean isInstrumentationEnabledForProcess = isAgentInstrumentationEnabled();
boolean differentInstrumentationRequested = getAllArgs().stream().anyMatch(
("-D" + DaemonBuildOptions.ApplyInstrumentationAgentOption.GRADLE_PROPERTY + "=" + !isInstrumentationEnabledForProcess)::equals);
return differentInstrumentationRequested;
}
private T assertResult(T result) {
getResultAssertion().execute(result);
return result;
}
@Override
protected GradleHandle createGradleHandle() {
configureConsoleCommandLineArgs();
return super.createGradleHandle();
}
@Override
protected Factory getExecHandleFactory() {
return () -> {
NativeServicesTestFixture.initialize();
GradleInvocation invocation = buildInvocation();
JavaExecHandleBuilder builder = TestFiles.execFactory().newJavaExec();
builder.workingDir(getWorkingDir());
builder.setExecutable(new File(getJavaHomeLocation(), "bin/java"));
builder.classpath(getExecHandleFactoryClasspath());
builder.jvmArgs(invocation.launcherJvmArgs);
// Apply the agent to the newly created daemon. The feature flag decides if it is going to be used.
for (File agent : cleanup(GLOBAL_SERVICES.get(ModuleRegistry.class).getModule(AgentUtils.AGENT_MODULE_NAME).getClasspath().getAsFiles())) {
builder.jvmArgs("-javaagent:" + agent.getAbsolutePath());
}
builder.environment(invocation.environmentVars);
builder.getMainClass().set(Main.class.getName());
builder.args(invocation.args);
builder.setStandardInput(connectStdIn());
return builder;
};
}
private Collection getExecHandleFactoryClasspath() {
Collection classpath = cleanup(GLOBAL_SERVICES.get(ModuleRegistry.class).getAdditionalClassPath().getAsFiles());
if (!OperatingSystem.current().isWindows()) {
return classpath;
}
// Use a Class-Path manifest JAR to circumvent too long command line issues on Windows (cap 8191)
// Classpath is huge here because it's the test runtime classpath
return Collections.singleton(getClasspathManifestJarFor(classpath));
}
private Collection cleanup(List files) {
List result = new LinkedList<>();
String prefix = Jvm.current().getJavaHome().getPath() + File.separator;
for (File file : files) {
if (file.getPath().startsWith(prefix)) {
// IDEA adds the JDK's bootstrap classpath to the classpath it uses to run test - remove this
continue;
}
result.add(file);
}
return result;
}
private File getClasspathManifestJarFor(Collection classpath) {
String cpString = classpath.stream()
.map(File::toURI)
.map(Object::toString)
.collect(Collectors.joining(" "));
File cpJar = new File(getDefaultTmpDir(), "daemon-classpath-manifest-" + hashString(cpString).toCompactString() + ".jar");
if (!cpJar.isFile()) {
// Make sure the parent exists or the jar creation might fail
cpJar.getParentFile().mkdirs();
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, cpString);
JarOutputStream output = null;
try {
output = new JarOutputStream(new FileOutputStream(cpJar), manifest);
output.putNextEntry(new JarEntry("META-INF/"));
output.closeEntry();
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
IoActions.closeQuietly(output);
}
}
return cpJar;
}
private BuildResult doRun(OutputStream outputStream, OutputStream errorStream, BuildListenerImpl listener) {
// Capture the current state of things that we will change during execution
InputStream originalStdIn = System.in;
Properties originalSysProperties = new Properties();
originalSysProperties.putAll(System.getProperties());
File originalUserDir = new File(originalSysProperties.getProperty("user.dir")).getAbsoluteFile();
Map originalEnv = new HashMap<>(System.getenv());
GradleInvocation invocation = buildInvocation();
Set changedEnvVars = new HashSet<>(invocation.environmentVars.keySet());
try {
return executeBuild(invocation, outputStream, errorStream, listener);
} finally {
// Restore the environment
System.setProperties(originalSysProperties);
processEnvironment.maybeSetProcessDir(originalUserDir);
for (String envVar : changedEnvVars) {
String oldValue = originalEnv.get(envVar);
if (oldValue != null) {
processEnvironment.maybeSetEnvironmentVariable(envVar, oldValue);
} else {
processEnvironment.maybeRemoveEnvironmentVariable(envVar);
}
}
System.setProperty("user.dir", originalSysProperties.getProperty("user.dir"));
System.setIn(originalStdIn);
}
}
private LoggingManagerInternal createLoggingManager(StartParameter startParameter, OutputStream outputStream, OutputStream errorStream) {
LoggingManagerInternal loggingManager = GLOBAL_SERVICES.getFactory(LoggingManagerInternal.class).create();
loggingManager.captureSystemSources();
ConsoleOutput consoleOutput = startParameter.getConsoleOutput();
loggingManager.attachConsole(new TeeOutputStream(System.out, outputStream), new TeeOutputStream(System.err, errorStream), consoleOutput, consoleAttachment.getConsoleMetaData());
return loggingManager;
}
private BuildResult executeBuild(GradleInvocation invocation, OutputStream outputStream, OutputStream errorStream, BuildListenerImpl listener) {
// Augment the environment for the execution
System.setIn(connectStdIn());
processEnvironment.maybeSetProcessDir(getWorkingDir());
for (Map.Entry entry : invocation.environmentVars.entrySet()) {
processEnvironment.maybeSetEnvironmentVariable(entry.getKey(), entry.getValue());
}
Map implicitJvmSystemProperties = getImplicitJvmSystemProperties();
System.getProperties().putAll(implicitJvmSystemProperties);
// TODO: Reuse more of CommandlineActionFactory
CommandLineParser parser = new CommandLineParser();
FileCollectionFactory fileCollectionFactory = TestFiles.fileCollectionFactory();
ParametersConverter parametersConverter = new ParametersConverter(new BuildLayoutFactory(), fileCollectionFactory);
parametersConverter.configure(parser);
Parameters parameters = parametersConverter.convert(parser.parse(getAllArgs()), getWorkingDir());
BuildActionExecuter actionExecuter = GLOBAL_SERVICES.get(BuildActionExecuter.class);
ListenerManager listenerManager = GLOBAL_SERVICES.get(ListenerManager.class);
listenerManager.addListener(listener);
try {
// TODO: Reuse more of BuildActionsFactory
StartParameterInternal startParameter = parameters.getStartParameter();
BuildAction action = new ExecuteBuildAction(startParameter);
BuildActionParameters buildActionParameters = createBuildActionParameters(startParameter);
BuildRequestContext buildRequestContext = createBuildRequestContext();
LoggingManagerInternal loggingManager = createLoggingManager(startParameter, outputStream, errorStream);
loggingManager.start();
try {
startMeasurement();
try {
BuildActionResult result = actionExecuter.execute(action, buildActionParameters, buildRequestContext);
if (result.getException() != null) {
return new BuildResult(null, result.getException());
}
if (result.getFailure() != null) {
PayloadSerializer payloadSerializer = new PayloadSerializer(new TestClassLoaderRegistry());
return new BuildResult(null, (RuntimeException) payloadSerializer.deserialize(result.getFailure()));
}
return new BuildResult(null, null);
} finally {
stopMeasurement();
}
} finally {
loggingManager.stop();
}
} finally {
listenerManager.removeListener(listener);
}
}
private BuildActionParameters createBuildActionParameters(StartParameter startParameter) {
return new DefaultBuildActionParameters(
System.getProperties(),
System.getenv(),
SystemProperties.getInstance().getCurrentDir(),
startParameter.getLogLevel(),
false,
ClassPath.EMPTY
);
}
private BuildRequestContext createBuildRequestContext() {
return new DefaultBuildRequestContext(
new DefaultBuildRequestMetaData(new GradleLauncherMetaData(), Time.currentTimeMillis(), interactive),
new DefaultBuildCancellationToken(),
new NoOpBuildEventConsumer());
}
@Override
public void assertCanExecute() {
assertNull(getExecutable());
}
@Override
protected TestFile getDefaultTmpDir() {
// File.createTempFile sets the location of the temp directory to a static variable on the first call. This prevents future
// changes to java.io.tmpdir from having any effect in the same process. We set this to use a common tmp directory for all
// tests running in the same process so that we don't have a situation where one process initializes with a tmp directory
// that it then removes, causing an IOException for any future tests that run in the same process and call File.createTempFile.
return COMMON_TMP;
}
@Override
public GradleExecuter withTestConsoleAttached() {
return withTestConsoleAttached(ConsoleAttachment.ATTACHED);
}
@Override
public GradleExecuter withTestConsoleAttached(ConsoleAttachment consoleAttachment) {
this.consoleAttachment = consoleAttachment;
return this;
}
private static class BuildListenerImpl implements TaskExecutionListener, InternalListener {
private final List executedTasks = new CopyOnWriteArrayList<>();
private final Set skippedTasks = new CopyOnWriteArraySet<>();
@Override
public void beforeExecute(Task task) {
String taskPath = path(task);
executedTasks.add(taskPath);
}
@Override
public void afterExecute(Task task, TaskState state) {
String taskPath = path(task);
if (state.getSkipped()) {
skippedTasks.add(taskPath);
}
}
private String path(Task task) {
return ((TaskInternal) task).getIdentityPath().getPath();
}
}
public static class InProcessExecutionResult implements ExecutionResult {
protected static final Spec NOT_BUILD_SRC_TASK = t -> !t.startsWith(":buildSrc:");
protected final List executedTasks;
protected final Set skippedTasks;
private final ExecutionResult outputResult;
InProcessExecutionResult(List executedTasks, Set skippedTasks, ExecutionResult outputResult) {
this.executedTasks = executedTasks;
this.skippedTasks = skippedTasks;
this.outputResult = outputResult;
}
@Override
public ExecutionResult getIgnoreBuildSrc() {
List executedTasks = CollectionUtils.filter(this.executedTasks, NOT_BUILD_SRC_TASK);
Set skippedTasks = CollectionUtils.filter(this.skippedTasks, NOT_BUILD_SRC_TASK);
return new InProcessExecutionResult(executedTasks, skippedTasks, outputResult.getIgnoreBuildSrc());
}
@Override
public String getOutput() {
return outputResult.getOutput();
}
@Override
public String getNormalizedOutput() {
return outputResult.getNormalizedOutput();
}
@Override
public String getFormattedOutput() {
return outputResult.getFormattedOutput();
}
@Override
public String getPlainTextOutput() {
return outputResult.getPlainTextOutput();
}
@Override
public GroupedOutputFixture getGroupedOutput() {
return outputResult.getGroupedOutput();
}
@Override
public ExecutionResult assertOutputEquals(String expectedOutput, boolean ignoreExtraLines, boolean ignoreLineOrder) {
outputResult.assertOutputEquals(expectedOutput, ignoreExtraLines, ignoreLineOrder);
return this;
}
@Override
public ExecutionResult assertNotOutput(String expectedOutput) {
outputResult.assertNotOutput(expectedOutput);
return this;
}
@Override
public ExecutionResult assertOutputContains(String expectedOutput) {
outputResult.assertOutputContains(expectedOutput);
return this;
}
@Override
public ExecutionResult assertContentContains(String content, String expectedOutput, String label) {
outputResult.assertContentContains(content, expectedOutput, label);
return null;
}
@Override
public ExecutionResult assertHasPostBuildOutput(String expectedOutput) {
outputResult.assertHasPostBuildOutput(expectedOutput);
return this;
}
@Override
public ExecutionResult assertNotPostBuildOutput(String expectedOutput) {
outputResult.assertNotPostBuildOutput(expectedOutput);
return this;
}
@Override
public boolean hasErrorOutput(String expectedOutput) {
return outputResult.hasErrorOutput(expectedOutput);
}
@Override
public ExecutionResult assertHasErrorOutput(String expectedOutput) {
outputResult.assertHasErrorOutput(expectedOutput);
return this;
}
@Override
public String getError() {
return outputResult.getError();
}
@Override
public String getOutputLineThatContains(String text) {
return outputResult.getOutputLineThatContains(text);
}
@Override
public String getPostBuildOutputLineThatContains(String text) {
return outputResult.getPostBuildOutputLineThatContains(text);
}
@Override
public ExecutionResult assertTasksExecutedInOrder(Object... taskPaths) {
Set expected = TaskOrderSpecs.exact(taskPaths).getTasks();
assertTasksExecuted(expected);
assertTaskOrder(taskPaths);
outputResult.assertTasksExecutedInOrder(taskPaths);
return this;
}
@Override
public ExecutionResult assertTasksExecuted(Object... taskPaths) {
Set flattenedTasks = new TreeSet<>(flattenTaskPaths(taskPaths));
assertEquals(new TreeSet<>(flattenedTasks), new TreeSet<>(executedTasks));
outputResult.assertTasksExecuted(flattenedTasks);
return this;
}
@Override
public ExecutionResult assertTasksExecutedAndNotSkipped(Object... taskPaths) {
assertTasksExecuted(taskPaths);
assertTasksNotSkipped(taskPaths);
return this;
}
@Override
public ExecutionResult assertTaskExecuted(String taskPath) {
assertThat(executedTasks, hasItem(taskPath));
outputResult.assertTaskExecuted(taskPath);
return this;
}
@Override
public ExecutionResult assertTaskNotExecuted(String taskPath) {
assertThat(executedTasks, not(hasItem(taskPath)));
outputResult.assertTaskNotExecuted(taskPath);
return this;
}
@Override
public ExecutionResult assertTaskOrder(Object... taskPaths) {
TaskOrderSpecs.exact(taskPaths).assertMatches(-1, executedTasks);
outputResult.assertTaskOrder(taskPaths);
return this;
}
@Override
public ExecutionResult assertTasksSkipped(Object... taskPaths) {
Set expected = new TreeSet<>(flattenTaskPaths(taskPaths));
assertThat(skippedTasks, equalTo(expected));
outputResult.assertTasksSkipped(expected);
return this;
}
@Override
public ExecutionResult assertTaskSkipped(String taskPath) {
assertThat(skippedTasks, hasItem(taskPath));
outputResult.assertTaskSkipped(taskPath);
return this;
}
@Override
public ExecutionResult assertTasksNotSkipped(Object... taskPaths) {
Set expected = new TreeSet<>(flattenTaskPaths(taskPaths));
Set notSkipped = getNotSkippedTasks();
assertThat(notSkipped, equalTo(expected));
outputResult.assertTasksNotSkipped(expected);
return this;
}
@Override
public ExecutionResult assertTaskNotSkipped(String taskPath) {
assertThat(getNotSkippedTasks(), hasItem(taskPath));
outputResult.assertTaskNotSkipped(taskPath);
return this;
}
private Set getNotSkippedTasks() {
Set notSkipped = new TreeSet<>(executedTasks);
notSkipped.removeAll(skippedTasks);
return notSkipped;
}
@Override
public void assertResultVisited() {
outputResult.assertResultVisited();
}
}
private static class InProcessExecutionFailure extends InProcessExecutionResult implements ExecutionFailure {
private static final Pattern LOCATION_PATTERN = Pattern.compile("(?m)^((\\w+ )+'.+') line: (\\d+)$");
private final ExecutionFailure outputFailure;
private final Throwable failure;
private final List fileNames = new ArrayList<>();
private final List lineNumbers = new ArrayList<>();
private final List failures = new ArrayList<>();
InProcessExecutionFailure(List tasks, Set skippedTasks, ExecutionFailure outputFailure, Throwable failure) {
super(tasks, skippedTasks, outputFailure);
this.outputFailure = outputFailure;
this.failure = failure;
if (failure instanceof MultipleBuildFailures) {
for (Throwable cause : ((MultipleBuildFailures) failure).getCauses()) {
extractDetails(cause);
}
} else {
extractDetails(failure);
}
}
private void extractDetails(Throwable failure) {
List causes = new ArrayList<>();
extractCauses(failure, causes);
String failureMessage = failure.getMessage() == null ? "" : normalizeLambdaIds(failure.getMessage());
java.util.regex.Matcher matcher = LOCATION_PATTERN.matcher(failureMessage);
if (matcher.find()) {
fileNames.add(matcher.group(1));
lineNumbers.add(matcher.group(3));
failures.add(new FailureDetails(failure, failureMessage.substring(matcher.end()).trim(), causes));
} else {
failures.add(new FailureDetails(failure, failureMessage.trim(), causes));
}
}
@Override
public InProcessExecutionFailure getIgnoreBuildSrc() {
List executedTasks = CollectionUtils.filter(this.executedTasks, NOT_BUILD_SRC_TASK);
Set skippedTasks = CollectionUtils.filter(this.skippedTasks, NOT_BUILD_SRC_TASK);
return new InProcessExecutionFailure(executedTasks, skippedTasks, outputFailure.getIgnoreBuildSrc(), failure);
}
@Override
public ExecutionFailure assertHasLineNumber(int lineNumber) {
outputFailure.assertHasLineNumber(lineNumber);
assertThat(this.lineNumbers, hasItem(equalTo(String.valueOf(lineNumber))));
return this;
}
@Override
public ExecutionFailure assertHasFileName(String filename) {
outputFailure.assertHasFileName(filename);
assertThat(this.fileNames, hasItem(equalTo(filename)));
return this;
}
@Override
public ExecutionFailure assertHasResolutions(String... resolutions) {
outputFailure.assertHasResolutions(resolutions);
return this;
}
@Override
public ExecutionFailure assertHasResolution(String resolution) {
outputFailure.assertHasResolution(resolution);
return this;
}
@Override
public ExecutionFailure assertHasFailures(int count) {
outputFailure.assertHasFailures(count);
if (failures.size() != count) {
throw new AssertionFailedError(String.format("Expected %s failures, but found %s", count, failures.size()));
}
return this;
}
@Override
public ExecutionFailure assertHasCause(String description) {
assertThatCause(startsWith(description));
return this;
}
@Override
public ExecutionFailure assertThatCause(Matcher super String> matcher) {
outputFailure.assertThatCause(matcher);
Set seen = new LinkedHashSet<>();
Matcher messageMatcher = normalizedLineSeparators(matcher);
for (FailureDetails failure : failures) {
for (String cause : failure.causes) {
if (messageMatcher.matches(cause)) {
return this;
}
seen.add(cause);
}
}
fail(String.format("Could not find matching cause in: %s%nFailure is: %s", seen, failure));
return this;
}
private void extractCauses(Throwable failure, List causes) {
if (failure instanceof MultipleBuildFailures) {
MultipleBuildFailures exception = (MultipleBuildFailures) failure;
for (Throwable componentFailure : exception.getCauses()) {
extractCauses(componentFailure, causes);
}
} else if (failure instanceof LocationAwareException) {
for (Throwable cause : ((LocationAwareException) failure).getReportableCauses()) {
causes.add(cause.getMessage());
}
} else {
causes.add(failure.getMessage());
}
}
@Override
public ExecutionFailure assertHasNoCause(String description) {
outputFailure.assertHasNoCause(description);
Matcher matcher = containsString(description);
for (FailureDetails failure : failures) {
for (String cause : failure.causes) {
if (matcher.matches(cause)) {
throw new AssertionFailedError(String.format("Expected no failure with description '%s', found: %s", description, cause));
}
}
}
return this;
}
@Override
public ExecutionFailure assertHasNoCause() {
outputFailure.assertHasNoCause();
for (FailureDetails failure : failures) {
assertEquals(0, failure.causes.size());
}
return this;
}
@Override
public ExecutionFailure assertHasDescription(String context) {
assertThatDescription(startsWith(context));
return this;
}
@Override
public ExecutionFailure assertThatDescription(Matcher super String> matcher) {
outputFailure.assertThatDescription(matcher);
assertHasFailure(matcher, f -> {
});
return this;
}
@Override
public ExecutionFailure assertHasFailure(String description, Consumer super Failure> action) {
outputFailure.assertHasFailure(description, action);
assertHasFailure(startsWith(description), action);
return this;
}
private void assertHasFailure(Matcher super String> matcher, Consumer super Failure> action) {
Matcher normalized = normalizedLineSeparators(matcher);
for (FailureDetails failure : failures) {
if (normalized.matches(failure.description)) {
action.accept(failure);
return;
}
}
StringDescription description = new StringDescription();
matcher.describeTo(description);
throw new AssertionFailedError(String.format("Could not find any failure with description %s, failures:%s\n", description, Joiner.on("\n").join(failures)));
}
@Override
public ExecutionFailure assertTestsFailed() {
new DetailedExecutionFailure(this).assertTestsFailed();
return this;
}
@Override
public DependencyResolutionFailure assertResolutionFailure(String configurationPath) {
return new DependencyResolutionFailure(this, configurationPath);
}
}
private static class FailureDetails extends AbstractFailure {
final Throwable failure;
public FailureDetails(Throwable failure, String description, List causes) {
super(description, causes);
this.failure = failure;
}
@Override
public String toString() {
return description;
}
}
private static class TestClassLoaderRegistry implements PayloadClassLoaderRegistry {
@Override
public SerializeMap newSerializeSession() {
throw new UnsupportedOperationException();
}
@Override
public DeserializeMap newDeserializeSession() {
return (classLoaderDetails, className) -> {
// Assume everything is loaded into the current classloader
return Class.forName(className);
};
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy