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 2020/02/16 22:53:26 UTC
[maven-surefire] branch maven2surefire-jvm-communication updated:
fault tolerant LegacyMasterProcessChannelDecoder
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch maven2surefire-jvm-communication
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/maven2surefire-jvm-communication by this push:
new 85602d5 fault tolerant LegacyMasterProcessChannelDecoder
85602d5 is described below
commit 85602d5a45d30889bf82ec94dfe99ca47879cfd4
Author: tibordigana <ti...@apache.org>
AuthorDate: Sun Feb 16 23:53:15 2020 +0100
fault tolerant LegacyMasterProcessChannelDecoder
---
.../surefire/booter/MasterProcessCommand.java | 11 +-
.../providerapi/MasterProcessChannelDecoder.java | 3 +-
.../maven/surefire/booter/CommandReader.java | 17 +-
.../spi/LegacyMasterProcessChannelDecoder.java | 163 ++++++-----
.../spi/LegacyMasterProcessChannelEncoder.java | 5 +-
...MasterProcessCommandNoMagicNumberException.java | 38 ---
.../spi/MasterProcessUnknownCommandException.java | 39 ---
.../maven/surefire/booter/CommandReaderTest.java | 14 +-
.../maven/surefire/booter/JUnit4SuiteTest.java | 2 +-
.../spi/LegacyMasterProcessChannelDecoderTest.java | 298 +++++++++++++++------
10 files changed, 309 insertions(+), 281 deletions(-)
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
index 6fa85a1..55e604d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
@@ -19,6 +19,8 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
+import javax.annotation.Nonnull;
+
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.Objects.requireNonNull;
@@ -59,11 +61,6 @@ public enum MasterProcessCommand
this.dataType = requireNonNull( dataType, "dataType cannot be null" );
}
- public String getOpcode()
- {
- return opcodeName;
- }
-
public Class<?> getDataType()
{
return dataType;
@@ -74,11 +71,11 @@ public enum MasterProcessCommand
return dataType != Void.class;
}
- public static MasterProcessCommand byOpcode( String opcode )
+ public static MasterProcessCommand byOpcode( @Nonnull String opcode )
{
for ( MasterProcessCommand cmd : values() )
{
- if ( cmd.opcodeName.equals( opcode ) )
+ if ( cmd.opcodeName.equals( requireNonNull( opcode ) ) )
{
return cmd;
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
index 6c64b25..4dc4908 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/providerapi/MasterProcessChannelDecoder.java
@@ -21,6 +21,7 @@ package org.apache.maven.surefire.providerapi;
import org.apache.maven.surefire.booter.Command;
+import javax.annotation.Nonnull;
import java.io.IOException;
/**
@@ -40,7 +41,7 @@ public interface MasterProcessChannelDecoder
* @return decoded command
* @throws IOException exception in channel
*/
- Command decode() throws IOException;
+ @Nonnull Command decode() throws IOException;
@Override
void close() throws IOException;
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
index 4b43fb2..e437f97 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/CommandReader.java
@@ -20,8 +20,6 @@ package org.apache.maven.surefire.booter;
*/
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.surefire.booter.spi.MasterProcessCommandNoMagicNumberException;
-import org.apache.maven.surefire.booter.spi.MasterProcessUnknownCommandException;
import org.apache.maven.surefire.providerapi.CommandChainReader;
import org.apache.maven.surefire.providerapi.CommandListener;
import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
@@ -393,12 +391,12 @@ public final class CommandReader implements CommandChainReader
CommandReader.this.wakeupIterator();
callListeners( command );
break;
- case BYE_ACK:
- callListeners( command );
+ case BYE_ACK:
+ callListeners( command );
// After SHUTDOWN no more commands can come.
- // Hence, do NOT go back to blocking in I/O.
- CommandReader.this.state.set( TERMINATED );
- break;
+ // Hence, do NOT go back to blocking in I/O.
+ CommandReader.this.state.set( TERMINATED );
+ break;
default:
callListeners( command );
break;
@@ -419,11 +417,6 @@ public final class CommandReader implements CommandChainReader
// does not go to finally for non-default config: Shutdown.EXIT or Shutdown.KILL
}
}
- catch ( MasterProcessCommandNoMagicNumberException | MasterProcessUnknownCommandException e )
- {
- DumpErrorSingleton.getSingleton().dumpStreamException( e );
- CommandReader.this.logger.error( e );
- }
catch ( IOException e )
{
CommandReader.this.state.set( TERMINATED );
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
index c22ee11..b4a31f3 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
@@ -23,14 +23,15 @@ import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.MasterProcessCommand;
import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+import javax.annotation.Nonnull;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.MAGIC_NUMBER;
+
/**
* magic number : opcode [: opcode specific data]*
* <br>
@@ -42,125 +43,117 @@ public class LegacyMasterProcessChannelDecoder implements MasterProcessChannelDe
{
private final InputStream is;
- public LegacyMasterProcessChannelDecoder( InputStream is )
+ public LegacyMasterProcessChannelDecoder( @Nonnull InputStream is )
{
this.is = is;
}
- protected boolean hasData( String opcode )
- {
- MasterProcessCommand cmd = MasterProcessCommand.byOpcode( opcode );
- return cmd == null || cmd.hasDataType();
- }
-
- @SuppressWarnings( "checkstyle:innerassignment" )
@Override
+ @Nonnull
+ @SuppressWarnings( "checkstyle:innerassignment" )
public Command decode() throws IOException
{
- List<String> tokens = new ArrayList<>();
- StringBuilder frame = new StringBuilder();
- boolean frameStarted = false;
- boolean frameFinished = false;
- boolean notEndOfStream;
- for ( int r; notEndOfStream = ( r = is.read() ) != -1 ; )
- {
- char c = (char) r;
- if ( frameFinished && c == '\n' )
- {
- continue;
- }
+ List<String> tokens = new ArrayList<>( 3 );
+ StringBuilder token = new StringBuilder( MAGIC_NUMBER.length() );
+ boolean endOfStream;
- if ( !frameStarted )
+ start:
+ do
+ {
+ tokens.clear();
+ token.setLength( 0 );
+ boolean frameStarted = false;
+ for ( int r; !( endOfStream = ( r = is.read() ) == -1 ) ; )
{
- if ( c == ':' )
+ char c = (char) r;
+ if ( !frameStarted )
{
- frameStarted = true;
- frameFinished = false;
- frame.setLength( 0 );
- tokens.clear();
- continue;
+ if ( c == ':' )
+ {
+ frameStarted = true;
+ token.setLength( 0 );
+ tokens.clear();
+ }
}
- }
- else if ( !frameFinished )
- {
- boolean isColon = c == ':';
- if ( isColon || c == '\n' || c == '\r' )
+ else
{
- tokens.add( frame.toString() );
- frame.setLength( 0 );
+ if ( c == ':' )
+ {
+ tokens.add( token.toString() );
+ token.setLength( 0 );
+ FrameCompletion completion = isFrameComplete( tokens );
+ if ( completion == FrameCompletion.COMPLETE )
+ {
+ break;
+ }
+ else if ( completion == FrameCompletion.MALFORMED )
+ {
+ continue start;
+ }
+ }
+ else
+ {
+ token.append( c );
+ }
}
- else
+ }
+
+ if ( isFrameComplete( tokens ) == FrameCompletion.COMPLETE )
+ {
+ MasterProcessCommand cmd = MasterProcessCommand.byOpcode( tokens.get( 1 ) );
+ if ( tokens.size() == 2 )
{
- frame.append( c );
+ return new Command( cmd );
}
- boolean isFinishedFrame = isTokenComplete( tokens );
- if ( isFinishedFrame )
+ else if ( tokens.size() == 3 )
{
- frameFinished = true;
- frameStarted = false;
- break;
+ return new Command( cmd, tokens.get( 2 ) );
}
}
- boolean removed = removeUnsynchronizedTokens( tokens );
- if ( removed && tokens.isEmpty() )
+ if ( endOfStream )
{
- frameStarted = false;
- frameFinished = true;
+ throw new EOFException();
}
}
-
- if ( !notEndOfStream )
- {
- throw new EOFException();
- }
-
- if ( tokens.size() <= 1 ) // todo
- {
- throw new MasterProcessCommandNoMagicNumberException( frame.toString() );
- }
- if ( tokens.size() == 2 )
- {
- return new Command( MasterProcessCommand.byOpcode( tokens.get( 1 ) ) );
- }
- else if ( tokens.size() == 3 )
- {
- return new Command( MasterProcessCommand.byOpcode( tokens.get( 1 ) ), tokens.get( 2 ) );
- }
- else
- {
- throw new MasterProcessUnknownCommandException( frame.toString() );
- }
+ while ( true );
}
- private boolean isTokenComplete( List<String> tokens )
+ private FrameCompletion isFrameComplete( List<String> tokens )
{
- if ( tokens.size() >= 2 )
+ if ( !tokens.isEmpty() && !MAGIC_NUMBER.equals( tokens.get( 0 ) ) )
{
- return hasData( tokens.get( 1 ) ) == ( tokens.size() == 3 );
+ return FrameCompletion.MALFORMED;
}
- return false;
- }
- private boolean removeUnsynchronizedTokens( Collection<String> tokens )
- {
- boolean removed = false;
- for ( Iterator<String> it = tokens.iterator(); it.hasNext(); )
+ if ( tokens.size() >= 2 )
{
- String token = it.next();
- if ( token.equals( MasterProcessCommand.MAGIC_NUMBER ) )
+ String opcode = tokens.get( 1 );
+ MasterProcessCommand cmd = MasterProcessCommand.byOpcode( opcode );
+ if ( cmd == null )
{
- break;
+ return FrameCompletion.MALFORMED;
+ }
+ else if ( cmd.hasDataType() == ( tokens.size() == 3 ) )
+ {
+ return FrameCompletion.COMPLETE;
}
- removed = true;
- it.remove();
- System.err.println( "Forked JVM could not synchronize the '" + token + "' token with preamble sequence." );
}
- return removed;
+ return FrameCompletion.NOT_COMPLETE;
}
@Override
public void close()
{
}
+
+ /**
+ * Determines whether the token is complete of malformed.
+ */
+ private enum FrameCompletion
+ {
+ NOT_COMPLETE,
+ COMPLETE,
+ MALFORMED
+ }
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
index d4b32bd..6ad771e 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelEncoder.java
@@ -29,6 +29,7 @@ import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.SafeThrowable;
import org.apache.maven.surefire.report.StackTraceWriter;
+import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
@@ -80,12 +81,12 @@ public class LegacyMasterProcessChannelEncoder implements MasterProcessChannelEn
private final RunMode runMode;
private volatile boolean trouble;
- public LegacyMasterProcessChannelEncoder( OutputStream out )
+ public LegacyMasterProcessChannelEncoder( @Nonnull OutputStream out )
{
this( out, NORMAL_RUN );
}
- protected LegacyMasterProcessChannelEncoder( OutputStream out, RunMode runMode )
+ protected LegacyMasterProcessChannelEncoder( @Nonnull OutputStream out, @Nonnull RunMode runMode )
{
this.out = requireNonNull( out );
this.runMode = requireNonNull( runMode );
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
deleted file mode 100644
index 261969e..0000000
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessCommandNoMagicNumberException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.maven.surefire.booter.spi;
-
-/*
- * 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.apache.maven.surefire.booter.MasterProcessCommand;
-
-import java.io.IOException;
-
-/**
- * No magic number recognized in the command line, see the JavaDoc in {@link MasterProcessCommand}.
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 3.0.0-M4
- */
-public class MasterProcessCommandNoMagicNumberException extends IOException
-{
- MasterProcessCommandNoMagicNumberException( String line )
- {
- super( "No magic # recognized in the line '" + line + "'" );
- }
-}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
deleted file mode 100644
index 11cab97..0000000
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/MasterProcessUnknownCommandException.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.maven.surefire.booter.spi;
-
-/*
- * 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.apache.maven.surefire.booter.MasterProcessCommand;
-
-import java.io.IOException;
-
-/**
- * No {@link MasterProcessCommand command} recognized according to the opcode
- * encapsulated in the command line, see the JavaDoc in {@link MasterProcessCommand}.
- *
- * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
- * @since 3.0.0-M4
- */
-public class MasterProcessUnknownCommandException extends IOException
-{
- MasterProcessUnknownCommandException( String line )
- {
- super( "Unrecognized command found '" + line + "'" );
- }
-}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index 74d7b16..452c0d2 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -43,13 +43,12 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import static java.nio.charset.StandardCharsets.US_ASCII;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.fest.assertions.Assertions.assertThat;
/**
* Testing singleton {@code MasterProcessReader} in multiple class loaders.
@@ -247,9 +246,7 @@ public class CommandReaderTest
private void addTestToPipeline( String cls )
{
- String cmd = ":maven-surefire-command:"
- + MasterProcessCommand.RUN_CLASS.getOpcode() + ':' + cls + '\n';
- for ( byte cmdByte : cmd.getBytes( US_ASCII ) )
+ for ( byte cmdByte : MasterProcessCommand.RUN_CLASS.encode( cls ) )
{
blockingStream.add( cmdByte );
}
@@ -257,8 +254,7 @@ public class CommandReaderTest
private void addEndOfPipeline()
{
- String cmd = ":maven-surefire-command:" + MasterProcessCommand.TEST_SET_FINISHED.getOpcode() + '\n';
- for ( byte cmdByte : cmd.getBytes( US_ASCII ) )
+ for ( byte cmdByte : MasterProcessCommand.TEST_SET_FINISHED.encode() )
{
blockingStream.add( cmdByte );
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
index a7c6298..280774e 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/JUnit4SuiteTest.java
@@ -46,7 +46,7 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( BooterDeserializerTest.class ) );
suite.addTestSuite( ClasspathTest.class );
suite.addTestSuite( PropertiesWrapperTest.class );
- suite.addTestSuite( LegacyMasterProcessChannelDecoderTest.class );
+ suite.addTest( new JUnit4TestAdapter( LegacyMasterProcessChannelDecoderTest.class ) );
suite.addTest( new JUnit4TestAdapter( LegacyMasterProcessChannelEncoderTest.class ) );
suite.addTestSuite( SurefireReflectorTest.class );
return suite;
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java
index 13efee2..5cf6b65 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java
@@ -19,112 +19,192 @@ package org.apache.maven.surefire.booter.spi;
* under the License.
*/
-import junit.framework.TestCase;
import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.MasterProcessCommand;
import org.apache.maven.surefire.booter.Shutdown;
+import org.junit.Test;
import java.io.ByteArrayInputStream;
+import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.TEST_SET_FINISHED;
+import static org.apache.maven.surefire.booter.Shutdown.DEFAULT;
+import static org.apache.maven.surefire.booter.Shutdown.EXIT;
+import static org.apache.maven.surefire.booter.Shutdown.KILL;
import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
/**
* Tests for {@link LegacyMasterProcessChannelDecoder}.
*/
public class LegacyMasterProcessChannelDecoderTest
- extends TestCase
{
- public void testDataToByteArrayAndBack() throws IOException
+ @Test
+ public void testDecoderRunClass() throws IOException
{
- for ( MasterProcessCommand commandType : MasterProcessCommand.values() )
- {
- switch ( commandType )
- {
- case RUN_CLASS:
- assertEquals( String.class, commandType.getDataType() );
- byte[] encoded = commandType.encode( "pkg.Test" );
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:run-testclass:pkg.Test:" );
- byte[] line = addNL( encoded, '\n' );
- InputStream is = new ByteArrayInputStream( line );
- LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
- Command command = decoder.decode();
- assertThat( command.getCommandType(), is( commandType ) );
- assertThat( command.getData(), is( "pkg.Test" ) );
- break;
- case TEST_SET_FINISHED:
- assertThat( commandType ).isSameAs( Command.TEST_SET_FINISHED.getCommandType() );
- assertEquals( Void.class, commandType.getDataType() );
- encoded = commandType.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:testset-finished:" );
- is = new ByteArrayInputStream( encoded );
- decoder = new LegacyMasterProcessChannelDecoder( is );
- command = decoder.decode();
- assertThat( command.getCommandType(), is( commandType ) );
- assertNull( command.getData() );
- break;
- case SKIP_SINCE_NEXT_TEST:
- assertThat( commandType ).isSameAs( Command.SKIP_SINCE_NEXT_TEST.getCommandType() );
- assertEquals( Void.class, commandType.getDataType() );
- encoded = commandType.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:skip-since-next-test:" );
- is = new ByteArrayInputStream( encoded );
- decoder = new LegacyMasterProcessChannelDecoder( is );
- command = decoder.decode();
- assertThat( command.getCommandType(), is( commandType ) );
- assertNull( command.getData() );
- break;
- case SHUTDOWN:
- assertEquals( String.class, commandType.getDataType() );
- encoded = commandType.encode( Shutdown.EXIT.name() );
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:shutdown:EXIT:" );
- is = new ByteArrayInputStream( encoded );
- decoder = new LegacyMasterProcessChannelDecoder( is );
- command = decoder.decode();
- assertThat( command.getCommandType(), is( commandType ) );
- assertThat( command.getData(), is( "EXIT" ) );
- break;
- case NOOP:
- assertThat( commandType ).isSameAs( Command.NOOP.getCommandType() );
- assertEquals( Void.class, commandType.getDataType() );
- encoded = commandType.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:noop:" );
- is = new ByteArrayInputStream( encoded );
- decoder = new LegacyMasterProcessChannelDecoder( is );
- command = decoder.decode();
- assertThat( command.getCommandType(), is( commandType ) );
- assertNull( command.getData() );
- break;
- case BYE_ACK:
- assertThat( commandType ).isSameAs( Command.BYE_ACK.getCommandType() );
- assertEquals( Void.class, commandType.getDataType() );
- encoded = commandType.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:bye-ack:" );
- is = new ByteArrayInputStream( encoded );
- decoder = new LegacyMasterProcessChannelDecoder( is );
- command = decoder.decode();
- assertThat( command.getCommandType(), is( commandType ) );
- assertNull( command.getData() );
- break;
- default:
- fail();
- }
- }
+ assertEquals( String.class, RUN_CLASS.getDataType() );
+ byte[] encoded = RUN_CLASS.encode( "pkg.Test" );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:run-testclass:pkg.Test:" );
+ byte[] line = addNL( encoded, '\n' );
+ InputStream is = new ByteArrayInputStream( line );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( RUN_CLASS );
+ assertThat( command.getData() ).isEqualTo( "pkg.Test" );
+ }
+
+ @Test
+ public void testDecoderTestsetFinished() throws IOException
+ {
+ Command command = Command.TEST_SET_FINISHED;
+ assertThat( command.getCommandType() ).isSameAs( TEST_SET_FINISHED );
+ assertEquals( Void.class, TEST_SET_FINISHED.getDataType() );
+ byte[] encoded = TEST_SET_FINISHED.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:testset-finished:" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( TEST_SET_FINISHED );
+ assertNull( command.getData() );
+ }
+
+ @Test
+ public void testDecoderSkipSinceNextTest() throws IOException
+ {
+ Command command = Command.SKIP_SINCE_NEXT_TEST;
+ assertThat( command.getCommandType() ).isSameAs( SKIP_SINCE_NEXT_TEST );
+ assertEquals( Void.class, SKIP_SINCE_NEXT_TEST.getDataType() );
+ byte[] encoded = SKIP_SINCE_NEXT_TEST.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:skip-since-next-test:" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( SKIP_SINCE_NEXT_TEST );
+ assertNull( command.getData() );
+ }
+
+ @Test
+ public void testDecoderShutdownWithExit() throws IOException
+ {
+ Shutdown shutdownType = EXIT;
+ assertEquals( String.class, SHUTDOWN.getDataType() );
+ byte[] encoded = SHUTDOWN.encode( shutdownType.name() );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:shutdown:" + shutdownType + ":" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( SHUTDOWN );
+ assertThat( command.getData() ).isEqualTo( shutdownType.name() );
}
- public void testShouldDecodeTwoCommands() throws IOException
+ @Test
+ public void testDecoderShutdownWithKill() throws IOException
{
- String cmd = ":maven-surefire-command:bye-ack\n:maven-surefire-command:bye-ack:";
+ Shutdown shutdownType = KILL;
+ assertEquals( String.class, SHUTDOWN.getDataType() );
+ byte[] encoded = SHUTDOWN.encode( shutdownType.name() );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:shutdown:" + shutdownType + ":" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( SHUTDOWN );
+ assertThat( command.getData() ).isEqualTo( shutdownType.name() );
+ }
+
+ @Test
+ public void testDecoderShutdownWithDefault() throws IOException
+ {
+ Shutdown shutdownType = DEFAULT;
+ assertEquals( String.class, SHUTDOWN.getDataType() );
+ byte[] encoded = SHUTDOWN.encode( shutdownType.name() );
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:shutdown:" + shutdownType + ":" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( SHUTDOWN );
+ assertThat( command.getData() ).isEqualTo( shutdownType.name() );
+ }
+
+ @Test
+ public void testDecoderNoop() throws IOException
+ {
+ assertThat( NOOP ).isSameAs( Command.NOOP.getCommandType() );
+ assertEquals( Void.class, NOOP.getDataType() );
+ byte[] encoded = NOOP.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:noop:" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( NOOP );
+ assertNull( command.getData() );
+ }
+
+ @Test
+ public void shouldIgnoreDamagedStream() throws IOException
+ {
+ assertThat( BYE_ACK ).isSameAs( Command.BYE_ACK.getCommandType() );
+ assertEquals( Void.class, BYE_ACK.getDataType() );
+ byte[] encoded = BYE_ACK.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:bye-ack:" );
+ byte[] streamContent = ( "<something>" + new String( encoded ) + "<damaged>" ).getBytes();
+ ByteArrayInputStream is = new ByteArrayInputStream( streamContent );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( BYE_ACK );
+ assertNull( command.getData() );
+ }
+
+ @Test
+ public void shouldIgnoreDamagedHeader() throws IOException
+ {
+ assertThat( BYE_ACK ).isSameAs( Command.BYE_ACK.getCommandType() );
+ assertEquals( Void.class, BYE_ACK.getDataType() );
+ byte[] encoded = BYE_ACK.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:bye-ack:" );
+ byte[] streamContent = ( ":<damaged>:" + new String( encoded ) ).getBytes();
+ ByteArrayInputStream is = new ByteArrayInputStream( streamContent );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( BYE_ACK );
+ assertNull( command.getData() );
+ }
+
+ @Test
+ public void testDecoderByeAck() throws IOException
+ {
+ assertThat( BYE_ACK ).isSameAs( Command.BYE_ACK.getCommandType() );
+ assertEquals( Void.class, BYE_ACK.getDataType() );
+ byte[] encoded = BYE_ACK.encode();
+ assertThat( new String( encoded ) )
+ .isEqualTo( ":maven-surefire-command:bye-ack:" );
+ ByteArrayInputStream is = new ByteArrayInputStream( encoded );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( BYE_ACK );
+ assertNull( command.getData() );
+ }
+
+ @Test
+ public void shouldDecodeTwoCommands() throws IOException
+ {
+ String cmd = ":maven-surefire-command:bye-ack:\r\n:maven-surefire-command:bye-ack:";
InputStream is = new ByteArrayInputStream( cmd.getBytes() );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
@@ -135,6 +215,50 @@ public class LegacyMasterProcessChannelDecoderTest
command = decoder.decode();
assertThat( command.getCommandType() ).isEqualTo( BYE_ACK );
assertThat( command.getData() ).isNull();
+
+ decoder.close();
+ }
+
+ @Test( expected = EOFException.class )
+ public void testIncompleteCommand() throws IOException
+ {
+
+ ByteArrayInputStream is = new ByteArrayInputStream( ":maven-surefire-command:".getBytes() );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ decoder.decode();
+ fail();
+ }
+
+ @Test( expected = EOFException.class )
+ public void testIncompleteCommandStart() throws IOException
+ {
+
+ ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {':', '\r'} );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+ decoder.decode();
+ fail();
+ }
+
+ @Test( expected = EOFException.class )
+ public void shouldNotDecodeCorruptedCommand() throws IOException
+ {
+ String cmd = ":maven-surefire-command:bye-ack ::maven-surefire-command:";
+ InputStream is = new ByteArrayInputStream( cmd.getBytes() );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+
+ decoder.decode();
+ }
+
+ @Test
+ public void shouldSkipCorruptedCommand() throws IOException
+ {
+ String cmd = ":maven-surefire-command:bye-ack\r\n::maven-surefire-command:noop:";
+ InputStream is = new ByteArrayInputStream( cmd.getBytes() );
+ LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( is );
+
+ Command command = decoder.decode();
+ assertThat( command.getCommandType() ).isSameAs( NOOP );
+ assertNull( command.getData() );
}
private static byte[] addNL( byte[] encoded, char... newLines )