/* * Copyright 2015 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.tooling.internal.provider.runner; import com.google.common.collect.Maps; import org.gradle.api.Task; import org.gradle.api.execution.internal.ExecuteTaskBuildOperationDetails; import org.gradle.api.internal.tasks.testing.TestCompleteEvent; import org.gradle.api.internal.tasks.testing.TestDescriptorInternal; import org.gradle.api.internal.tasks.testing.TestStartEvent; import org.gradle.api.internal.tasks.testing.results.TestListenerInternal; import org.gradle.api.tasks.testing.Test; import org.gradle.api.tasks.testing.TestOutputEvent; import org.gradle.api.tasks.testing.TestResult; import org.gradle.initialization.BuildEventConsumer; import org.gradle.internal.progress.BuildOperationDescriptor; import org.gradle.internal.progress.BuildOperationListener; import org.gradle.internal.progress.OperationFinishEvent; import org.gradle.internal.progress.OperationStartEvent; import org.gradle.tooling.internal.protocol.events.InternalJvmTestDescriptor; import org.gradle.tooling.internal.provider.BuildClientSubscriptions; import org.gradle.tooling.internal.provider.events.AbstractTestResult; import org.gradle.tooling.internal.provider.events.DefaultFailure; import org.gradle.tooling.internal.provider.events.DefaultTestDescriptor; import org.gradle.tooling.internal.provider.events.DefaultTestFailureResult; import org.gradle.tooling.internal.provider.events.DefaultTestFinishedProgressEvent; import org.gradle.tooling.internal.provider.events.DefaultTestSkippedResult; import org.gradle.tooling.internal.provider.events.DefaultTestStartedProgressEvent; import org.gradle.tooling.internal.provider.events.DefaultTestSuccessResult; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Test listener that forwards all receiving events to the client via the provided {@code BuildEventConsumer} instance. */ class ClientForwardingTestOperationListener implements TestListenerInternal, BuildOperationListener { private final BuildEventConsumer eventConsumer; private final BuildClientSubscriptions clientSubscriptions; private Map<Object, String> runningTasks = Maps.newHashMap(); ClientForwardingTestOperationListener(BuildEventConsumer eventConsumer, BuildClientSubscriptions clientSubscriptions) { this.eventConsumer = eventConsumer; this.clientSubscriptions = clientSubscriptions; } @Override public void started(TestDescriptorInternal testDescriptor, TestStartEvent startEvent) { eventConsumer.dispatch(new DefaultTestStartedProgressEvent(startEvent.getStartTime(), adapt(testDescriptor))); } @Override public void completed(TestDescriptorInternal testDescriptor, TestResult testResult, TestCompleteEvent completeEvent) { eventConsumer.dispatch(new DefaultTestFinishedProgressEvent(completeEvent.getEndTime(), adapt(testDescriptor), adapt(testResult))); } @Override public void output(TestDescriptorInternal testDescriptor, TestOutputEvent event) { // Don't forward } private DefaultTestDescriptor adapt(TestDescriptorInternal testDescriptor) { return testDescriptor.isComposite() ? toTestDescriptorForSuite(testDescriptor) : toTestDescriptorForTest(testDescriptor); } private DefaultTestDescriptor toTestDescriptorForSuite(TestDescriptorInternal suite) { Object id = suite.getId(); String name = suite.getName(); String displayName = suite.toString(); String testKind = InternalJvmTestDescriptor.KIND_SUITE; String suiteName = suite.getName(); String className = suite.getClassName(); String methodName = null; Object parentId = getParentId(suite); final String testTaskPath = getTaskPath(suite); return new DefaultTestDescriptor(id, name, displayName, testKind, suiteName, className, methodName, parentId, testTaskPath); } private DefaultTestDescriptor toTestDescriptorForTest(TestDescriptorInternal test) { Object id = test.getId(); String name = test.getName(); String displayName = test.toString(); String testKind = InternalJvmTestDescriptor.KIND_ATOMIC; String suiteName = null; String className = test.getClassName(); String methodName = test.getName(); Object parentId = getParentId(test); final String taskPath = getTaskPath(test); return new DefaultTestDescriptor(id, name, displayName, testKind, suiteName, className, methodName, parentId, taskPath); } private String getTaskPath(TestDescriptorInternal givenDescriptor) { TestDescriptorInternal descriptor = givenDescriptor; while (descriptor.getOwnerBuildOperationId() == null && descriptor.getParent() != null) { descriptor = descriptor.getParent(); } return runningTasks.get(descriptor.getOwnerBuildOperationId()); } private Object getParentId(TestDescriptorInternal descriptor) { TestDescriptorInternal parent = descriptor.getParent(); if (parent != null) { return parent.getId(); } // only set the TaskOperation as the parent if the Tooling API Consumer is listening to task progress events if (clientSubscriptions.isSendTaskProgressEvents()) { return descriptor.getOwnerBuildOperationId(); } return null; } private static AbstractTestResult adapt(TestResult result) { TestResult.ResultType resultType = result.getResultType(); switch (resultType) { case SUCCESS: return new DefaultTestSuccessResult(result.getStartTime(), result.getEndTime()); case SKIPPED: return new DefaultTestSkippedResult(result.getStartTime(), result.getEndTime()); case FAILURE: return new DefaultTestFailureResult(result.getStartTime(), result.getEndTime(), convertExceptions(result.getExceptions())); default: throw new IllegalStateException("Unknown test result type: " + resultType); } } private static List<DefaultFailure> convertExceptions(List<Throwable> exceptions) { List<DefaultFailure> failures = new ArrayList<DefaultFailure>(exceptions.size()); for (Throwable exception : exceptions) { failures.add(DefaultFailure.fromThrowable(exception)); } return failures; } @Override public void started(BuildOperationDescriptor buildOperation, OperationStartEvent startEvent) { if (!(buildOperation.getDetails() instanceof ExecuteTaskBuildOperationDetails)) { return; } Task task = ((ExecuteTaskBuildOperationDetails) buildOperation.getDetails()).getTask(); if (!(task instanceof Test)) { return; } runningTasks.put(buildOperation.getId(), task.getPath()); } @Override public void finished(BuildOperationDescriptor buildOperation, OperationFinishEvent finishEvent) { if (!(buildOperation.getDetails() instanceof ExecuteTaskBuildOperationDetails)) { return; } runningTasks.remove(buildOperation.getId()); } }