Added: qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapperTest.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapperTest.java?rev=1484842&view=auto ============================================================================== --- qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapperTest.java (added) +++ qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapperTest.java Tue May 21 15:49:52 2013 @@ -0,0 +1,179 @@ +/* + * + * 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. + * + */ +package org.apache.qpid.proton.engine.impl.ssl; + +import static org.apache.qpid.proton.engine.impl.TransportTestHelper.assertByteBufferContentEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import java.nio.ByteBuffer; + +import org.apache.qpid.proton.engine.impl.TransportWrapper; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class SslHandshakeSniffingTransportWrapperTest +{ + private static final byte[] EXAMPLE_SSL_V3_HANDSHAKE_BYTES = new byte[] {0x16, 0x03, 0x02, 0x00, 0x31}; + private static final byte[] EXAMPLE_SSL_V2_HANDSHAKE_BYTES = new byte[] {0x00, 0x00, 0x01, 0x03, 0x00}; + + private SslTransportWrapper _secureTransportWrapper = mock(SslTransportWrapper.class); + private TransportWrapper _plainTransportWrapper = mock(TransportWrapper.class); + private SslTransportWrapper _sniffingWrapper = new SslHandshakeSniffingTransportWrapper(_secureTransportWrapper, _plainTransportWrapper); + + @Rule + public ExpectedException _expectedException = ExpectedException.none(); + + @Test + public void testGetInputBufferGetOutputBufferWithNonSsl() + { + testInputAndOutput("INPUT".getBytes(), _plainTransportWrapper); + } + + @Test + public void testWithSSLv2() + { + testInputAndOutput(EXAMPLE_SSL_V2_HANDSHAKE_BYTES, _secureTransportWrapper); + } + + @Test + public void testWithSSLv3TLS() + { + testInputAndOutput(EXAMPLE_SSL_V3_HANDSHAKE_BYTES, _secureTransportWrapper); + } + + private void testInputAndOutput(byte[] input, TransportWrapper transportThatShouldBeUsed) + { + byte[] output = "OUTPUT".getBytes(); + + ByteBuffer underlyingInputBuffer = ByteBuffer.allocate(1024); + ByteBuffer underlyingOutputBuffer = ByteBuffer.wrap(output); + + // set up underlying transport + when(transportThatShouldBeUsed.getInputBuffer()).thenReturn(underlyingInputBuffer); + when(transportThatShouldBeUsed.getOutputBuffer()).thenReturn(underlyingOutputBuffer); + + // do input and verify underlying calls were made + ByteBuffer inputBuffer = _sniffingWrapper.getInputBuffer(); + inputBuffer.put(input); + _sniffingWrapper.processInput(); + + verify(transportThatShouldBeUsed).getInputBuffer(); + verify(transportThatShouldBeUsed).processInput(); + + // check the wrapped input actually received the expected bytes + underlyingInputBuffer.flip(); + assertByteBufferContentEquals(input, underlyingInputBuffer); + + // do output and check we get the correct transport's output + ByteBuffer outputBuffer = _sniffingWrapper.getOutputBuffer(); + verify(transportThatShouldBeUsed).getOutputBuffer(); + + assertByteBufferContentEquals(output, outputBuffer); + _sniffingWrapper.outputConsumed(); + verify(transportThatShouldBeUsed).outputConsumed(); + + verifyZeroInteractionsWithOtherTransport(transportThatShouldBeUsed); + } + + @Test + public void testTooFewBytesToMakeDetermination() + { + byte[] sourceBuffer = new byte[] {0x00}; + + try + { + _sniffingWrapper.getInputBuffer().put(sourceBuffer); + + _expectedException.expect(IllegalArgumentException.class); + _sniffingWrapper.processInput(); + } + finally + { + verifyZeroInteractions(_secureTransportWrapper, _plainTransportWrapper); + } + } + + @Test + public void testGetSslAttributesWhenProtocolIsNotYetDetermined_returnNull() + { + assertEquals("Cipher name should be null", null, _sniffingWrapper.getCipherName()); + assertEquals("Protocol name should be null", null, _sniffingWrapper.getProtocolName()); + verifyZeroInteractions(_secureTransportWrapper, _plainTransportWrapper); + } + + @Test + public void testGetSslAttributesWhenUsingNonSsl_returnNull() + { + testGetSslAttributes("INPUT".getBytes(), _plainTransportWrapper, null, null); + } + + /** + * Tests {@link SslHandshakeSniffingTransportWrapper#getCipherName()} + * and {@link SslHandshakeSniffingTransportWrapper#getProtocolName()}. + */ + @Test + public void testGetSslAttributesWhenUsingSsl() + { + String cipherName = "testCipherName"; + String protocolName = "testProtocolName"; + when(_secureTransportWrapper.getCipherName()).thenReturn(cipherName); + when(_secureTransportWrapper.getProtocolName()).thenReturn(protocolName); + + testGetSslAttributes(EXAMPLE_SSL_V2_HANDSHAKE_BYTES, _secureTransportWrapper, cipherName, protocolName); + } + + private void testGetSslAttributes( + byte[] input, TransportWrapper transportThatShouldBeUsed, + String expectedCipherName, String expectedProtocolName) + { + ByteBuffer underlyingInputBuffer = ByteBuffer.allocate(1024); + when(transportThatShouldBeUsed.getInputBuffer()).thenReturn(underlyingInputBuffer); + + _sniffingWrapper.getInputBuffer().put(input); + _sniffingWrapper.processInput(); + + assertEquals(expectedCipherName, _sniffingWrapper.getCipherName()); + assertEquals(expectedProtocolName, _sniffingWrapper.getProtocolName()); + + verifyZeroInteractionsWithOtherTransport(transportThatShouldBeUsed); + } + + private void verifyZeroInteractionsWithOtherTransport(TransportWrapper transportThatShouldBeUsed) + { + final TransportWrapper transportThatShouldNotBeUsed; + if(transportThatShouldBeUsed == _plainTransportWrapper) + { + transportThatShouldNotBeUsed = _secureTransportWrapper; + } + else + { + transportThatShouldNotBeUsed = _plainTransportWrapper; + } + + verifyZeroInteractions(transportThatShouldNotBeUsed); + } + +}
Modified: qpid/proton/trunk/tests/java/org/apache/qpid/proton/JythonTest.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/java/org/apache/qpid/proton/JythonTest.java?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/java/org/apache/qpid/proton/JythonTest.java (original) +++ qpid/proton/trunk/tests/java/org/apache/qpid/proton/JythonTest.java Tue May 21 15:49:52 2013 @@ -20,6 +20,7 @@ */ package org.apache.qpid.proton; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; @@ -35,7 +36,9 @@ import org.python.util.PythonInterpreter /** * Runs all the python tests, or just those that match the system property {@value #TEST_PATTERN_SYSTEM_PROPERTY} - * if it exists + * if it exists. + * Use {@value #TEST_INVOCATIONS_SYSTEM_PROPERTY} to specify the number of repetitions, or use 0 + * for unlimited repetitions. */ public class JythonTest { @@ -49,7 +52,12 @@ public class JythonTest /** Name of the junit style xml report to be written by the python test script */ private static final String XML_REPORT_NAME = "TEST-jython-test-results.xml"; - private static final String TEST_PATTERN_SYSTEM_PROPERTY = "proton.pythontest.pattern"; + public static final String TEST_PATTERN_SYSTEM_PROPERTY = "proton.pythontest.pattern"; + + /** The number of times to run the test, or forever if zero */ + public static final String TEST_INVOCATIONS_SYSTEM_PROPERTY = "proton.pythontest.invocations"; + + public static final String ALWAYS_COLORIZE_SYSTEM_PROPERTY = "proton.pythontest.always_colorize"; @Test public void test() throws Exception @@ -64,6 +72,26 @@ public class JythonTest LOGGER.info("About to call Jython test script: '" + testScript + "' with '" + testRoot + "' added to Jython path"); + int maxInvocations = Integer.getInteger(TEST_INVOCATIONS_SYSTEM_PROPERTY, 1); + assertTrue("Number of invocations should be non-negative", maxInvocations >= 0); + boolean loopForever = maxInvocations == 0; + if(maxInvocations > 1) + { + LOGGER.info("Will invoke Python test " + maxInvocations + " times"); + } + if(loopForever) + { + LOGGER.info("Will repeatedly invoke Python test forever"); + } + int invocations = 1; + while(loopForever || invocations++ <= maxInvocations) + { + runTestOnce(testScript, interp, invocations); + } + } + + private void runTestOnce(String testScript, PythonInterpreter interp, int invocationsSoFar) + { try { interp.execfile(testScript); @@ -83,7 +111,7 @@ public class JythonTest // This unusual code is necessary because PyException toString() contains the useful Python traceback // and getMessage() is usually null - fail("Caught PyException: " + e.toString() + " with message: " + e.getMessage()); + fail("Caught PyException on invocation number " + invocationsSoFar + ": " + e.toString() + " with message: " + e.getMessage()); } } } @@ -91,7 +119,6 @@ public class JythonTest private PythonInterpreter createInterpreterWithArgs(String xmlReportFile) { PySystemState systemState = new PySystemState(); - String testPattern = System.getProperty(TEST_PATTERN_SYSTEM_PROPERTY); if (xmlReportFile != null) { @@ -99,11 +126,17 @@ public class JythonTest systemState.argv.append(new PyString(xmlReportFile)); } + String testPattern = System.getProperty(TEST_PATTERN_SYSTEM_PROPERTY); if(testPattern != null) { systemState.argv.append(new PyString(testPattern)); } + if(Boolean.getBoolean(ALWAYS_COLORIZE_SYSTEM_PROPERTY)) + { + systemState.argv.append(new PyString("--always-colorize")); + } + PythonInterpreter interp = new PythonInterpreter(null, systemState); return interp; } Modified: qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatter.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatter.java?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatter.java (original) +++ qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatter.java Tue May 21 15:49:52 2013 @@ -21,10 +21,10 @@ package org.apache.qpid.proton.systemtes public class BinaryFormatter { - public String format(byte[] binaryData, int length) + public String format(byte[] binaryData) { StringBuilder stringBuilder = new StringBuilder(); - for(int i = 0; i < length; i++) + for(int i = 0; i < binaryData.length; i++) { byte theByte = binaryData[i]; String formattedByte = formatByte(theByte); Modified: qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatterTest.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatterTest.java?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatterTest.java (original) +++ qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/BinaryFormatterTest.java Tue May 21 15:49:52 2013 @@ -30,14 +30,14 @@ public class BinaryFormatterTest @Test public void testSingleCharacter() { - assertEquals("[ A ]", _binaryFormatter.format("A".getBytes(), 1)); + assertEquals("[ A ]", _binaryFormatter.format("A".getBytes())); } @Test public void testSingleSmallNonCharacter() { byte[] bytes = new byte[] { (byte)0x1 }; - assertEquals("[x01]", _binaryFormatter.format(bytes, 1)); + assertEquals("[x01]", _binaryFormatter.format(bytes)); } @Test @@ -46,7 +46,7 @@ public class BinaryFormatterTest int numberToUse = 0xa2; byte byteToUse = (byte)numberToUse; byte[] bytes = new byte[] { byteToUse }; - assertEquals("[xa2]", _binaryFormatter.format(bytes, 1)); + assertEquals("[xa2]", _binaryFormatter.format(bytes)); } @Test @@ -56,7 +56,7 @@ public class BinaryFormatterTest System.arraycopy("ABC".getBytes(), 0, binaryData, 0, 3); binaryData[3] = (byte)0xff; - String formattedString = _binaryFormatter.format(binaryData, binaryData.length); + String formattedString = _binaryFormatter.format(binaryData); String expected = "[ A ][ B ][ C ][xff]"; assertEquals(expected, formattedString); } Modified: qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java (original) +++ qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java Tue May 21 15:49:52 2013 @@ -29,7 +29,8 @@ import static org.apache.qpid.proton.sys import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; -import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.logging.Logger; import org.apache.qpid.proton.ProtonFactoryLoader; @@ -59,6 +60,10 @@ import org.junit.Test; * * org.apache.qpid.proton.logging.LoggingProtocolTracer.sent.level = ALL * + * and to see the byte level trace, add the following: + * + * org.apache.qpid.proton.systemtests.ProtonEngineExampleTest.level = ALL + * * Does not illustrate use of the Messenger API. */ public class ProtonEngineExampleTest @@ -181,9 +186,9 @@ public class ProtonEngineExampleTest _client.message = _messageFactory.createMessage(); Section messageBody = new AmqpValue("Hello"); _client.message.setBody(messageBody); - _client.messageData = newByteArray(); + _client.messageData = new byte[BUFFER_SIZE]; int lengthOfEncodedMessage = _client.message.encode(_client.messageData, 0, BUFFER_SIZE); - _testLoggingHelper.prettyPrintBytes(TestLoggingHelper.MESSAGE_PREFIX, _client.messageData, lengthOfEncodedMessage); + _testLoggingHelper.prettyPrint(TestLoggingHelper.MESSAGE_PREFIX, Arrays.copyOf(_client.messageData, lengthOfEncodedMessage)); byte[] deliveryTag = "delivery1".getBytes(); _client.delivery = _client.sender.delivery(deliveryTag); @@ -218,7 +223,7 @@ public class ProtonEngineExampleTest assertFalse(_server.delivery.isPartial()); assertTrue(_server.delivery.isReadable()); - _server.messageData = newByteArray(); + _server.messageData = new byte[BUFFER_SIZE]; int numberOfBytesProducedByReceiver = _server.receiver.recv(_server.messageData, 0, BUFFER_SIZE); assertEquals(numberOfBytesAcceptedBySender, numberOfBytesProducedByReceiver); @@ -364,47 +369,43 @@ public class ProtonEngineExampleTest pumpServerToClient(); } - private void pumpClientToServer() throws UnsupportedEncodingException + private void pumpClientToServer() { - final byte[] clientOutput = newByteArray(); - int clientOutputLength = _client.transport.output(clientOutput, 0, BUFFER_SIZE); - _testLoggingHelper.prettyPrintBytes(TestLoggingHelper.CLIENT_PREFIX + ">>> ", clientOutput, clientOutputLength); + ByteBuffer clientBuffer = _client.transport.getOutputBuffer(); - assertTrue("Client expected to produce some output", clientOutputLength > 0); + _testLoggingHelper.prettyPrint(TestLoggingHelper.CLIENT_PREFIX + ">>> ", clientBuffer); + assertTrue("Client expected to produce some output", clientBuffer.hasRemaining()); - int serverInputLength = _server.transport.input(clientOutput, 0, clientOutputLength); - LOGGER.fine(" >>>" + TestLoggingHelper.SERVER_PREFIX + " " + serverInputLength + " byte(s)"); + ByteBuffer serverBuffer = _server.transport.getInputBuffer(); - assertEquals("Server expected to consume all client's output", clientOutputLength, serverInputLength); - } + serverBuffer.put(clientBuffer); - private void assertClientHasNothingToOutput() throws UnsupportedEncodingException - { - final byte[] clientOutput1 = newByteArray(); - int clientOutputLength = _client.transport.output(clientOutput1, 0, BUFFER_SIZE); - assertEquals(0, clientOutputLength); - } + assertEquals("Server expected to consume all client's output", 0, clientBuffer.remaining()); + _client.transport.outputConsumed(); + _server.transport.processInput().checkIsOk(); + } - private void pumpServerToClient() throws UnsupportedEncodingException + private void pumpServerToClient() { - final byte[] serverOutput = newByteArray(); - int serverOutputLength = _server.transport.output(serverOutput, 0, BUFFER_SIZE); + ByteBuffer serverBuffer = _server.transport.getOutputBuffer(); - _testLoggingHelper.prettyPrintBytes(" <<<" + TestLoggingHelper.SERVER_PREFIX + " ", serverOutput, serverOutputLength); + _testLoggingHelper.prettyPrint(" <<<" + TestLoggingHelper.SERVER_PREFIX + " ", serverBuffer); + assertTrue("Server expected to produce some output", serverBuffer.hasRemaining()); - assertTrue("Server expected to produce some output", serverOutputLength > 0); + ByteBuffer clientBuffer = _client.transport.getInputBuffer(); - int clientInputLength = _client.transport.input(serverOutput, 0, serverOutputLength); - LOGGER.fine(TestLoggingHelper.CLIENT_PREFIX + "<<< " + clientInputLength + " byte(s)"); + clientBuffer.put(serverBuffer); - assertEquals("Client expected to consume all server's output", serverOutputLength, clientInputLength); + assertEquals("Client expected to consume all server's output", 0, serverBuffer.remaining()); + + _client.transport.processInput().checkIsOk(); + _server.transport.outputConsumed(); } - /** returns a byte array sized to be big enough to avoid left-overs */ - private byte[] newByteArray() + private void assertClientHasNothingToOutput() { - return new byte[BUFFER_SIZE]; + assertEquals(0, _client.transport.getOutputBuffer().remaining()); + _client.transport.outputConsumed(); } - } Modified: qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/TestLoggingHelper.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/TestLoggingHelper.java?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/TestLoggingHelper.java (original) +++ qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/TestLoggingHelper.java Tue May 21 15:49:52 2013 @@ -18,7 +18,7 @@ */ package org.apache.qpid.proton.systemtests; -import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; import java.util.logging.Logger; /** @@ -63,9 +63,19 @@ public class TestLoggingHelper _logger = logger; } - public void prettyPrintBytes(String prefix, final byte[] bytes, int length) throws UnsupportedEncodingException + public void prettyPrint(String prefix, byte[] bytes) { - _logger.fine(prefix + " " + length + " byte(s) " + _binaryFormatter.format(bytes, length)); + _logger.fine(prefix + " " + bytes.length + " byte(s) " + _binaryFormatter.format(bytes)); + } + + /** + * Note that ByteBuffer is assumed to be readable. Its state is unchanged by this operation. + */ + public void prettyPrint(String prefix, ByteBuffer buf) + { + byte[] bytes = new byte[buf.remaining()]; + buf.duplicate().get(bytes); + prettyPrint(prefix, bytes); } public static String bold(String string) @@ -73,4 +83,5 @@ public class TestLoggingHelper return BOLD + string + TestLoggingHelper.COLOUR_RESET; } + } Modified: qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java (original) +++ qpid/proton/trunk/tests/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java Tue May 21 15:49:52 2013 @@ -45,6 +45,7 @@ import org.apache.qpid.proton.engine.Eng import org.apache.qpid.proton.engine.Session; import org.apache.qpid.proton.engine.Transport; import org.apache.qpid.proton.engine.TransportException; +import org.apache.qpid.proton.engine.impl.AmqpFramer; import org.junit.Ignore; import org.junit.Test; Modified: qpid/proton/trunk/tests/pom.xml URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/pom.xml?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/pom.xml (original) +++ qpid/proton/trunk/tests/pom.xml Tue May 21 15:49:52 2013 @@ -24,16 +24,22 @@ <artifactId>tests</artifactId> <name>tests</name> - <description>The Proton system tests execute against either the Java or the C implementations, based on the chosen profile. + <description>The Proton system tests execute against either the Java or the C implementations, +based on the chosen profile. -To execute, run either "mvn test -P proton-j" or "mvn test -P proton-jni". +To execute, run either "mvn test" or "mvn test -P proton-jni". -To reduce the set of Python tests run, set system property proton.pythontest.pattern, for example: +Example of advanced usage (all of the -D flags are optional): -mvn test -Dproton.pythontest.pattern='proton_tests.transport.TransportTest.*' +mvn test \ +-P proton-jni \ +-Dproton.pythontest.pattern='proton_tests.transport.TransportTest.*' \ +-Dproton.pythontest.invocations=20 \ +-Dproton.pythontest.always_colorize=true \ +-Dproton-c-build-dir=/path/to/build/dir -The proton-jni profile looks for the JNI jar and native libraries under directory <basedir>/build/proton-c. -To override this, run Maven like so: "mvn test -P proton-jni -Dproton-c-build-dir=/path/to/build/dir".</description> +By default, the proton-jni profile looks for the JNI jar and native libraries under +directory <basedir>/build/proton-c.</description> <properties> <testReportOutputDirectory>${basedir}/target/surefire-reports</testReportOutputDirectory> @@ -80,6 +86,23 @@ To override this, run Maven like so: &qu <version>2.5.3</version> <scope>test</scope> </dependency> + + <dependency> + <!-- proton-j-impl is even required for profile proton-jni so we can use EncoderImpl and DecoderImpl to + generate test data, hence this dependency appearing here and not just in the proton-j profile --> + <groupId>org.apache.qpid</groupId> + <artifactId>proton-j-impl</artifactId> + <version>1.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <!-- Depend on test helper classes contained with test-jar from proton-j-impl --> + <groupId>org.apache.qpid</groupId> + <artifactId>proton-j-impl</artifactId> + <version>1.0-SNAPSHOT</version> + <scope>test</scope> + <type>test-jar</type> + </dependency> </dependencies> <profiles> @@ -101,14 +124,6 @@ To override this, run Maven like so: &qu </plugin> </plugins> </build> - <dependencies> - <dependency> - <groupId>org.apache.qpid</groupId> - <artifactId>proton-j-impl</artifactId> - <version>1.0-SNAPSHOT</version> - <scope>runtime</scope> - </dependency> - </dependencies> </profile> <profile> <id>proton-jni</id> @@ -142,13 +157,6 @@ To override this, run Maven like so: &qu <scope>system</scope> <systemPath>${jni-jar}</systemPath> </dependency> - <!-- proton-j-impl is required so we can use EncoderImpl and DecoderImpl to generate test data --> - <dependency> - <groupId>org.apache.qpid</groupId> - <artifactId>proton-j-impl</artifactId> - <version>1.0-SNAPSHOT</version> - <scope>runtime</scope> - </dependency> </dependencies> </profile> </profiles> Modified: qpid/proton/trunk/tests/python/proton-test URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton-test?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/python/proton-test (original) +++ qpid/proton/trunk/tests/python/proton-test Tue May 21 15:49:52 2013 @@ -62,6 +62,8 @@ parser.add_option("-D", "--define", meta action="append", default=[], help="define test parameters") parser.add_option("-x", "--xml", metavar="XML", dest="xml", help="write test results in Junit style xml suitable for use by CI tools etc") +parser.add_option("-a", "--always-colorize", action="store_true", dest="always_colorize", default=False, + help="always colorize the test results rather than relying on terminal tty detection. Useful when invoked from Jython/Maven.") class Config: @@ -164,15 +166,13 @@ KEYWORDS = {"pass": (32,), "elapsed": (34,), "average": (34,)} -COLORIZE = is_smart() - def colorize_word(word, text=None): if text is None: text = word return colorize(text, *KEYWORDS.get(word, ())) def colorize(text, *attrs): - if attrs and COLORIZE: + if attrs and (is_smart() or opts.always_colorize): return "%s%s%s" % (vt100_attrs(*attrs), text, vt100_reset) else: return text Modified: qpid/proton/trunk/tests/python/proton_tests/common.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/common.py?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/python/proton_tests/common.py (original) +++ qpid/proton/trunk/tests/python/proton_tests/common.py Tue May 21 15:49:52 2013 @@ -22,7 +22,7 @@ from threading import Thread from socket import socket, AF_INET, SOCK_STREAM from subprocess import Popen,PIPE import sys, os -from proton import Driver, Connection, SASL, Endpoint, Delivery +from proton import Driver, Connection, Transport, SASL, Endpoint, Delivery def free_tcp_ports(count=1): @@ -46,6 +46,42 @@ def free_tcp_ports(count=1): return ports +def pump(transport1, transport2, buffer_size=1024): + """ Transfer all pending bytes between two Proton engines + by repeatedly calling input and output. + Asserts that each engine accepts some bytes every time + (unless it's already closed). + """ + + out1_leftover_by_t2 = "" + out2_leftover_by_t1 = "" + i = 0 + + while True: + out1 = out1_leftover_by_t2 + (transport1.output(buffer_size) or "") + out2 = out2_leftover_by_t1 + (transport2.output(buffer_size) or "") + + if out1: + number_t2_consumed = transport2.input(out1) + if number_t2_consumed is None: + # special None return value means input is closed so discard the leftovers + out1_leftover_by_t2 = "" + else: + assert number_t2_consumed > 0, (number_t2_consumed, len(out1), out1[:100]) + out1_leftover_by_t2 = out1[number_t2_consumed:] + + if out2: + number_t1_consumed = transport1.input(out2) + if number_t1_consumed is None: + # special None return value means input is closed so discard the leftovers + out2_leftover_by_t1 = "" + else: + assert number_t1_consumed > 0, (number_t1_consumed, len(out1), out1[:100]) + out2_leftover_by_t1 = out2[number_t1_consumed:] + + if not out1 and not out2: break + i = i + 1 + class Test: def __init__(self, name): Modified: qpid/proton/trunk/tests/python/proton_tests/engine.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/engine.py?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/python/proton_tests/engine.py (original) +++ qpid/proton/trunk/tests/python/proton_tests/engine.py Tue May 21 15:49:52 2013 @@ -20,6 +20,7 @@ import os, common from time import time, sleep from proton import * +from common import pump # future test areas # + different permutations of setup @@ -30,21 +31,6 @@ from proton import * OUTPUT_SIZE = 10*1024 -def pump(t1, t2, buffer_size=OUTPUT_SIZE): - while True: - out1 = t1.output(buffer_size) - out2 = t2.output(buffer_size) - - if out1 or out2: - if out1: - n = t2.input(out1) - assert n is None or n == len(out1), (n, out1, len(out1)) - if out2: - n = t1.input(out2) - assert n is None or n == len(out2), (n, out2, len(out2)) - else: - return - class Test(common.Test): def __init__(self, *args): Modified: qpid/proton/trunk/tests/python/proton_tests/messenger.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/messenger.py?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/python/proton_tests/messenger.py (original) +++ qpid/proton/trunk/tests/python/proton_tests/messenger.py Tue May 21 15:49:52 2013 @@ -17,7 +17,7 @@ # under the License. # -import os, common +import os, common, sys, traceback from proton import * from threading import Thread, Event from time import sleep, time @@ -46,20 +46,39 @@ class Test(common.Test): self.server_is_running_event.wait(self.timeout) self.client.start() + def _safelyStopClient(self): + existing_exception = None + try: + # send a message to cause the server to promptly exit + msg = Message() + msg.address="amqp://0.0.0.0:12345" + self.client.put(msg) + try: + self.client.send() + except: + print "Client failed to send shutdown message due to: %s" % sys.exc_info()[1] + existing_exception = sys.exc_info()[1] + raise + finally: + try: + self.client.stop() + self.client = None + except: + print "Client failed to stop due to: %s" % sys.exc_info()[1] + if existing_exception: + raise existing_exception + else: + raise + def teardown(self): try: if self.running: if not self.server_thread_started: self.start() # send a message to cause the server to promptly exit self.running = False - msg = Message() - msg.address="amqp://0.0.0.0:12345" - self.client.put(msg) - self.client.send() + self._safelyStopClient() finally: - self.client.stop() self.server_thread.join(self.timeout) - self.client = None self.server = None REJECT_ME = "*REJECT-ME*" @@ -165,6 +184,7 @@ class MessengerTest(Test): for t in trackers: assert self.client.status(t) is None + # reduce outgoing_window to 5 and then try to send 10 messages self.client.outgoing_window = 5 trackers = [] Modified: qpid/proton/trunk/tests/python/proton_tests/sasl.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/sasl.py?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/python/proton_tests/sasl.py (original) +++ qpid/proton/trunk/tests/python/proton_tests/sasl.py Tue May 21 15:49:52 2013 @@ -19,6 +19,7 @@ import os, common from proton import * +from common import pump class Test(common.Test): pass @@ -32,12 +33,7 @@ class SaslTest(Test): self.s2 = SASL(self.t2) def pump(self): - while True: - out1 = self.t1.output(1024) - out2 = self.t2.output(1024) - if out1: self.t2.input(out1) - if out2: self.t1.input(out2) - if not out1 and not out2: break + pump(self.t1, self.t2, 1024) def testPipelined(self): self.s1.mechanisms("ANONYMOUS") @@ -62,6 +58,49 @@ class SaslTest(Test): assert self.s2.outcome == SASL.OK + def testSaslAndAmqpInSingleChunk(self): + self.s1.mechanisms("ANONYMOUS") + self.s1.client() + + self.s2.mechanisms("ANONYMOUS") + self.s2.server() + self.s2.done(SASL.OK) + + # send the server's OK to the client + out2 = self.t2.output(1024) + self.t1.input(out2) + + # do some work to generate AMQP data + c1 = Connection() + c2 = Connection() + self.t1.bind(c1) + c1._transport = self.t1 + self.t2.bind(c2) + c2._transport = self.t2 + + c1.open() + + # get all t1's output in one buffer then pass it all to t2 + out1_sasl_and_amqp = "" + t1_still_producing = True + while t1_still_producing: + out1 = self.t1.output(1024) + out1_sasl_and_amqp += out1 + t1_still_producing = out1 + + t2_still_consuming = True + while t2_still_consuming: + num_consumed = self.t2.input(out1_sasl_and_amqp) + out1_sasl_and_amqp = out1_sasl_and_amqp[num_consumed:] + t2_still_consuming = num_consumed > 0 and len(out1_sasl_and_amqp) > 0 + + assert len(out1_sasl_and_amqp) == 0, (len(out1_sasl_and_amqp), out1_sasl_and_amqp) + + # check that t2 processed both the SASL data and the AMQP data + assert self.s2.outcome == SASL.OK + assert c2.state & Endpoint.REMOTE_ACTIVE + + def testChallengeResponse(self): self.s1.mechanisms("FAKE_MECH") self.s1.client() Modified: qpid/proton/trunk/tests/python/proton_tests/ssl.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/ssl.py?rev=1484842&r1=1484841&r2=1484842&view=diff ============================================================================== --- qpid/proton/trunk/tests/python/proton_tests/ssl.py (original) +++ qpid/proton/trunk/tests/python/proton_tests/ssl.py Tue May 21 15:49:52 2013 @@ -20,7 +20,7 @@ import os, common import subprocess from proton import * -from common import Skipped +from common import Skipped, pump class SslTest(common.Test): @@ -57,34 +57,7 @@ class SslTest(common.Test): raise Skipped(e) def _pump(self, ssl_client, ssl_server, buffer_size=1024): - """ Allow two SslTestConnections to transfer data until done. - """ - out_client_leftover_by_server = "" - out_server_leftover_by_client = "" - i = 0 - - while True: - out_client = out_client_leftover_by_server + (ssl_client.transport.output(buffer_size) or "") - out_server = out_server_leftover_by_client + (ssl_server.transport.output(buffer_size) or "") - - if out_client: - number_server_consumed = ssl_server.transport.input(out_client) - if number_server_consumed is None: - # special None return value means input is closed so discard the leftovers - out_client_leftover_by_server = "" - else: - out_client_leftover_by_server = out_client[number_server_consumed:] - - if out_server: - number_client_consumed = ssl_client.transport.input(out_server) - if number_client_consumed is None: - # special None return value means input is closed so discard the leftovers - out_server_leftover_by_client = "" - else: - out_server_leftover_by_client = out_server[number_client_consumed:] - - if not out_client and not out_server: break - i = i + 1 + pump(ssl_client.transport, ssl_server.transport, buffer_size) def _testpath(self, file): """ Set the full path to the certificate,keyfile, etc. for the test. @@ -363,7 +336,7 @@ class SslTest(common.Test): server.connection.close() self._pump( client, server ) - def test_allow_unsecured_client(self): + def test_allow_unsecured_client_which_connects_unsecured(self): """ Server allows an unsecured client to connect if configured. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), @@ -387,6 +360,39 @@ class SslTest(common.Test): server.connection.close() self._pump( client, server ) + def test_allow_unsecured_client_which_connects_secured(self): + """ As per test_allow_unsecured_client_which_connects_unsecured + but client actually uses SSL + """ + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + + self.client_domain.set_credentials(self._testpath("client-certificate.pem"), + self._testpath("client-private-key.pem"), + "client-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) + + # allow unsecured clients on this connection + #self.server_domain.allow_unsecured_client() + + # client uses ssl. Server should detect this. + client = SslTest.SslTestConnection( self.client_domain ) + server = SslTest.SslTestConnection( self.server_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert server.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) + + def test_disallow_unsecured_client(self): """ Non-SSL Client is disallowed from connecting to server. """ --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org