You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2019/12/28 23:05:25 UTC
[maven-surefire] branch cli updated: [SUREFIRE-1719] Race condition
results in "VM crash or System.exit called?" failure
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch cli
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/cli by this push:
new f8817a0 [SUREFIRE-1719] Race condition results in "VM crash or System.exit called?" failure
f8817a0 is described below
commit f8817a00022f552e3282cc4955d480f5cf36db5f
Author: tibordigana <ti...@apache.org>
AuthorDate: Sun Dec 29 00:05:15 2019 +0100
[SUREFIRE-1719] Race condition results in "VM crash or System.exit called?" failure
---
.../plugin/surefire/booterclient/ForkStarter.java | 4 +-
.../lazytestprovider/TestLessInputStream.java | 74 +++++++---------------
.../TestLessInputStreamBuilderTest.java | 53 ++++++++++++++--
3 files changed, 72 insertions(+), 59 deletions(-)
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index f2734ee..0ba2f46 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -436,7 +436,8 @@ public class ForkStarter
DefaultReporterFactory forkedReporterFactory =
new DefaultReporterFactory( startupReportConfiguration, log, forkNumber );
defaultReporterFactories.add( forkedReporterFactory );
- ForkClient forkClient = new ForkClient( forkedReporterFactory, builder.getImmediateCommands(),
+ TestLessInputStream stream = builder.build();
+ ForkClient forkClient = new ForkClient( forkedReporterFactory, stream,
log, printedErrorStream, forkNumber )
{
@Override
@@ -448,7 +449,6 @@ public class ForkStarter
}
}
};
- TestLessInputStream stream = builder.build();
try
{
return fork( testSet,
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java
index 3014486..372ce00 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStream.java
@@ -228,11 +228,27 @@ public final class TestLessInputStream
}
}
+ /**
+ * Only {@link NotifiableTestStream#noop()} and {@link NotifiableTestStream#shutdown(Shutdown)} are supported.
+ * Another methods throw {@link UnsupportedOperationException}.
+ *
+ * @return commands which are immediately transmitted once to all alive forked JVMs, not cached. As opposite
+ * to cached commands, the immediate commands disappear and cannot be seen by any fork initiated after
+ * the command has dispatched.
+ */
public NotifiableTestStream getImmediateCommands()
{
return immediateCommands;
}
+ /**
+ * Cached commands are sent to all alive or future alive forks. These are termination commands which are not
+ * reversible and therefore only {@link NotifiableTestStream#shutdown(Shutdown)} and
+ * {@link NotifiableTestStream#skipSinceNextTest()} are supported.
+ * Another methods throw {@link UnsupportedOperationException}.
+ *
+ * @return commands which are cached for currently alive or future forks.
+ */
public NotifiableTestStream getCachableCommands()
{
return cachableCommands;
@@ -318,24 +334,13 @@ public final class TestLessInputStream
@Override
public void provideNewTest()
{
+ throw new UnsupportedOperationException();
}
@Override
public void skipSinceNextTest()
{
- Lock lock = rwLock.readLock();
- lock.lock();
- try
- {
- for ( TestLessInputStream aliveStream : TestLessInputStreamBuilder.this.aliveStreams )
- {
- aliveStream.skipSinceNextTest();
- }
- }
- finally
- {
- lock.unlock();
- }
+ throw new UnsupportedOperationException();
}
@Override
@@ -377,19 +382,7 @@ public final class TestLessInputStream
@Override
public void acknowledgeByeEventReceived()
{
- Lock lock = rwLock.readLock();
- lock.lock();
- try
- {
- for ( TestLessInputStream aliveStream : TestLessInputStreamBuilder.this.aliveStreams )
- {
- aliveStream.acknowledgeByeEventReceived();
- }
- }
- finally
- {
- lock.unlock();
- }
+ throw new UnsupportedOperationException();
}
}
@@ -402,6 +395,7 @@ public final class TestLessInputStream
@Override
public void provideNewTest()
{
+ throw new UnsupportedOperationException();
}
@Override
@@ -443,37 +437,13 @@ public final class TestLessInputStream
@Override
public void noop()
{
- Lock lock = rwLock.readLock();
- lock.lock();
- try
- {
- if ( TestLessInputStreamBuilder.this.addTailNodeIfAbsent( NOOP ) )
- {
- release();
- }
- }
- finally
- {
- lock.unlock();
- }
+ throw new UnsupportedOperationException();
}
@Override
public void acknowledgeByeEventReceived()
{
- Lock lock = rwLock.readLock();
- lock.lock();
- try
- {
- if ( TestLessInputStreamBuilder.this.addTailNodeIfAbsent( BYE_ACK ) )
- {
- release();
- }
- }
- finally
- {
- lock.unlock();
- }
+ throw new UnsupportedOperationException();
}
private void release()
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
index 5d9b5af..bbc85d4 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
@@ -33,10 +33,10 @@ import java.util.NoSuchElementException;
import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
import static org.apache.maven.surefire.booter.Command.NOOP;
import static org.apache.maven.surefire.booter.Command.SKIP_SINCE_NEXT_TEST;
-import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
import static org.apache.maven.surefire.booter.MasterProcessCommand.decode;
import static org.apache.maven.surefire.booter.Shutdown.EXIT;
+import static org.apache.maven.surefire.booter.Shutdown.KILL;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@@ -69,9 +69,9 @@ public class TestLessInputStreamBuilderTest
assertFalse( iterator.hasNext() );
- builder.getCachableCommands().noop();
+ builder.getCachableCommands().shutdown( KILL );
assertTrue( iterator.hasNext() );
- assertThat( iterator.next(), is( NOOP ) );
+ assertThat( iterator.next(), is( new Command( SHUTDOWN, "KILL" ) ) );
builder.removeStream( is );
}
@@ -138,14 +138,57 @@ public class TestLessInputStreamBuilderTest
{
TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
TestLessInputStream pluginIs = builder.build();
- builder.getImmediateCommands().acknowledgeByeEventReceived();
+ builder.getImmediateCommands().shutdown( KILL );
builder.getImmediateCommands().noop();
DataInputStream is = new DataInputStream( pluginIs );
Command bye = decode( is );
assertThat( bye, is( notNullValue() ) );
- assertThat( bye.getCommandType(), is( BYE_ACK ) );
+ assertThat( bye.getCommandType(), is( SHUTDOWN ) );
+ assertThat( bye.getData(), is( KILL.name() ) );
Command noop = decode( is );
assertThat( noop, is( notNullValue() ) );
assertThat( noop.getCommandType(), is( MasterProcessCommand.NOOP ) );
}
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldThrowUnsupportedException1()
+ {
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ builder.getImmediateCommands().provideNewTest();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldThrowUnsupportedException2()
+ {
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ builder.getImmediateCommands().skipSinceNextTest();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldThrowUnsupportedException3()
+ {
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ builder.getImmediateCommands().acknowledgeByeEventReceived();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldThrowUnsupportedException4()
+ {
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ builder.getCachableCommands().acknowledgeByeEventReceived();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldThrowUnsupportedException5()
+ {
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ builder.getCachableCommands().provideNewTest();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldThrowUnsupportedException6()
+ {
+ TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
+ builder.getCachableCommands().noop();
+ }
}