blob: ab70395dc0e5d2daf4f3cdb3ab18f37707979b1d [file] [log] [blame]
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();
}
}