| package org.apache.maven.surefire.common.junit4; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| import org.junit.runner.Description; |
| import org.junit.runner.notification.Failure; |
| import org.junit.runner.notification.RunListener; |
| import org.junit.runner.notification.RunNotifier; |
| import org.junit.runner.notification.StoppedByUserException; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.Queue; |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod; |
| import static org.apache.maven.surefire.api.util.internal.ConcurrencyUtils.countDownToZero; |
| |
| /** |
| * Extends {@link RunNotifier JUnit notifier}, |
| * encapsulates several different types of {@link RunListener JUnit listeners}, and |
| * fires events to listeners. |
| * |
| * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a> |
| * @since 2.19 |
| */ |
| public class Notifier |
| extends RunNotifier |
| { |
| private final Collection<RunListener> listeners = new ArrayList<>(); |
| |
| private final Queue<String> testClassNames = new ConcurrentLinkedQueue<>(); |
| |
| private final AtomicInteger skipAfterFailureCount; |
| |
| private final JUnit4RunListener reporter; |
| |
| private volatile boolean failFast; |
| |
| public Notifier( JUnit4RunListener reporter, int skipAfterFailureCount ) |
| { |
| addListener( reporter ); |
| this.reporter = reporter; |
| this.skipAfterFailureCount = new AtomicInteger( skipAfterFailureCount ); |
| } |
| |
| private Notifier() |
| { |
| reporter = null; |
| skipAfterFailureCount = null; |
| } |
| |
| public static Notifier pureNotifier() |
| { |
| return new Notifier() |
| { |
| @Override |
| public void asFailFast( @SuppressWarnings( { "unused", "checkstyle:hiddenfieldcheck" } ) boolean failFast ) |
| { |
| throw new UnsupportedOperationException( "pure notifier" ); |
| } |
| }; |
| } |
| |
| public void asFailFast( boolean enableFailFast ) |
| { |
| failFast = enableFailFast; |
| } |
| |
| public final boolean isFailFast() |
| { |
| return failFast; |
| } |
| |
| @Override |
| @SuppressWarnings( "checkstyle:redundantthrowscheck" ) // checkstyle is wrong here, see super.fireTestStarted() |
| public final void fireTestStarted( Description description ) throws StoppedByUserException |
| { |
| // If fireTestStarted() throws exception (== skipped test), the class must not be removed from testClassNames. |
| // Therefore this class will be removed only if test class started with some test method. |
| super.fireTestStarted( description ); |
| if ( !testClassNames.isEmpty() ) |
| { |
| testClassNames.remove( toClassMethod( description ).getClazz() ); |
| } |
| } |
| |
| @Override |
| public final void fireTestFailure( Failure failure ) |
| { |
| if ( failFast ) |
| { |
| fireStopEvent(); |
| } |
| super.fireTestFailure( failure ); |
| } |
| |
| @Override |
| public final void addListener( RunListener listener ) |
| { |
| listeners.add( listener ); |
| super.addListener( listener ); |
| } |
| |
| public final Notifier addListeners( Collection<RunListener> given ) |
| { |
| for ( RunListener listener : given ) |
| { |
| addListener( listener ); |
| } |
| return this; |
| } |
| |
| @SuppressWarnings( "unused" ) |
| public final Notifier addListeners( RunListener... given ) |
| { |
| for ( RunListener listener : given ) |
| { |
| addListener( listener ); |
| } |
| return this; |
| } |
| |
| @Override |
| public final void removeListener( RunListener listener ) |
| { |
| listeners.remove( listener ); |
| super.removeListener( listener ); |
| } |
| |
| public final void removeListeners() |
| { |
| for ( Iterator<RunListener> it = listeners.iterator(); it.hasNext(); ) |
| { |
| RunListener listener = it.next(); |
| it.remove(); |
| super.removeListener( listener ); |
| } |
| } |
| |
| public final Queue<String> getRemainingTestClasses() |
| { |
| return failFast ? testClassNames : null; |
| } |
| |
| public final void copyListenersTo( Notifier copyTo ) |
| { |
| copyTo.addListeners( listeners ); |
| } |
| |
| /** |
| * Fire stop even to plugin process and/or call {@link org.junit.runner.notification.RunNotifier#pleaseStop()}. |
| */ |
| private void fireStopEvent() |
| { |
| if ( countDownToZero( skipAfterFailureCount ) ) |
| { |
| pleaseStop(); |
| } |
| |
| reporter.testExecutionSkippedByUser(); |
| } |
| } |