diff options
Diffstat (limited to 'qpid/java/common/src/test/java')
23 files changed, 5653 insertions, 0 deletions
diff --git a/qpid/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java b/qpid/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java new file mode 100644 index 0000000000..b93dc46741 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java @@ -0,0 +1,396 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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.mina.SocketIOTest; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.CloseFuture; +import org.apache.mina.common.ConnectFuture; +import org.apache.mina.common.IoConnector; +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.SimpleByteBufferAllocator; +import org.apache.mina.filter.ReadThrottleFilterBuilder; +import org.apache.mina.filter.WriteBufferLimitFilterBuilder; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.CountDownLatch; + +public class IOWriterClient implements Runnable +{ + private static final Logger _logger = LoggerFactory.getLogger(IOWriterClient.class); + + public static int DEFAULT_TEST_SIZE = 2; + + private IoSession _session; + + private long _startTime; + + private long[] _chunkTimes; + + public int _chunkCount = 200000; + + private int _chunkSize = 1024; + + private CountDownLatch _notifier; + + private int _maximumWriteQueueLength; + + static public int _PORT = IOWriterServer._PORT; + + public void run() + { + _logger.info("Starting to send " + _chunkCount + " buffers of " + _chunkSize + "B"); + _startTime = System.currentTimeMillis(); + _notifier = new CountDownLatch(1); + + for (int i = 0; i < _chunkCount; i++) + { + ByteBuffer buf = ByteBuffer.allocate(_chunkSize, false); + byte check = (byte) (i % 128); + buf.put(check); + buf.fill((byte) 88, buf.remaining()); + buf.flip(); + + _session.write(buf); + } + + long _sentall = System.currentTimeMillis(); + long _receivedall = _sentall; + try + { + _logger.info("All buffers sent; waiting for receipt from server"); + _notifier.await(); + _receivedall = System.currentTimeMillis(); + } + catch (InterruptedException e) + { + //Ignore + } + _logger.info("Completed"); + _logger.info("Total time waiting for server after last write: " + (_receivedall - _sentall)); + + long totalTime = System.currentTimeMillis() - _startTime; + + _logger.info("Total time: " + totalTime); + _logger.info("MB per second: " + (int) ((1.0 * _chunkSize * _chunkCount) / totalTime)); + long lastChunkTime = _startTime; + double average = 0; + for (int i = 0; i < _chunkTimes.length; i++) + { + if (i == 0) + { + average = _chunkTimes[i] - _startTime; + } + else + { + long delta = _chunkTimes[i] - lastChunkTime; + if (delta != 0) + { + average = (average + delta) / 2; + } + } + lastChunkTime = _chunkTimes[i]; + } + _logger.info("Average chunk time: " + average + "ms"); + _logger.info("Maximum WriteRequestQueue size: " + _maximumWriteQueueLength); + + CloseFuture cf = _session.close(); + _logger.info("Closing session"); + cf.join(); + } + + private class WriterHandler extends IoHandlerAdapter + { + private int _chunksReceived = 0; + + private int _partialBytesRead = 0; + + private byte _partialCheckNumber; + + private int _totalBytesReceived = 0; + + private int _receivedCount = 0; + private int _sentCount = 0; + private static final String DEFAULT_READ_BUFFER = "262144"; + private static final String DEFAULT_WRITE_BUFFER = "262144"; + + public void sessionCreated(IoSession session) throws Exception + { + IoFilterChain chain = session.getFilterChain(); + + ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder(); + readfilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.read.buffer.limit", DEFAULT_READ_BUFFER))); + readfilter.attach(chain); + + WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder(); + + writefilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.write.buffer.limit", DEFAULT_WRITE_BUFFER))); + + writefilter.attach(chain); + } + + public void messageSent(IoSession session, Object message) throws Exception + { + _maximumWriteQueueLength = Math.max(session.getScheduledWriteRequests(), _maximumWriteQueueLength); + + if (_logger.isDebugEnabled()) + { + ++_sentCount; + if (_sentCount % 1000 == 0) + { + _logger.debug("Sent count " + _sentCount + ":WQueue" + session.getScheduledWriteRequests()); + + } + } + } + + public void messageReceived(IoSession session, Object message) throws Exception + { + if (_logger.isDebugEnabled()) + { + ++_receivedCount; + + if (_receivedCount % 1000 == 0) + { + _logger.debug("Receieved count " + _receivedCount); + } + } + + ByteBuffer result = (ByteBuffer) message; + _totalBytesReceived += result.remaining(); + int size = result.remaining(); + long now = System.currentTimeMillis(); + if (_partialBytesRead > 0) + { + int offset = _chunkSize - _partialBytesRead; + if (size >= offset) + { + _chunkTimes[_chunksReceived++] = now; + result.position(offset); + } + else + { + // have not read even one chunk, including the previous partial bytes + _partialBytesRead += size; + return; + } + } + + + int chunkCount = result.remaining() / _chunkSize; + + for (int i = 0; i < chunkCount; i++) + { + _chunkTimes[_chunksReceived++] = now; + byte check = result.get(); + _logger.debug("Check number " + check + " read"); + if (check != (byte) ((_chunksReceived - 1) % 128)) + { + _logger.error("Check number " + check + " read when expected " + (_chunksReceived % 128)); + } + _logger.debug("Chunk times recorded"); + + try + { + result.skip(_chunkSize - 1); + } + catch (IllegalArgumentException e) + { + _logger.error("Position was: " + result.position()); + _logger.error("Tried to skip to: " + (_chunkSize * i)); + _logger.error("limit was; " + result.limit()); + } + } + _logger.debug("Chunks received now " + _chunksReceived); + _logger.debug("Bytes received: " + _totalBytesReceived); + _partialBytesRead = result.remaining(); + + if (_partialBytesRead > 0) + { + _partialCheckNumber = result.get(); + } + + + if (_chunksReceived >= _chunkCount) + { + _notifier.countDown(); + } + + } + + public void exceptionCaught(IoSession session, Throwable cause) throws Exception + { + _logger.error("Error: " + cause, cause); + } + } + + public void startWriter() throws IOException, InterruptedException + { + + _maximumWriteQueueLength = 0; + + IoConnector ioConnector = null; + + if (Boolean.getBoolean("multinio")) + { + _logger.warn("Using MultiThread NIO"); + ioConnector = new org.apache.mina.transport.socket.nio.MultiThreadSocketConnector(); + } + else + { + _logger.warn("Using MINA NIO"); + ioConnector = new org.apache.mina.transport.socket.nio.SocketConnector(); + } + + SocketSessionConfig scfg = (SocketSessionConfig) ioConnector.getDefaultConfig().getSessionConfig(); + scfg.setTcpNoDelay(true); + scfg.setSendBufferSize(32768); + scfg.setReceiveBufferSize(32768); + + ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); + + + final InetSocketAddress address = new InetSocketAddress("localhost", _PORT); + _logger.info("Attempting connection to " + address); + + //Old mina style +// ioConnector.setHandler(new WriterHandler()); +// ConnectFuture future = ioConnector.connect(address); + ConnectFuture future = ioConnector.connect(address, new WriterHandler()); + // wait for connection to complete + future.join(); + _logger.info("Connection completed"); + // we call getSession which throws an IOException if there has been an error connecting + _session = future.getSession(); + + _chunkTimes = new long[_chunkCount]; + Thread t = new Thread(this); + t.start(); + t.join(); + _logger.info("Test Complete"); + } + + + public void test1k() throws IOException, InterruptedException + { + _logger.info("Starting 1k test"); + _chunkSize = 1024; + startWriter(); + } + + + public void test2k() throws IOException, InterruptedException + { + _logger.info("Starting 2k test"); + _chunkSize = 2048; + startWriter(); + } + + + public void test4k() throws IOException, InterruptedException + { + _logger.info("Starting 4k test"); + _chunkSize = 4096; + startWriter(); + } + + + public void test8k() throws IOException, InterruptedException + { + _logger.info("Starting 8k test"); + _chunkSize = 8192; + startWriter(); + } + + + public void test16k() throws IOException, InterruptedException + { + _logger.info("Starting 16k test"); + _chunkSize = 16384; + startWriter(); + } + + + public void test32k() throws IOException, InterruptedException + { + _logger.info("Starting 32k test"); + _chunkSize = 32768; + startWriter(); + } + + + public static int getIntArg(String[] args, int index, int defaultValue) + { + if (args.length > index) + { + try + { + return Integer.parseInt(args[index]); + } + catch (NumberFormatException e) + { + //Do nothing + } + } + return defaultValue; + } + + public static void main(String[] args) throws IOException, InterruptedException + { + _PORT = getIntArg(args, 0, _PORT); + + int test = getIntArg(args, 1, DEFAULT_TEST_SIZE); + + IOWriterClient w = new IOWriterClient(); + w._chunkCount = getIntArg(args, 2, w._chunkCount); + switch (test) + { + case 0: + w.test1k(); + w.test2k(); + w.test4k(); + w.test8k(); + w.test16k(); + w.test32k(); + break; + case 1: + w.test1k(); + break; + case 2: + w.test2k(); + break; + case 4: + w.test4k(); + break; + case 8: + w.test8k(); + break; + case 16: + w.test16k(); + break; + case 32: + w.test32k(); + break; + } + } +} diff --git a/qpid/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java b/qpid/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java new file mode 100644 index 0000000000..423e98c67b --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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.mina.SocketIOTest; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoAcceptor; +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.SimpleByteBufferAllocator; +import org.apache.mina.filter.ReadThrottleFilterBuilder; +import org.apache.mina.filter.WriteBufferLimitFilterBuilder; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.InetSocketAddress; + +/** Tests MINA socket performance. This acceptor simply reads data from the network and writes it back again. */ +public class IOWriterServer +{ + private static final Logger _logger = LoggerFactory.getLogger(IOWriterServer.class); + + static public int _PORT = 9999; + + private static final String DEFAULT_READ_BUFFER = "262144"; + private static final String DEFAULT_WRITE_BUFFER = "262144"; + + + private static class TestHandler extends IoHandlerAdapter + { + private int _sentCount = 0; + + private int _bytesSent = 0; + + private int _receivedCount = 0; + + public void sessionCreated(IoSession ioSession) throws java.lang.Exception + { + IoFilterChain chain = ioSession.getFilterChain(); + + ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder(); + readfilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.read.buffer.limit", DEFAULT_READ_BUFFER))); + readfilter.attach(chain); + + WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder(); + + writefilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.write.buffer.limit", DEFAULT_WRITE_BUFFER))); + + writefilter.attach(chain); + + } + + public void messageReceived(IoSession session, Object message) throws Exception + { + ((ByteBuffer) message).acquire(); + session.write(message); + + if (_logger.isDebugEnabled()) + { + _bytesSent += ((ByteBuffer) message).remaining(); + + _sentCount++; + + if (_sentCount % 1000 == 0) + { + _logger.debug("Bytes sent: " + _bytesSent); + } + } + } + + public void messageSent(IoSession session, Object message) throws Exception + { + if (_logger.isDebugEnabled()) + { + ++_receivedCount; + + if (_receivedCount % 1000 == 0) + { + _logger.debug("Receieved count " + _receivedCount); + } + } + } + + public void exceptionCaught(IoSession session, Throwable cause) throws Exception + { + _logger.error("Error: " + cause, cause); + } + } + + public void startAcceptor() throws IOException + { + IoAcceptor acceptor; + if (Boolean.getBoolean("multinio")) + { + _logger.warn("Using MultiThread NIO"); + acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(); + } + else + { + _logger.warn("Using MINA NIO"); + acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(); + } + + + SocketSessionConfig sc = (SocketSessionConfig) acceptor.getDefaultConfig().getSessionConfig(); + sc.setTcpNoDelay(true); + sc.setSendBufferSize(32768); + sc.setReceiveBufferSize(32768); + + ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); + + //The old mina style +// acceptor.setLocalAddress(new InetSocketAddress(_PORT)); +// acceptor.setHandler(new TestHandler()); +// acceptor.bind(); + acceptor.bind(new InetSocketAddress(_PORT), new TestHandler()); + + _logger.info("Bound on port " + _PORT + ":" + _logger.isDebugEnabled()); + _logger.debug("debug on"); + } + + public static void main(String[] args) throws IOException + { + + if (args.length > 0) + { + try + { + _PORT = Integer.parseInt(args[0]); + } + catch (NumberFormatException e) + { + //IGNORE so use default port 9999; + } + } + + IOWriterServer a = new IOWriterServer(); + a.startAcceptor(); + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java b/qpid/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java new file mode 100644 index 0000000000..ef6cd41492 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java @@ -0,0 +1,106 @@ +/* + * + * 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; + +import junit.framework.TestCase; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.framing.AMQFrameDecodingException; + +/** + * This test is to ensure that when an AMQException is rethrown that the specified exception is correctly wrapped up. + * + * There are three cases: + * Re-throwing an AMQException + * Re-throwing a Subclass of AMQException + * Re-throwing a Subclass of AMQException that does not have the default AMQException constructor which will force the + * creation of an AMQException. + */ +public class AMQExceptionTest extends TestCase +{ + /** + * Test that an AMQException will be correctly created and rethrown. + */ + public void testRethrowGeneric() + { + AMQException test = new AMQException(AMQConstant.ACCESS_REFUSED, "refused", new RuntimeException()); + + AMQException e = reThrowException(test); + + assertEquals("Exception not of correct class", AMQException.class, e.getClass()); + + } + + /** + * Test that a subclass of AMQException that has the default constructor will be correctly created and rethrown. + */ + public void testRethrowAMQESubclass() + { + AMQFrameDecodingException test = new AMQFrameDecodingException(AMQConstant.INTERNAL_ERROR, + "Error", + new Exception()); + AMQException e = reThrowException(test); + + assertEquals("Exception not of correct class", AMQFrameDecodingException.class, e.getClass()); + } + + /** + * Test that a subclass of AMQException that doesnot have the default constructor will be correctly rethrown as an + * AMQException + */ + public void testRethrowAMQESubclassNoConstructor() + { + AMQExceptionSubclass test = new AMQExceptionSubclass("Invalid Argument Exception"); + + AMQException e = reThrowException(test); + + assertEquals("Exception not of correct class", AMQException.class, e.getClass()); + } + + /** + * Private method to rethrown and validate the basic values of the rethrown + * @param test Exception to rethrow + * @throws AMQException the rethrown exception + */ + private AMQException reThrowException(AMQException test) + { + AMQException amqe = test.cloneForCurrentThread(); + + assertEquals("Error code does not match.", test.getErrorCode(), amqe.getErrorCode()); + assertTrue("Exception message does not start as expected.", amqe.getMessage().startsWith(test.getMessage())); + assertEquals("Test Exception is not set as the cause", test, amqe.getCause()); + assertEquals("Cause is not correct", test.getCause(), amqe.getCause().getCause()); + + return amqe; + } + + /** + * Private class that extends AMQException but does not have a default exception. + */ + private class AMQExceptionSubclass extends AMQException + { + + public AMQExceptionSubclass(String msg) + { + super(null, msg, null); + } + } +} + diff --git a/qpid/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java b/qpid/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java new file mode 100644 index 0000000000..62e25e7d79 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java @@ -0,0 +1,151 @@ +package org.apache.qpid.codec; +/* + * + * 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 java.nio.ByteBuffer; +import java.util.ArrayList; + +import junit.framework.TestCase; + +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.AMQProtocolVersionException; +import org.apache.qpid.framing.HeartbeatBody; + +public class AMQDecoderTest extends TestCase +{ + + private AMQCodecFactory _factory; + private AMQDecoder _decoder; + + + public void setUp() + { + _factory = new AMQCodecFactory(false, null); + _decoder = _factory.getDecoder(); + } + + + public void testSingleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException + { + ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer(); + ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg); + if (frames.get(0) instanceof AMQFrame) + { + assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frames.get(0)).getBodyFrame().getFrameType()); + } + else + { + fail("decode was not a frame"); + } + } + + public void testPartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException + { + ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer(); + ByteBuffer msgA = msg.slice(); + int msgbPos = msg.remaining() / 2; + int msgaLimit = msg.remaining() - msgbPos; + msgA.limit(msgaLimit); + msg.position(msgbPos); + ByteBuffer msgB = msg.slice(); + ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msgA); + assertEquals(0, frames.size()); + frames = _decoder.decodeBuffer(msgB); + assertEquals(1, frames.size()); + if (frames.get(0) instanceof AMQFrame) + { + assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frames.get(0)).getBodyFrame().getFrameType()); + } + else + { + fail("decode was not a frame"); + } + } + + public void testMultipleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException + { + ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer(); + ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer(); + ByteBuffer msg = ByteBuffer.allocate(msgA.remaining() + msgB.remaining()); + msg.put(msgA); + msg.put(msgB); + msg.flip(); + ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg); + assertEquals(2, frames.size()); + for (AMQDataBlock frame : frames) + { + if (frame instanceof AMQFrame) + { + assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frame).getBodyFrame().getFrameType()); + } + else + { + fail("decode was not a frame"); + } + } + } + + public void testMultiplePartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException + { + ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer(); + ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer(); + ByteBuffer msgC = HeartbeatBody.FRAME.toNioByteBuffer(); + + ByteBuffer sliceA = ByteBuffer.allocate(msgA.remaining() + msgB.remaining() / 2); + sliceA.put(msgA); + int limit = msgB.limit(); + int pos = msgB.remaining() / 2; + msgB.limit(pos); + sliceA.put(msgB); + sliceA.flip(); + msgB.limit(limit); + msgB.position(pos); + + ByteBuffer sliceB = ByteBuffer.allocate(msgB.remaining() + pos); + sliceB.put(msgB); + msgC.limit(pos); + sliceB.put(msgC); + sliceB.flip(); + msgC.limit(limit); + + ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(sliceA); + assertEquals(1, frames.size()); + frames = _decoder.decodeBuffer(sliceB); + assertEquals(1, frames.size()); + frames = _decoder.decodeBuffer(msgC); + assertEquals(1, frames.size()); + for (AMQDataBlock frame : frames) + { + if (frame instanceof AMQFrame) + { + assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frame).getBodyFrame().getFrameType()); + } + else + { + fail("decode was not a frame"); + } + } + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java b/qpid/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java new file mode 100644 index 0000000000..401848c21d --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java @@ -0,0 +1,105 @@ +package org.apache.qpid.codec; +/* + * + * 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 java.nio.ByteBuffer; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; +import org.apache.qpid.transport.Sender; + +public class MockAMQVersionAwareProtocolSession implements AMQVersionAwareProtocolSession +{ + + public void contentBodyReceived(int channelId, ContentBody body) throws AMQException + { + // TODO Auto-generated method stub + + } + + public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException + { + // TODO Auto-generated method stub + + } + + public MethodRegistry getMethodRegistry() + { + return MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + } + + public void heartbeatBodyReceived(int channelId, HeartbeatBody body) throws AMQException + { + // TODO Auto-generated method stub + + } + + public void init() + { + // TODO Auto-generated method stub + + } + + public void methodFrameReceived(int channelId, AMQMethodBody body) throws AMQException + { + // TODO Auto-generated method stub + + } + + public void setSender(Sender<ByteBuffer> sender) + { + // TODO Auto-generated method stub + + } + + public void writeFrame(AMQDataBlock frame) + { + // TODO Auto-generated method stub + + } + + public byte getProtocolMajorVersion() + { + // TODO Auto-generated method stub + return 0; + } + + public byte getProtocolMinorVersion() + { + // TODO Auto-generated method stub + return 0; + } + + public ProtocolVersion getProtocolVersion() + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java b/qpid/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java new file mode 100644 index 0000000000..92e7ce0a80 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java @@ -0,0 +1,109 @@ +/* + * 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.framing; + +import junit.framework.TestCase; +public class AMQShortStringTest extends TestCase +{ + + public static final AMQShortString HELLO = new AMQShortString("Hello"); + public static final AMQShortString HELL = new AMQShortString("Hell"); + public static final AMQShortString GOODBYE = new AMQShortString("Goodbye"); + public static final AMQShortString GOOD = new AMQShortString("Good"); + public static final AMQShortString BYE = new AMQShortString("BYE"); + + public void testStartsWith() + { + assertTrue(HELLO.startsWith(HELL)); + + assertFalse(HELL.startsWith(HELLO)); + + assertTrue(GOODBYE.startsWith(GOOD)); + + assertFalse(GOOD.startsWith(GOODBYE)); + } + + public void testEndWith() + { + assertFalse(HELL.endsWith(HELLO)); + + assertTrue(GOODBYE.endsWith(new AMQShortString("bye"))); + + assertFalse(GOODBYE.endsWith(BYE)); + } + + + public void testTokenize() + { + AMQShortString dotSeparatedWords = new AMQShortString("this.is.a.test.with.1.2.3.-numbers-and-then--dashes-"); + AMQShortStringTokenizer dotTokenizer = dotSeparatedWords.tokenize((byte) '.'); + + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(new AMQShortString("this"),(dotTokenizer.nextToken())); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(new AMQShortString("is"),(dotTokenizer.nextToken())); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(new AMQShortString("a"),(dotTokenizer.nextToken())); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(new AMQShortString("test"),(dotTokenizer.nextToken())); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(new AMQShortString("with"),(dotTokenizer.nextToken())); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(dotTokenizer.nextToken().toIntValue() , 1); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(dotTokenizer.nextToken().toIntValue() , 2); + assertTrue(dotTokenizer.hasMoreTokens()); + assertEquals(dotTokenizer.nextToken().toIntValue() , 3); + assertTrue(dotTokenizer.hasMoreTokens()); + AMQShortString dashString = dotTokenizer.nextToken(); + assertEquals(new AMQShortString("-numbers-and-then--dashes-"),(dashString)); + + AMQShortStringTokenizer dashTokenizer = dashString.tokenize((byte)'-'); + assertEquals(dashTokenizer.countTokens(), 7); + + AMQShortString[] expectedResults = new AMQShortString[] + { AMQShortString.EMPTY_STRING, + new AMQShortString("numbers"), + new AMQShortString("and"), + new AMQShortString("then"), + AMQShortString.EMPTY_STRING, + new AMQShortString("dashes"), + AMQShortString.EMPTY_STRING }; + + for(int i = 0; i < 7; i++) + { + assertTrue(dashTokenizer.hasMoreTokens()); + assertEquals(dashTokenizer.nextToken(), expectedResults[i]); + } + + assertFalse(dotTokenizer.hasMoreTokens()); + } + + + public void testEquals() + { + assertEquals(GOODBYE, new AMQShortString("Goodbye")); + assertEquals(new AMQShortString("A"), new AMQShortString("A")); + assertFalse(new AMQShortString("A").equals(new AMQShortString("a"))); + } + + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java b/qpid/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java new file mode 100644 index 0000000000..4fd1f60d69 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java @@ -0,0 +1,188 @@ +/* + * + * 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.framing; + +import org.apache.mina.common.ByteBuffer; + +import junit.framework.TestCase; + + +public class BasicContentHeaderPropertiesTest extends TestCase +{ + + BasicContentHeaderProperties _testProperties; + FieldTable _testTable; + String _testString = "This is a test string"; + int _testint = 666; + + /** + * Currently only test setting/getting String, int and boolean props + */ + public BasicContentHeaderPropertiesTest() + { + _testProperties = new BasicContentHeaderProperties(); + } + + public void setUp() + { + _testTable = new FieldTable(); + _testTable.setString("TestString", _testString); + _testTable.setInteger("Testint", _testint); + _testProperties = new BasicContentHeaderProperties(); + _testProperties.setHeaders(_testTable); + } + + public void testGetPropertyListSize() + { + //needs a better test but at least we're exercising the code ! + // FT length is encoded in an int + int expectedSize = EncodingUtils.encodedIntegerLength(); + + expectedSize += EncodingUtils.encodedShortStringLength("TestInt"); + // 1 is for the Encoding Letter. here an 'i' + expectedSize += 1 + EncodingUtils.encodedIntegerLength(); + + expectedSize += EncodingUtils.encodedShortStringLength("TestString"); + // 1 is for the Encoding Letter. here an 'S' + expectedSize += 1 + EncodingUtils.encodedLongStringLength(_testString); + + + int size = _testProperties.getPropertyListSize(); + + assertEquals(expectedSize, size); + } + + public void testGetSetPropertyFlags() + { + _testProperties.setPropertyFlags(99); + assertEquals(99, _testProperties.getPropertyFlags()); + } + + public void testWritePropertyListPayload() + { + ByteBuffer buf = ByteBuffer.allocate(300); + _testProperties.writePropertyListPayload(buf); + } + + public void testPopulatePropertiesFromBuffer() throws Exception + { + ByteBuffer buf = ByteBuffer.allocate(300); + _testProperties.populatePropertiesFromBuffer(buf, 99, 99); + } + + public void testSetGetContentType() + { + String contentType = "contentType"; + _testProperties.setContentType(contentType); + assertEquals(contentType, _testProperties.getContentTypeAsString()); + } + + public void testSetGetEncoding() + { + String encoding = "encoding"; + _testProperties.setEncoding(encoding); + assertEquals(encoding, _testProperties.getEncodingAsString()); + } + + public void testSetGetHeaders() + { + _testProperties.setHeaders(_testTable); + assertEquals(_testTable, _testProperties.getHeaders()); + } + + public void testSetGetDeliveryMode() + { + byte deliveryMode = 1; + _testProperties.setDeliveryMode(deliveryMode); + assertEquals(deliveryMode, _testProperties.getDeliveryMode()); + } + + public void testSetGetPriority() + { + byte priority = 1; + _testProperties.setPriority(priority); + assertEquals(priority, _testProperties.getPriority()); + } + + public void testSetGetCorrelationId() + { + String correlationId = "correlationId"; + _testProperties.setCorrelationId(correlationId); + assertEquals(correlationId, _testProperties.getCorrelationIdAsString()); + } + + public void testSetGetReplyTo() + { + String replyTo = "replyTo"; + _testProperties.setReplyTo(replyTo); + assertEquals(replyTo, _testProperties.getReplyToAsString()); + } + + public void testSetGetExpiration() + { + long expiration = 999999999; + _testProperties.setExpiration(expiration); + assertEquals(expiration, _testProperties.getExpiration()); + } + + public void testSetGetMessageId() + { + String messageId = "messageId"; + _testProperties.setMessageId(messageId); + assertEquals(messageId, _testProperties.getMessageIdAsString()); + } + + public void testSetGetTimestamp() + { + long timestamp = System.currentTimeMillis(); + _testProperties.setTimestamp(timestamp); + assertEquals(timestamp, _testProperties.getTimestamp()); + } + + public void testSetGetType() + { + String type = "type"; + _testProperties.setType(type); + assertEquals(type, _testProperties.getTypeAsString()); + } + + public void testSetGetUserId() + { + String userId = "userId"; + _testProperties.setUserId(userId); + assertEquals(userId, _testProperties.getUserIdAsString()); + } + + public void testSetGetAppId() + { + String appId = "appId"; + _testProperties.setAppId(appId); + assertEquals(appId, _testProperties.getAppIdAsString()); + } + + public void testSetGetClusterId() + { + String clusterId = "clusterId"; + _testProperties.setClusterId(clusterId); + assertEquals(clusterId, _testProperties.getClusterIdAsString()); + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java b/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java new file mode 100644 index 0000000000..d4691ba097 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java @@ -0,0 +1,974 @@ +/* + * + * 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.framing; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.mina.common.ByteBuffer; + +import org.apache.qpid.AMQInvalidArgumentException; +import org.apache.qpid.AMQPInvalidClassException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PropertyFieldTableTest extends TestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(PropertyFieldTableTest.class); + + /** + * Test that setting a similar named value replaces any previous value set on that name + */ + public void testReplacement() + { + FieldTable table1 = new FieldTable(); + // Set a boolean value + table1.setBoolean("value", true); + // Check length of table is correct (<Value length> + <type> + <Boolean length>) + int size = EncodingUtils.encodedShortStringLength("value") + 1 + EncodingUtils.encodedBooleanLength(); + Assert.assertEquals(size, table1.getEncodedSize()); + + // reset value to an integer + table1.setInteger("value", Integer.MAX_VALUE); + + // Check the length has changed accordingly (<Value length> + <type> + <Integer length>) + size = EncodingUtils.encodedShortStringLength("value") + 1 + EncodingUtils.encodedIntegerLength(); + Assert.assertEquals(size, table1.getEncodedSize()); + + // Check boolean value is null + Assert.assertEquals(null, table1.getBoolean("value")); + // ... and integer value is good + Assert.assertEquals((Integer) Integer.MAX_VALUE, table1.getInteger("value")); + } + + /** + * Set a boolean and check that we can only get it back as a boolean and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testBoolean() + { + FieldTable table1 = new FieldTable(); + table1.setBoolean("value", true); + Assert.assertTrue(table1.propertyExists("value")); + + // Test Getting right value back + Assert.assertEquals((Boolean) true, table1.getBoolean("value")); + + // Check we don't get anything back for other gets + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // except value as a string + Assert.assertEquals("true", table1.getString("value")); + + table1.remove("value"); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getBoolean("Rubbish")); + } + + /** + * Set a byte and check that we can only get it back as a byte and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testByte() + { + FieldTable table1 = new FieldTable(); + table1.setByte("value", Byte.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(Byte.MAX_VALUE, (byte) table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("" + Byte.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getByte("Rubbish")); + } + + /** + * Set a short and check that we can only get it back as a short and a string + * Check that attempting to lookup a non existent value returns null + */ + public void testShort() + { + FieldTable table1 = new FieldTable(); + table1.setShort("value", Short.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(Short.MAX_VALUE, (short) table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("" + Short.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getShort("Rubbish")); + } + + /** + * Set a char and check that we can only get it back as a char + * Check that attempting to lookup a non existent value returns null + */ + public void testChar() + { + FieldTable table1 = new FieldTable(); + table1.setChar("value", 'c'); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals('c', (char) table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("c", table1.getString("value")); + + table1.remove("value"); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getCharacter("Rubbish")); + } + + /** + * Set a double and check that we can only get it back as a double + * Check that attempting to lookup a non existent value returns null + */ + public void testDouble() + { + FieldTable table1 = new FieldTable(); + table1.setDouble("value", Double.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(Double.MAX_VALUE, (double) table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("" + Double.MAX_VALUE, table1.getString("value")); + table1.remove("value"); + // but after a removeKey it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getDouble("Rubbish")); + } + + /** + * Set a float and check that we can only get it back as a float + * Check that attempting to lookup a non existent value returns null + */ + public void testFloat() + { + FieldTable table1 = new FieldTable(); + table1.setFloat("value", Float.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(Float.MAX_VALUE, (float) table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("" + Float.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + // but after a removeKey it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getFloat("Rubbish")); + } + + /** + * Set an int and check that we can only get it back as an int + * Check that attempting to lookup a non existent value returns null + */ + public void testInt() + { + FieldTable table1 = new FieldTable(); + table1.setInteger("value", Integer.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(Integer.MAX_VALUE, (int) table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("" + Integer.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + // but after a removeKey it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getInteger("Rubbish")); + } + + /** + * Set a long and check that we can only get it back as a long + * Check that attempting to lookup a non existent value returns null + */ + public void testLong() + { + FieldTable table1 = new FieldTable(); + table1.setLong("value", Long.MAX_VALUE); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(Long.MAX_VALUE, (long) table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + + // ... and a the string value of it. + Assert.assertEquals("" + Long.MAX_VALUE, table1.getString("value")); + + table1.remove("value"); + // but after a removeKey it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getLong("Rubbish")); + } + + /** + * Set a double and check that we can only get it back as a double + * Check that attempting to lookup a non existent value returns null + */ + public void testBytes() + { + byte[] bytes = { 99, 98, 97, 96, 95 }; + + FieldTable table1 = new FieldTable(); + table1.setBytes("value", bytes); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + assertBytesEqual(bytes, table1.getBytes("value")); + + // ... and a the string value of it is null + Assert.assertEquals(null, table1.getString("value")); + + table1.remove("value"); + // but after a removeKey it doesn't + Assert.assertFalse(table1.containsKey("value")); + + // Table should now have zero length for encoding + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getBytes("Rubbish")); + } + + /** + * Calls all methods that can be used to check the table is empty + * - getEncodedSize + * - isEmpty + * - length + * + * @param table to check is empty + */ + private void checkEmpty(FieldTable table) + { + Assert.assertEquals(0, table.getEncodedSize()); + Assert.assertTrue(table.isEmpty()); + Assert.assertEquals(0, table.size()); + + Assert.assertEquals(0, table.keySet().size()); + } + + /** + * Set a String and check that we can only get it back as a String + * Check that attempting to lookup a non existent value returns null + */ + public void testString() + { + FieldTable table1 = new FieldTable(); + table1.setString("value", "Hello"); + Assert.assertTrue(table1.propertyExists("value")); + + // Tets lookups we shouldn't get anything back for other gets + // we should get right value back for this type .... + Assert.assertEquals(null, table1.getBoolean("value")); + Assert.assertEquals(null, table1.getByte("value")); + Assert.assertEquals(null, table1.getShort("value")); + Assert.assertEquals(null, table1.getCharacter("value")); + Assert.assertEquals(null, table1.getDouble("value")); + Assert.assertEquals(null, table1.getFloat("value")); + Assert.assertEquals(null, table1.getInteger("value")); + Assert.assertEquals(null, table1.getLong("value")); + Assert.assertEquals(null, table1.getBytes("value")); + Assert.assertEquals("Hello", table1.getString("value")); + + // Try setting a null value and read it back + table1.setString("value", null); + + Assert.assertEquals(null, table1.getString("value")); + + // but still contains the value + Assert.assertTrue(table1.containsKey("value")); + + table1.remove("value"); + // but after a removeKey it doesn't + Assert.assertFalse(table1.containsKey("value")); + + checkEmpty(table1); + + // Looking up an invalid value returns null + Assert.assertEquals(null, table1.getString("Rubbish")); + + // Additional Test that haven't been covered for string + table1.setObject("value", "Hello"); + // Check that it was set correctly + Assert.assertEquals("Hello", table1.getString("value")); + } + + /** Check that a nested field table parameter correctly encodes and decodes to a byte buffer. */ + public void testNestedFieldTable() + { + byte[] testBytes = new byte[] { 0, 1, 2, 3, 4, 5 }; + + FieldTable outerTable = new FieldTable(); + FieldTable innerTable = new FieldTable(); + + // Put some stuff in the inner table. + innerTable.setBoolean("bool", true); + innerTable.setByte("byte", Byte.MAX_VALUE); + innerTable.setBytes("bytes", testBytes); + innerTable.setChar("char", 'c'); + innerTable.setDouble("double", Double.MAX_VALUE); + innerTable.setFloat("float", Float.MAX_VALUE); + innerTable.setInteger("int", Integer.MAX_VALUE); + innerTable.setLong("long", Long.MAX_VALUE); + innerTable.setShort("short", Short.MAX_VALUE); + innerTable.setString("string", "hello"); + innerTable.setString("null-string", null); + + // Put the inner table in the outer one. + outerTable.setFieldTable("innerTable", innerTable); + + // Write the outer table into the buffer. + final ByteBuffer buffer = ByteBuffer.allocate((int) outerTable.getEncodedSize() + 4); + outerTable.writeToBuffer(buffer); + buffer.flip(); + + // Extract the table back from the buffer again. + try + { + FieldTable extractedOuterTable = EncodingUtils.readFieldTable(buffer); + + FieldTable extractedTable = extractedOuterTable.getFieldTable("innerTable"); + + Assert.assertEquals((Boolean) true, extractedTable.getBoolean("bool")); + Assert.assertEquals((Byte) Byte.MAX_VALUE, extractedTable.getByte("byte")); + assertBytesEqual(testBytes, extractedTable.getBytes("bytes")); + Assert.assertEquals((Character) 'c', extractedTable.getCharacter("char")); + Assert.assertEquals(Double.MAX_VALUE, extractedTable.getDouble("double")); + Assert.assertEquals(Float.MAX_VALUE, extractedTable.getFloat("float")); + Assert.assertEquals((Integer) Integer.MAX_VALUE, extractedTable.getInteger("int")); + Assert.assertEquals((Long) Long.MAX_VALUE, extractedTable.getLong("long")); + Assert.assertEquals((Short) Short.MAX_VALUE, extractedTable.getShort("short")); + Assert.assertEquals("hello", extractedTable.getString("string")); + Assert.assertEquals(null, extractedTable.getString("null-string")); + } + catch (AMQFrameDecodingException e) + { + fail("Failed to decode field table with nested inner table."); + } + } + + public void testValues() + { + FieldTable table = new FieldTable(); + table.setBoolean("bool", true); + table.setByte("byte", Byte.MAX_VALUE); + byte[] bytes = { 99, 98, 97, 96, 95 }; + table.setBytes("bytes", bytes); + table.setChar("char", 'c'); + table.setDouble("double", Double.MAX_VALUE); + table.setFloat("float", Float.MAX_VALUE); + table.setInteger("int", Integer.MAX_VALUE); + table.setLong("long", Long.MAX_VALUE); + table.setShort("short", Short.MAX_VALUE); + table.setString("string", "Hello"); + table.setString("null-string", null); + + table.setObject("object-bool", true); + table.setObject("object-byte", Byte.MAX_VALUE); + table.setObject("object-bytes", bytes); + table.setObject("object-char", 'c'); + table.setObject("object-double", Double.MAX_VALUE); + table.setObject("object-float", Float.MAX_VALUE); + table.setObject("object-int", Integer.MAX_VALUE); + table.setObject("object-long", Long.MAX_VALUE); + table.setObject("object-short", Short.MAX_VALUE); + table.setObject("object-string", "Hello"); + + try + { + table.setObject("Null-object", null); + fail("null values are not allowed"); + } + catch (AMQPInvalidClassException aice) + { + assertEquals("Null values are not allowed to be set", + AMQPInvalidClassException.INVALID_OBJECT_MSG + "null", aice.getMessage()); + } + + try + { + table.setObject("Unsupported-object", new Exception()); + fail("Non primitive values are not allowed"); + } + catch (AMQPInvalidClassException aice) + { + assertEquals("Non primitive values are not allowed to be set", + AMQPInvalidClassException.INVALID_OBJECT_MSG + Exception.class, aice.getMessage()); + } + + Assert.assertEquals((Boolean) true, table.getBoolean("bool")); + Assert.assertEquals((Byte) Byte.MAX_VALUE, table.getByte("byte")); + assertBytesEqual(bytes, table.getBytes("bytes")); + Assert.assertEquals((Character) 'c', table.getCharacter("char")); + Assert.assertEquals(Double.MAX_VALUE, table.getDouble("double")); + Assert.assertEquals(Float.MAX_VALUE, table.getFloat("float")); + Assert.assertEquals((Integer) Integer.MAX_VALUE, table.getInteger("int")); + Assert.assertEquals((Long) Long.MAX_VALUE, table.getLong("long")); + Assert.assertEquals((Short) Short.MAX_VALUE, table.getShort("short")); + Assert.assertEquals("Hello", table.getString("string")); + Assert.assertEquals(null, table.getString("null-string")); + + Assert.assertEquals(true, table.getObject("object-bool")); + Assert.assertEquals(Byte.MAX_VALUE, table.getObject("object-byte")); + assertBytesEqual(bytes, (byte[]) table.getObject("object-bytes")); + Assert.assertEquals('c', table.getObject("object-char")); + Assert.assertEquals(Double.MAX_VALUE, table.getObject("object-double")); + Assert.assertEquals(Float.MAX_VALUE, table.getObject("object-float")); + Assert.assertEquals(Integer.MAX_VALUE, table.getObject("object-int")); + Assert.assertEquals(Long.MAX_VALUE, table.getObject("object-long")); + Assert.assertEquals(Short.MAX_VALUE, table.getObject("object-short")); + Assert.assertEquals("Hello", table.getObject("object-string")); + } + + public void testwriteBuffer() + { + byte[] bytes = { 99, 98, 97, 96, 95 }; + + FieldTable table = new FieldTable(); + table.setBoolean("bool", true); + table.setByte("byte", Byte.MAX_VALUE); + + table.setBytes("bytes", bytes); + table.setChar("char", 'c'); + table.setDouble("double", Double.MAX_VALUE); + table.setFloat("float", Float.MAX_VALUE); + table.setInteger("int", Integer.MAX_VALUE); + table.setLong("long", Long.MAX_VALUE); + table.setShort("short", Short.MAX_VALUE); + table.setString("string", "hello"); + table.setString("null-string", null); + + final ByteBuffer buffer = ByteBuffer.allocate((int) table.getEncodedSize() + 4); // FIXME XXX: Is cast a problem? + + table.writeToBuffer(buffer); + + buffer.flip(); + + long length = buffer.getUnsignedInt(); + + FieldTable table2 = new FieldTable(buffer, length); + + Assert.assertEquals((Boolean) true, table2.getBoolean("bool")); + Assert.assertEquals((Byte) Byte.MAX_VALUE, table2.getByte("byte")); + assertBytesEqual(bytes, table2.getBytes("bytes")); + Assert.assertEquals((Character) 'c', table2.getCharacter("char")); + Assert.assertEquals(Double.MAX_VALUE, table2.getDouble("double")); + Assert.assertEquals(Float.MAX_VALUE, table2.getFloat("float")); + Assert.assertEquals((Integer) Integer.MAX_VALUE, table2.getInteger("int")); + Assert.assertEquals((Long) Long.MAX_VALUE, table2.getLong("long")); + Assert.assertEquals((Short) Short.MAX_VALUE, table2.getShort("short")); + Assert.assertEquals("hello", table2.getString("string")); + Assert.assertEquals(null, table2.getString("null-string")); + } + + public void testEncodingSize() + { + FieldTable result = new FieldTable(); + int size = 0; + + result.setBoolean("boolean", true); + size += 1 + EncodingUtils.encodedShortStringLength("boolean") + EncodingUtils.encodedBooleanLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setByte("byte", (byte) Byte.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("byte") + EncodingUtils.encodedByteLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + byte[] _bytes = { 99, 98, 97, 96, 95 }; + + result.setBytes("bytes", _bytes); + size += 1 + EncodingUtils.encodedShortStringLength("bytes") + 4 + _bytes.length; + Assert.assertEquals(size, result.getEncodedSize()); + + result.setChar("char", (char) 'c'); + size += 1 + EncodingUtils.encodedShortStringLength("char") + EncodingUtils.encodedCharLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setDouble("double", (double) Double.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("double") + EncodingUtils.encodedDoubleLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setFloat("float", (float) Float.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("float") + EncodingUtils.encodedFloatLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setInteger("int", (int) Integer.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("int") + EncodingUtils.encodedIntegerLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setLong("long", (long) Long.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("long") + EncodingUtils.encodedLongLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setShort("short", (short) Short.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("short") + EncodingUtils.encodedShortLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setString("result", "Hello"); + size += 1 + EncodingUtils.encodedShortStringLength("result") + EncodingUtils.encodedLongStringLength("Hello"); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-bool", true); + size += 1 + EncodingUtils.encodedShortStringLength("object-bool") + EncodingUtils.encodedBooleanLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-byte", Byte.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-byte") + EncodingUtils.encodedByteLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-bytes", _bytes); + size += 1 + EncodingUtils.encodedShortStringLength("object-bytes") + 4 + _bytes.length; + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-char", 'c'); + size += 1 + EncodingUtils.encodedShortStringLength("object-char") + EncodingUtils.encodedCharLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-double", Double.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-double") + EncodingUtils.encodedDoubleLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-float", Float.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-float") + EncodingUtils.encodedFloatLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-int", Integer.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-int") + EncodingUtils.encodedIntegerLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-long", Long.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-long") + EncodingUtils.encodedLongLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + result.setObject("object-short", Short.MAX_VALUE); + size += 1 + EncodingUtils.encodedShortStringLength("object-short") + EncodingUtils.encodedShortLength(); + Assert.assertEquals(size, result.getEncodedSize()); + + } + + // public void testEncodingSize1() + // { + // PropertyFieldTable table = new PropertyFieldTable(); + // int length = 0; + // result.put("one", 1L); + // length = EncodingUtils.encodedShortStringLength("one"); + // length += 1 + EncodingUtils.encodedLongLength(); + // assertEquals(length, result.getEncodedSize()); + // + // result.put("two", 2L); + // length += EncodingUtils.encodedShortStringLength("two"); + // length += 1 + EncodingUtils.encodedLongLength(); + // assertEquals(length, result.getEncodedSize()); + // + // result.put("three", 3L); + // length += EncodingUtils.encodedShortStringLength("three"); + // length += 1 + EncodingUtils.encodedLongLength(); + // assertEquals(length, result.getEncodedSize()); + // + // result.put("four", 4L); + // length += EncodingUtils.encodedShortStringLength("four"); + // length += 1 + EncodingUtils.encodedLongLength(); + // assertEquals(length, result.getEncodedSize()); + // + // result.put("five", 5L); + // length += EncodingUtils.encodedShortStringLength("five"); + // length += 1 + EncodingUtils.encodedLongLength(); + // assertEquals(length, result.getEncodedSize()); + // + // //fixme should perhaps be expanded to incorporate all types. + // + // final ByteBuffer buffer = ByteBuffer.allocate((int) result.getEncodedSize()); // FIXME XXX: Is cast a problem? + // + // result.writeToBuffer(buffer); + // + // buffer.flip(); + // + // long length = buffer.getUnsignedInt(); + // + // try + // { + // PropertyFieldTable table2 = new PropertyFieldTable(buffer, length); + // + // Assert.assertEquals((Long) 1L, table2.getLong("one")); + // Assert.assertEquals((Long) 2L, table2.getLong("two")); + // Assert.assertEquals((Long) 3L, table2.getLong("three")); + // Assert.assertEquals((Long) 4L, table2.getLong("four")); + // Assert.assertEquals((Long) 5L, table2.getLong("five")); + // } + // catch (AMQFrameDecodingException e) + // { + // e.printStackTrace(); + // fail("PFT should be instantiated from bytes." + e.getCause()); + // } + // + // } + + /** + * Additional test for setObject + */ + public void testSetObject() + { + FieldTable table = new FieldTable(); + + // Try setting a non primative object + + try + { + table.setObject("value", this); + fail("Only primative values allowed in setObject"); + } + catch (AMQPInvalidClassException iae) + { + // normal path + } + // so length should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } + + /** + * Additional test checkPropertyName doesn't accept Null + */ + public void testCheckPropertyNameasNull() + { + FieldTable table = new FieldTable(); + + try + { + table.setObject((String) null, "String"); + fail("Null property name is not allowed"); + } + catch (IllegalArgumentException iae) + { + // normal path + } + // so length should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } + + /** + * Additional test checkPropertyName doesn't accept an empty String + */ + public void testCheckPropertyNameasEmptyString() + { + FieldTable table = new FieldTable(); + + try + { + table.setObject("", "String"); + fail("empty property name is not allowed"); + } + catch (IllegalArgumentException iae) + { + // normal path + } + // so length should be zero + Assert.assertEquals(0, table.getEncodedSize()); + } + + /** + * Additional test checkPropertyName doesn't accept an empty String + */ + public void testCheckPropertyNamehasMaxLength() + { + String oldVal = System.getProperty("STRICT_AMQP"); + System.setProperty("STRICT_AMQP", "true"); + FieldTable table = new FieldTable(); + + StringBuffer longPropertyName = new StringBuffer(129); + + for (int i = 0; i < 129; i++) + { + longPropertyName.append("x"); + } + + try + { + table.setObject(longPropertyName.toString(), "String"); + fail("property name must be < 128 characters"); + } + catch (IllegalArgumentException iae) + { + // normal path + } + // so length should be zero + Assert.assertEquals(0, table.getEncodedSize()); + if (oldVal != null) + { + System.setProperty("STRICT_AMQP", oldVal); + } + else + { + System.clearProperty("STRICT_AMQP"); + } + } + + /** + * Additional test checkPropertyName starts with a letter + */ + public void testCheckPropertyNameStartCharacterIsLetter() + { + String oldVal = System.getProperty("STRICT_AMQP"); + System.setProperty("STRICT_AMQP", "true"); + FieldTable table = new FieldTable(); + + // Try a name that starts with a number + try + { + table.setObject("1", "String"); + fail("property name must start with a letter"); + } + catch (IllegalArgumentException iae) + { + // normal path + } + // so length should be zero + Assert.assertEquals(0, table.getEncodedSize()); + if (oldVal != null) + { + System.setProperty("STRICT_AMQP", oldVal); + } + else + { + System.clearProperty("STRICT_AMQP"); + } + } + + /** + * Additional test checkPropertyName starts with a hash or a dollar + */ + public void testCheckPropertyNameStartCharacterIsHashorDollar() + { + String oldVal = System.getProperty("STRICT_AMQP"); + System.setProperty("STRICT_AMQP", "true"); + FieldTable table = new FieldTable(); + + // Try a name that starts with a number + try + { + table.setObject("#", "String"); + table.setObject("$", "String"); + } + catch (IllegalArgumentException iae) + { + fail("property name are allowed to start with # and $s"); + } + + if (oldVal != null) + { + System.setProperty("STRICT_AMQP", oldVal); + } + else + { + System.clearProperty("STRICT_AMQP"); + } + } + + /** + * Additional test to test the contents of the table + */ + public void testContents() + { + FieldTable table = new FieldTable(); + + table.setObject("StringProperty", "String"); + + Assert.assertEquals("String", table.getString("StringProperty")); + + // Test Clear + + table.clear(); + + checkEmpty(table); + } + + /** + * Test the contents of the sets + */ + public void testSets() + { + + FieldTable table = new FieldTable(); + + table.setObject("n1", "1"); + table.setObject("n2", "2"); + table.setObject("n3", "3"); + + Assert.assertEquals("1", table.getObject("n1")); + Assert.assertEquals("2", table.getObject("n2")); + Assert.assertEquals("3", table.getObject("n3")); + + } + + private void assertBytesEqual(byte[] expected, byte[] actual) + { + Assert.assertEquals(expected.length, actual.length); + + for (int index = 0; index < expected.length; index++) + { + Assert.assertEquals(expected[index], actual[index]); + } + } + + private void assertBytesNotEqual(byte[] expected, byte[] actual) + { + Assert.assertEquals(expected.length, actual.length); + + for (int index = 0; index < expected.length; index++) + { + Assert.assertFalse(expected[index] == actual[index]); + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(PropertyFieldTableTest.class); + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java b/qpid/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java new file mode 100644 index 0000000000..3243136287 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java @@ -0,0 +1,99 @@ +/* + * + * 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.framing.abstraction; + +import junit.framework.TestCase; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; + +public class MessagePublishInfoImplTest extends TestCase +{ + MessagePublishInfoImpl _mpi; + final AMQShortString _exchange = new AMQShortString("exchange"); + final AMQShortString _routingKey = new AMQShortString("routingKey"); + + public void setUp() + { + _mpi = new MessagePublishInfoImpl(_exchange, true, true, _routingKey); + } + + /** Test that we can update the exchange value. */ + public void testExchange() + { + assertEquals(_exchange, _mpi.getExchange()); + AMQShortString newExchange = new AMQShortString("newExchange"); + //Check we can update the exchange + _mpi.setExchange(newExchange); + assertEquals(newExchange, _mpi.getExchange()); + //Ensure that the new exchange doesn't equal the old one + assertFalse(_exchange.equals(_mpi.getExchange())); + } + + /** + * Check that the immedate value is set correctly and defaulted correctly + */ + public void testIsImmediate() + { + //Check that the set value is correct + assertTrue("Set value for immediate not as expected", _mpi.isImmediate()); + + MessagePublishInfoImpl mpi = new MessagePublishInfoImpl(); + + assertFalse("Default value for immediate should be false", mpi.isImmediate()); + + mpi.setImmediate(true); + + assertTrue("Updated value for immediate not as expected", mpi.isImmediate()); + + } + + /** + * Check that the mandatory value is set correctly and defaulted correctly + */ + public void testIsMandatory() + { + assertTrue("Set value for mandatory not as expected", _mpi.isMandatory()); + + MessagePublishInfoImpl mpi = new MessagePublishInfoImpl(); + + assertFalse("Default value for mandatory should be false", mpi.isMandatory()); + + mpi.setMandatory(true); + + assertTrue("Updated value for mandatory not as expected", mpi.isMandatory()); + } + + /** + * Check that the routingKey value is perserved + */ + public void testRoutingKey() + { + assertEquals(_routingKey, _mpi.getRoutingKey()); + AMQShortString newRoutingKey = new AMQShortString("newRoutingKey"); + + //Check we can update the routingKey + _mpi.setRoutingKey(newRoutingKey); + assertEquals(newRoutingKey, _mpi.getRoutingKey()); + //Ensure that the new routingKey doesn't equal the old one + assertFalse(_routingKey.equals(_mpi.getRoutingKey())); + + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java b/qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java new file mode 100644 index 0000000000..35998de3a1 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/pool/ReferenceCountingExecutorServiceTest.java @@ -0,0 +1,159 @@ +/* + * + * 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.pool; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import junit.framework.TestCase; + + +public class ReferenceCountingExecutorServiceTest extends TestCase +{ + + + private ReferenceCountingExecutorService _executorService = ReferenceCountingExecutorService.getInstance(); // Class under test + private ThreadFactory _beforeExecutorThreadFactory; + + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _beforeExecutorThreadFactory = _executorService.getThreadFactory(); + } + + @Override + protected void tearDown() throws Exception + { + super.tearDown(); + _executorService.setThreadFactory(_beforeExecutorThreadFactory); + } + + + + /** + * Tests that the ReferenceCountingExecutorService correctly manages the reference count. + */ + public void testReferenceCounting() throws Exception + { + final int countBefore = _executorService.getReferenceCount(); + + try + { + _executorService.acquireExecutorService(); + _executorService.acquireExecutorService(); + + assertEquals("Reference count should now be +2", countBefore + 2, _executorService.getReferenceCount()); + } + finally + { + _executorService.releaseExecutorService(); + _executorService.releaseExecutorService(); + } + assertEquals("Reference count should have returned to the initial value", countBefore, _executorService.getReferenceCount()); + } + + /** + * Tests that the executor creates and executes a task using the default thread pool. + */ + public void testExecuteCommandWithDefaultExecutorThreadFactory() throws Exception + { + final CountDownLatch latch = new CountDownLatch(1); + final Set<ThreadGroup> threadGroups = new HashSet<ThreadGroup>(); + + _executorService.acquireExecutorService(); + + try + { + _executorService.getPool().execute(createRunnable(latch, threadGroups)); + + latch.await(3, TimeUnit.SECONDS); + + assertTrue("Expect that executor created a thread using default thread factory", + threadGroups.contains(Thread.currentThread().getThreadGroup())); + } + finally + { + _executorService.releaseExecutorService(); + } + } + + /** + * Tests that the executor creates and executes a task using an overridden thread pool. + */ + public void testExecuteCommandWithOverriddenExecutorThreadFactory() throws Exception + { + final CountDownLatch latch = new CountDownLatch(1); + final ThreadGroup expectedThreadGroup = new ThreadGroup("junit"); + _executorService.setThreadFactory(new ThreadGroupChangingThreadFactory(expectedThreadGroup)); + _executorService.acquireExecutorService(); + + final Set<ThreadGroup> threadGroups = new HashSet<ThreadGroup>(); + + try + { + _executorService.getPool().execute(createRunnable(latch, threadGroups)); + + latch.await(3, TimeUnit.SECONDS); + + assertTrue("Expect that executor created a thread using overridden thread factory", + threadGroups.contains(expectedThreadGroup)); + } + finally + { + _executorService.releaseExecutorService(); + } + } + + private Runnable createRunnable(final CountDownLatch latch, final Set<ThreadGroup> threadGroups) + { + return new Runnable() + { + + public void run() + { + threadGroups.add(Thread.currentThread().getThreadGroup()); + latch.countDown(); + } + + }; + } + + private final class ThreadGroupChangingThreadFactory implements ThreadFactory + { + private final ThreadGroup _newGroup; + + private ThreadGroupChangingThreadFactory(final ThreadGroup newGroup) + { + this._newGroup = newGroup; + } + + public Thread newThread(Runnable r) + { + return new Thread(_newGroup, r); + } + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/session/TestSession.java b/qpid/java/common/src/test/java/org/apache/qpid/session/TestSession.java new file mode 100644 index 0000000000..aafc91b03b --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/session/TestSession.java @@ -0,0 +1,277 @@ +/* + * + * 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.session; + +import org.apache.mina.common.*; + +import java.net.SocketAddress; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; + +public class TestSession implements IoSession +{ + private final ConcurrentMap attributes = new ConcurrentHashMap(); + + public TestSession() + { + } + + public IoService getService() + { + return null; //TODO + } + + public IoServiceConfig getServiceConfig() + { + return null; //TODO + } + + public IoHandler getHandler() + { + return null; //TODO + } + + public IoSessionConfig getConfig() + { + return null; //TODO + } + + public IoFilterChain getFilterChain() + { + return null; //TODO + } + + public WriteFuture write(Object message) + { + return null; //TODO + } + + public CloseFuture close() + { + return null; //TODO + } + + public Object getAttachment() + { + return getAttribute(""); + } + + public Object setAttachment(Object attachment) + { + return setAttribute("",attachment); + } + + public Object getAttribute(String key) + { + return attributes.get(key); + } + + public Object setAttribute(String key, Object value) + { + return attributes.put(key,value); + } + + public Object setAttribute(String key) + { + return attributes.put(key, Boolean.TRUE); + } + + public Object removeAttribute(String key) + { + return attributes.remove(key); + } + + public boolean containsAttribute(String key) + { + return attributes.containsKey(key); + } + + public Set getAttributeKeys() + { + return attributes.keySet(); + } + + public TransportType getTransportType() + { + return null; //TODO + } + + public boolean isConnected() + { + return false; //TODO + } + + public boolean isClosing() + { + return false; //TODO + } + + public CloseFuture getCloseFuture() + { + return null; //TODO + } + + public SocketAddress getRemoteAddress() + { + return null; //TODO + } + + public SocketAddress getLocalAddress() + { + return null; //TODO + } + + public SocketAddress getServiceAddress() + { + return null; //TODO + } + + public int getIdleTime(IdleStatus status) + { + return 0; //TODO + } + + public long getIdleTimeInMillis(IdleStatus status) + { + return 0; //TODO + } + + public void setIdleTime(IdleStatus status, int idleTime) + { + //TODO + } + + public int getWriteTimeout() + { + return 0; //TODO + } + + public long getWriteTimeoutInMillis() + { + return 0; //TODO + } + + public void setWriteTimeout(int writeTimeout) + { + //TODO + } + + public TrafficMask getTrafficMask() + { + return null; //TODO + } + + public void setTrafficMask(TrafficMask trafficMask) + { + //TODO + } + + public void suspendRead() + { + //TODO + } + + public void suspendWrite() + { + //TODO + } + + public void resumeRead() + { + //TODO + } + + public void resumeWrite() + { + //TODO + } + + public long getReadBytes() + { + return 0; //TODO + } + + public long getWrittenBytes() + { + return 0; //TODO + } + + public long getReadMessages() + { + return 0; + } + + public long getWrittenMessages() + { + return 0; + } + + public long getWrittenWriteRequests() + { + return 0; //TODO + } + + public int getScheduledWriteRequests() + { + return 0; //TODO + } + + public int getScheduledWriteBytes() + { + return 0; //TODO + } + + public long getCreationTime() + { + return 0; //TODO + } + + public long getLastIoTime() + { + return 0; //TODO + } + + public long getLastReadTime() + { + return 0; //TODO + } + + public long getLastWriteTime() + { + return 0; //TODO + } + + public boolean isIdle(IdleStatus status) + { + return false; //TODO + } + + public int getIdleCount(IdleStatus status) + { + return 0; //TODO + } + + public long getLastIdleTime(IdleStatus status) + { + return 0; //TODO + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java b/qpid/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java new file mode 100644 index 0000000000..8b470d555e --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java @@ -0,0 +1,130 @@ +/* + * + * 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.test.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import junit.framework.TestResult; + +import org.apache.log4j.Logger; + +public class QpidTestCase extends TestCase +{ + protected static final Logger _logger = Logger.getLogger(QpidTestCase.class); + + /** + * Some tests are excluded when the property test.excludes is set to true. + * An exclusion list is either a file (prop test.excludesfile) which contains one test name + * to be excluded per line or a String (prop test.excludeslist) where tests to be excluded are + * separated by " ". Excluded tests are specified following the format: + * className#testName where className is the class of the test to be + * excluded and testName is the name of the test to be excluded. + * className#* excludes all the tests of the specified class. + */ + static + { + if (Boolean.getBoolean("test.exclude")) + { + _logger.info("Some tests should be excluded, building the exclude list"); + String exclusionListURIs = System.getProperties().getProperty("test.excludefiles", ""); + String exclusionListString = System.getProperties().getProperty("test.excludelist", ""); + List<String> exclusionList = new ArrayList<String>(); + + for (String uri : exclusionListURIs.split("\\s+")) + { + File file = new File(uri); + if (file.exists()) + { + _logger.info("Using exclude file: " + uri); + try + { + BufferedReader in = new BufferedReader(new FileReader(file)); + String excludedTest = in.readLine(); + do + { + exclusionList.add(excludedTest); + excludedTest = in.readLine(); + } + while (excludedTest != null); + } + catch (IOException e) + { + _logger.warn("Exception when reading exclusion list", e); + } + } + } + + if (!exclusionListString.equals("")) + { + _logger.info("Using excludeslist: " + exclusionListString); + for (String test : exclusionListString.split("\\s+")) + { + exclusionList.add(test); + } + } + + _exclusionList = exclusionList; + } + } + + protected static final String MS_CLASS_NAME_KEY = "messagestore.class.name"; + protected static final String MEMORY_STORE_CLASS_NAME = "org.apache.qpid.server.store.MemoryMessageStore"; + + private static List<String> _exclusionList; + + public QpidTestCase() + { + this("QpidTestCase"); + } + + public QpidTestCase(String name) + { + super(name); + } + + public void run(TestResult testResult) + { + if (_exclusionList != null && (_exclusionList.contains(getClass().getPackage().getName() + ".*") || + _exclusionList.contains(getClass().getName() + "#*") || + _exclusionList.contains(getClass().getName() + "#" + getName()))) + { + _logger.info("Test: " + getName() + " is excluded"); + testResult.endTest(this); + } + else + { + super.run(testResult); + } + } + + public String getTestProfileMessageStoreClassName() + { + String storeClass = System.getProperty(MS_CLASS_NAME_KEY); + + return storeClass != null ? storeClass : MEMORY_STORE_CLASS_NAME ; + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java b/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java new file mode 100644 index 0000000000..7b0f93700a --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java @@ -0,0 +1,104 @@ +/* + * + * 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.thread; + +import junit.framework.TestCase; + +/** + * Tests the ThreadFactory. + */ +public class ThreadFactoryTest extends TestCase +{ + public void testThreadFactory() + { + Class<? extends ThreadFactory> threadFactoryClass = null; + try + { + threadFactoryClass = Class.forName(System.getProperty("qpid.thread_factory", + "org.apache.qpid.thread.DefaultThreadFactory")).asSubclass(ThreadFactory.class); + } + // If the thread factory class was wrong it will flagged way before it gets here. + catch(Exception e) + { + fail("Invalid thread factory class"); + } + + assertEquals(threadFactoryClass, Threading.getThreadFactory().getClass()); + } + + /** + * Tests creating a thread without a priority. Also verifies that the factory sets the + * uncaught exception handler so uncaught exceptions are logged to SLF4J. + */ + public void testCreateThreadWithDefaultPriority() + { + Runnable r = createRunnable(); + + Thread t = null; + try + { + t = Threading.getThreadFactory().createThread(r); + } + catch(Exception e) + { + fail("Error creating thread using Qpid thread factory"); + } + + assertNotNull(t); + assertEquals(Thread.NORM_PRIORITY, t.getPriority()); + assertTrue(t.getUncaughtExceptionHandler() instanceof LoggingUncaughtExceptionHandler); + } + + /** + * Tests creating thread with a priority. Also verifies that the factory sets the + * uncaught exception handler so uncaught exceptions are logged to SLF4J. + */ + public void testCreateThreadWithSpecifiedPriority() + { + Runnable r = createRunnable(); + + Thread t = null; + try + { + t = Threading.getThreadFactory().createThread(r, 4); + } + catch(Exception e) + { + fail("Error creating thread using Qpid thread factory"); + } + + assertNotNull(t); + assertEquals(4, t.getPriority()); + assertTrue(t.getUncaughtExceptionHandler() instanceof LoggingUncaughtExceptionHandler); + } + + private Runnable createRunnable() + { + Runnable r = new Runnable(){ + + public void run(){ + + } + }; + return r; + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java new file mode 100644 index 0000000000..375a326654 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java @@ -0,0 +1,446 @@ +/* + * + * 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.transport; + +import org.apache.mina.util.AvailablePortFinder; + +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.transport.network.ConnectionBinding; +import org.apache.qpid.transport.network.io.IoAcceptor; +import org.apache.qpid.transport.util.Logger; +import org.apache.qpid.transport.util.Waiter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.io.IOException; + +import static org.apache.qpid.transport.Option.*; + +/** + * ConnectionTest + */ + +public class ConnectionTest extends QpidTestCase implements SessionListener +{ + + private static final Logger log = Logger.get(ConnectionTest.class); + + private int port; + private volatile boolean queue = false; + private List<MessageTransfer> messages = new ArrayList<MessageTransfer>(); + private List<MessageTransfer> incoming = new ArrayList<MessageTransfer>(); + + private IoAcceptor _ioa = null; + + + protected void setUp() throws Exception + { + super.setUp(); + + port = AvailablePortFinder.getNextAvailable(12000); + } + + protected void tearDown() throws Exception + { + if (_ioa != null) + { + _ioa.close(); + } + + super.tearDown(); + } + + public void opened(Session ssn) {} + + public void resumed(Session ssn) {} + + public void message(final Session ssn, MessageTransfer xfr) + { + if (queue) + { + messages.add(xfr); + ssn.processed(xfr); + return; + } + + String body = xfr.getBodyString(); + + if (body.startsWith("CLOSE")) + { + ssn.getConnection().close(); + } + else if (body.startsWith("DELAYED_CLOSE")) + { + ssn.processed(xfr); + new Thread() + { + public void run() + { + try + { + sleep(3000); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + ssn.getConnection().close(); + } + }.start(); + } + else if (body.startsWith("ECHO")) + { + int id = xfr.getId(); + ssn.invoke(xfr); + ssn.processed(id); + } + else if (body.startsWith("SINK")) + { + ssn.processed(xfr); + } + else if (body.startsWith("DROP")) + { + // do nothing + } + else if (body.startsWith("EXCP")) + { + ExecutionException exc = new ExecutionException(); + exc.setDescription("intentional exception for testing"); + ssn.invoke(exc); + ssn.close(); + } + else + { + throw new IllegalArgumentException + ("unrecognized message: " + body); + } + } + + public void exception(Session ssn, SessionException exc) + { + throw exc; + } + + public void closed(Session ssn) {} + + private void send(Session ssn, String msg) + { + send(ssn, msg, false); + } + + private void send(Session ssn, String msg, boolean sync) + { + ssn.messageTransfer + ("xxx", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED, + null, msg, sync ? SYNC : NONE); + } + + private Connection connect(final CountDownLatch closed) + { + Connection conn = new Connection(); + conn.addConnectionListener(new ConnectionListener() + { + public void opened(Connection conn) {} + public void exception(Connection conn, ConnectionException exc) + { + exc.printStackTrace(); + } + public void closed(Connection conn) + { + if (closed != null) + { + closed.countDown(); + } + } + }); + conn.connect("localhost", port, null, "guest", "guest", false); + return conn; + } + + public void testProtocolNegotiationExceptionOverridesCloseException() throws Exception + { + // Force os.name to be windows to exercise code in IoReceiver + // that looks for the value of os.name + System.setProperty("os.name","windows"); + + // Start server as 0-9 to froce a ProtocolVersionException + startServer(new ProtocolHeader(1, 0, 9)); + + CountDownLatch closed = new CountDownLatch(1); + + try + { + connect(closed); + fail("ProtocolVersionException expected"); + } + catch (ProtocolVersionException pve) + { + //Expected code path + } + catch (Exception e) + { + fail("ProtocolVersionException expected. Got:" + e.getMessage()); + } + } + + private void startServer() + { + startServer(new ProtocolHeader(1, 0, 10)); + } + + private void startServer(final ProtocolHeader protocolHeader) + { + ConnectionDelegate server = new ServerDelegate() + { + @Override + public void init(Connection conn, ProtocolHeader hdr) + { + conn.send(protocolHeader); + List<Object> utf8 = new ArrayList<Object>(); + utf8.add("utf8"); + conn.connectionStart(null, Collections.EMPTY_LIST, utf8); + } + + @Override + public Session getSession(Connection conn, SessionAttach atc) + { + Session ssn = super.getSession(conn, atc); + ssn.setSessionListener(ConnectionTest.this); + return ssn; + } + }; + + try + { + _ioa = new IoAcceptor("localhost", port, ConnectionBinding.get(server)); + } + catch (IOException e) + { + e.printStackTrace(); + fail("Unable to start Server for test due to:" + e.getMessage()); + } + + _ioa.start(); + } + + public void testClosedNotificationAndWriteToClosed() throws Exception + { + startServer(); + + CountDownLatch closed = new CountDownLatch(1); + Connection conn = connect(closed); + + Session ssn = conn.createSession(1); + send(ssn, "CLOSE"); + + if (!closed.await(3, TimeUnit.SECONDS)) + { + fail("never got notified of connection close"); + } + + try + { + conn.connectionCloseOk(); + fail("writing to a closed socket succeeded"); + } + catch (TransportException e) + { + // expected + } + } + + class FailoverConnectionListener implements ConnectionListener + { + public void opened(Connection conn) {} + + public void exception(Connection conn, ConnectionException e) + { + throw e; + } + + public void closed(Connection conn) + { + queue = true; + conn.connect("localhost", port, null, "guest", "guest"); + conn.resume(); + } + } + + class TestSessionListener implements SessionListener + { + public void opened(Session s) {} + public void resumed(Session s) {} + public void exception(Session s, SessionException e) {} + public void message(Session s, MessageTransfer xfr) + { + synchronized (incoming) + { + incoming.add(xfr); + incoming.notifyAll(); + } + + s.processed(xfr); + } + public void closed(Session s) {} + } + + public void testResumeNonemptyReplayBuffer() throws Exception + { + startServer(); + + Connection conn = new Connection(); + conn.addConnectionListener(new FailoverConnectionListener()); + conn.connect("localhost", port, null, "guest", "guest"); + Session ssn = conn.createSession(1); + ssn.setSessionListener(new TestSessionListener()); + + send(ssn, "SINK 0"); + send(ssn, "ECHO 1"); + send(ssn, "ECHO 2"); + + ssn.sync(); + + String[] msgs = { "DROP 3", "DROP 4", "DROP 5", "CLOSE 6", "SINK 7" }; + for (String m : msgs) + { + send(ssn, m); + } + + ssn.sync(); + + assertEquals(msgs.length, messages.size()); + for (int i = 0; i < msgs.length; i++) + { + assertEquals(msgs[i], messages.get(i).getBodyString()); + } + + queue = false; + + send(ssn, "ECHO 8"); + send(ssn, "ECHO 9"); + + synchronized (incoming) + { + Waiter w = new Waiter(incoming, 30000); + while (w.hasTime() && incoming.size() < 4) + { + w.await(); + } + + assertEquals(4, incoming.size()); + assertEquals("ECHO 1", incoming.get(0).getBodyString()); + assertEquals(0, incoming.get(0).getId()); + assertEquals("ECHO 2", incoming.get(1).getBodyString()); + assertEquals(1, incoming.get(1).getId()); + assertEquals("ECHO 8", incoming.get(2).getBodyString()); + assertEquals(0, incoming.get(0).getId()); + assertEquals("ECHO 9", incoming.get(3).getBodyString()); + assertEquals(1, incoming.get(1).getId()); + } + } + + public void testResumeEmptyReplayBuffer() throws InterruptedException + { + startServer(); + + Connection conn = new Connection(); + conn.addConnectionListener(new FailoverConnectionListener()); + conn.connect("localhost", port, null, "guest", "guest"); + Session ssn = conn.createSession(1); + ssn.setSessionListener(new TestSessionListener()); + + send(ssn, "SINK 0"); + send(ssn, "SINK 1"); + send(ssn, "DELAYED_CLOSE 2"); + ssn.sync(); + Thread.sleep(6000); + send(ssn, "SINK 3"); + ssn.sync(); + System.out.println(messages); + assertEquals(1, messages.size()); + assertEquals("SINK 3", messages.get(0).getBodyString()); + } + + public void testFlushExpected() throws InterruptedException + { + startServer(); + + Connection conn = new Connection(); + conn.connect("localhost", port, null, "guest", "guest"); + Session ssn = conn.createSession(); + ssn.sessionFlush(EXPECTED); + send(ssn, "SINK 0"); + ssn.sessionFlush(EXPECTED); + send(ssn, "SINK 1"); + ssn.sync(); + } + + public void testHeartbeat() + { + startServer(); + Connection conn = new Connection(); + conn.connect("localhost", port, null, "guest", "guest"); + conn.connectionHeartbeat(); + conn.close(); + } + + public void testExecutionExceptionInvoke() throws Exception + { + startServer(); + + Connection conn = new Connection(); + conn.connect("localhost", port, null, "guest", "guest"); + Session ssn = conn.createSession(); + send(ssn, "EXCP 0"); + Thread.sleep(3000); + try + { + send(ssn, "SINK 1"); + } + catch (SessionException exc) + { + assertNotNull(exc.getException()); + } + } + + public void testExecutionExceptionSync() throws Exception + { + startServer(); + + Connection conn = new Connection(); + conn.connect("localhost", port, null, "guest", "guest"); + Session ssn = conn.createSession(); + send(ssn, "EXCP 0", true); + try + { + ssn.sync(); + fail("this should have failed"); + } + catch (SessionException exc) + { + assertNotNull(exc.getException()); + } + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/GenTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/GenTest.java new file mode 100644 index 0000000000..512a0a29a6 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/GenTest.java @@ -0,0 +1,44 @@ +/* + * + * 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.transport; + +import junit.framework.TestCase; + +/** + * GenTest + * + */ + +public class GenTest extends TestCase +{ + + public void testBooleans() + { + QueueDeclare qd = new QueueDeclare().queue("test-queue").durable(false); + assertEquals(qd.getQueue(), "test-queue"); + assertFalse("durable should be false", qd.getDurable()); + qd.setDurable(true); + assertTrue("durable should be true", qd.getDurable()); + qd.setDurable(false); + assertFalse("durable should be false again", qd.getDurable()); + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java new file mode 100644 index 0000000000..ad45d00e46 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java @@ -0,0 +1,238 @@ +/* + * + * 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.transport; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +import static org.apache.qpid.util.Serial.*; + +/** + * RangeSetTest + * + */ + +public class RangeSetTest extends TestCase +{ + + private void check(RangeSet ranges) + { + List<Integer> posts = new ArrayList<Integer>(); + for (Range range : ranges) + { + posts.add(range.getLower()); + posts.add(range.getUpper()); + } + + List<Integer> sorted = new ArrayList<Integer>(posts); + Collections.sort(sorted, COMPARATOR); + + assertEquals(posts, sorted); + + int idx = 1; + while (idx + 1 < posts.size()) + { + assertTrue(!eq(posts.get(idx) + 1, posts.get(idx+1))); + idx += 2; + } + } + + public void test1() + { + RangeSet ranges = new RangeSet(); + ranges.add(5, 10); + check(ranges); + ranges.add(15, 20); + check(ranges); + ranges.add(23, 25); + check(ranges); + ranges.add(12, 14); + check(ranges); + ranges.add(0, 1); + check(ranges); + ranges.add(3, 11); + check(ranges); + } + + public void test2() + { + RangeSet rs = new RangeSet(); + check(rs); + + rs.add(1); + assertTrue(rs.includes(1)); + assertTrue(!rs.includes(2)); + assertTrue(!rs.includes(0)); + check(rs); + + rs.add(2); + assertTrue(!rs.includes(0)); + assertTrue(rs.includes(1)); + assertTrue(rs.includes(2)); + assertTrue(!rs.includes(3)); + check(rs); + + rs.add(0); + + assertTrue(!rs.includes(-1)); + assertTrue(rs.includes(0)); + assertTrue(rs.includes(1)); + assertTrue(rs.includes(2)); + assertTrue(!rs.includes(3)); + check(rs); + + rs.add(37); + + assertTrue(!rs.includes(-1)); + assertTrue(rs.includes(0)); + assertTrue(rs.includes(1)); + assertTrue(rs.includes(2)); + assertTrue(!rs.includes(3)); + assertTrue(!rs.includes(36)); + assertTrue(rs.includes(37)); + assertTrue(!rs.includes(38)); + check(rs); + + rs.add(-1); + check(rs); + + rs.add(-3); + check(rs); + + rs.add(1, 20); + assertTrue(!rs.includes(21)); + assertTrue(rs.includes(20)); + check(rs); + } + + public void testAddSelf() + { + RangeSet a = new RangeSet(); + a.add(0, 8); + check(a); + a.add(0, 8); + check(a); + assertEquals(a.size(), 1); + Range range = a.iterator().next(); + assertEquals(range.getLower(), 0); + assertEquals(range.getUpper(), 8); + } + + public void testIntersect1() + { + Range a = new Range(0, 10); + Range b = new Range(9, 20); + Range i1 = a.intersect(b); + Range i2 = b.intersect(a); + assertEquals(i1.getUpper(), 10); + assertEquals(i2.getUpper(), 10); + assertEquals(i1.getLower(), 9); + assertEquals(i2.getLower(), 9); + } + + public void testIntersect2() + { + Range a = new Range(0, 10); + Range b = new Range(11, 20); + assertNull(a.intersect(b)); + assertNull(b.intersect(a)); + } + + public void testIntersect3() + { + Range a = new Range(0, 10); + Range b = new Range(3, 5); + Range i1 = a.intersect(b); + Range i2 = b.intersect(a); + assertEquals(i1.getUpper(), 5); + assertEquals(i2.getUpper(), 5); + assertEquals(i1.getLower(), 3); + assertEquals(i2.getLower(), 3); + } + + public void testSubtract1() + { + Range a = new Range(0, 10); + assertTrue(a.subtract(a).isEmpty()); + } + + public void testSubtract2() + { + Range a = new Range(0, 10); + Range b = new Range(20, 30); + List<Range> ranges = a.subtract(b); + assertEquals(ranges.size(), 1); + Range d = ranges.get(0); + assertEquals(d.getLower(), a.getLower()); + assertEquals(d.getUpper(), a.getUpper()); + } + + public void testSubtract3() + { + Range a = new Range(20, 30); + Range b = new Range(0, 10); + List<Range> ranges = a.subtract(b); + assertEquals(ranges.size(), 1); + Range d = ranges.get(0); + assertEquals(d.getLower(), a.getLower()); + assertEquals(d.getUpper(), a.getUpper()); + } + + public void testSubtract4() + { + Range a = new Range(0, 10); + Range b = new Range(3, 5); + List<Range> ranges = a.subtract(b); + assertEquals(ranges.size(), 2); + Range low = ranges.get(0); + Range high = ranges.get(1); + assertEquals(low.getLower(), 0); + assertEquals(low.getUpper(), 2); + assertEquals(high.getLower(), 6); + assertEquals(high.getUpper(), 10); + } + + public void testSubtract5() + { + Range a = new Range(0, 10); + Range b = new Range(3, 20); + List<Range> ranges = a.subtract(b); + assertEquals(ranges.size(), 1); + Range d = ranges.get(0); + assertEquals(d.getLower(), 0); + assertEquals(d.getUpper(), 2); + } + + public void testSubtract6() + { + Range a = new Range(0, 10); + Range b = new Range(-10, 5); + List<Range> ranges = a.subtract(b); + assertEquals(ranges.size(), 1); + Range d = ranges.get(0); + assertEquals(d.getLower(), 6); + assertEquals(d.getUpper(), 10); + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java new file mode 100644 index 0000000000..957a7190ee --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java @@ -0,0 +1,133 @@ +/* + * + * 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.transport; + +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.protocol.ProtocolEngineFactory; +import org.apache.qpid.ssl.SSLContextFactory; + +/** + * Test implementation of IoSession, which is required for some tests. Methods not being used are not implemented, + * so if this class is being used and some methods are to be used, then please update those. + */ +public class TestNetworkDriver implements NetworkDriver +{ + private final ConcurrentMap attributes = new ConcurrentHashMap(); + private String _remoteHost = "127.0.0.1"; + private String _localHost = "127.0.0.1"; + private int _port = 1; + private SocketAddress _localAddress = null; + private SocketAddress _remoteAddress = null; + + public TestNetworkDriver() + { + } + + public void bind(int port, InetAddress[] addresses, ProtocolEngineFactory protocolFactory, + NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException + { + + } + + public SocketAddress getLocalAddress() + { + return (_localAddress != null) ? _localAddress : new InetSocketAddress(_localHost, _port); + } + + public SocketAddress getRemoteAddress() + { + return (_remoteAddress != null) ? _remoteAddress : new InetSocketAddress(_remoteHost, _port); + } + + public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkDriverConfiguration config, + SSLContextFactory sslFactory) throws OpenException + { + + } + + public void setMaxReadIdle(int idleTime) + { + + } + + public void setMaxWriteIdle(int idleTime) + { + + } + + public void close() + { + + } + + public void flush() + { + + } + + public void send(ByteBuffer msg) + { + + } + + public void setIdleTimeout(int i) + { + + } + + public void setPort(int port) + { + _port = port; + } + + public int getPort() + { + return _port; + } + + public void setLocalHost(String host) + { + _localHost = host; + } + + public void setRemoteHost(String host) + { + _remoteHost = host; + } + + public void setLocalAddress(SocketAddress address) + { + _localAddress = address; + } + + public void setRemoteAddress(SocketAddress address) + { + _remoteAddress = address; + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java new file mode 100644 index 0000000000..79bf184fe2 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java @@ -0,0 +1,47 @@ +/* + * + * 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.transport.codec; + +import junit.framework.TestCase; + +import java.nio.ByteBuffer; + +/** + * BBEncoderTest + * + */ + +public class BBEncoderTest extends TestCase +{ + + public void testGrow() + { + BBEncoder enc = new BBEncoder(4); + enc.writeInt32(0xDEADBEEF); + ByteBuffer buf = enc.buffer(); + assertEquals(0xDEADBEEF, buf.getInt(0)); + enc.writeInt32(0xBEEFDEAD); + buf = enc.buffer(); + assertEquals(0xDEADBEEF, buf.getInt(0)); + assertEquals(0xBEEFDEAD, buf.getInt(4)); + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java new file mode 100644 index 0000000000..fc8e689ca4 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java @@ -0,0 +1,494 @@ +/* + * + * 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.transport.network.mina; + +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import junit.framework.TestCase; + +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.protocol.ProtocolEngineFactory; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.OpenException; + +public class MINANetworkDriverTest extends TestCase +{ + + private static final String TEST_DATA = "YHALOTHAR"; + private static int TEST_PORT = 2323; + private NetworkDriver _server; + private NetworkDriver _client; + private CountingProtocolEngine _countingEngine; // Keeps a count of how many bytes it's read + private Exception _thrownEx; + + @Override + public void setUp() + { + _server = new MINANetworkDriver(); + _client = new MINANetworkDriver(); + _thrownEx = null; + _countingEngine = new CountingProtocolEngine(); + // increment the port to prevent tests clashing with each other when + // the port is in TIMED_WAIT state. + TEST_PORT++; + } + + @Override + public void tearDown() + { + if (_server != null) + { + _server.close(); + } + + if (_client != null) + { + _client.close(); + } + } + + /** + * Tests that a socket can't be opened if a driver hasn't been bound + * to the port and can be opened if a driver has been bound. + * @throws BindException + * @throws UnknownHostException + * @throws OpenException + */ + public void testBindOpen() throws BindException, UnknownHostException, OpenException + { + try + { + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + } + catch (OpenException e) + { + _thrownEx = e; + } + + assertNotNull("Open should have failed since no engine bound", _thrownEx); + + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + } + + /** + * Tests that a socket can't be opened after a bound NetworkDriver has been closed + * @throws BindException + * @throws UnknownHostException + * @throws OpenException + */ + public void testBindOpenCloseOpen() throws BindException, UnknownHostException, OpenException + { + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + _client.close(); + _server.close(); + + try + { + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + } + catch (OpenException e) + { + _thrownEx = e; + } + assertNotNull("Open should have failed", _thrownEx); + } + + /** + * Checks that the right exception is thrown when binding a NetworkDriver to an already + * existing socket. + */ + public void testBindPortInUse() + { + try + { + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + } + catch (BindException e) + { + fail("First bind should not fail"); + } + + try + { + _client.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + } + catch (BindException e) + { + _thrownEx = e; + } + assertNotNull("Second bind should throw BindException", _thrownEx); + } + + /** + * tests that bytes sent on a network driver are received at the other end + * + * @throws UnknownHostException + * @throws OpenException + * @throws InterruptedException + * @throws BindException + */ + public void testSend() throws UnknownHostException, OpenException, InterruptedException, BindException + { + // Open a connection from a counting engine to an echo engine + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + + // Tell the counting engine how much data we're sending + _countingEngine.setNewLatch(TEST_DATA.getBytes().length); + + // Send the data and wait for up to 2 seconds to get it back + _client.send(ByteBuffer.wrap(TEST_DATA.getBytes())); + _countingEngine.getLatch().await(2, TimeUnit.SECONDS); + + // Check what we got + assertEquals("Wrong amount of data recieved", TEST_DATA.getBytes().length, _countingEngine.getReadBytes()); + } + + /** + * Opens a connection with a low read idle and check that it gets triggered + * @throws BindException + * @throws OpenException + * @throws UnknownHostException + * + */ + public void testSetReadIdle() throws BindException, UnknownHostException, OpenException + { + // Open a connection from a counting engine to an echo engine + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + assertFalse("Reader should not have been idle", _countingEngine.getReaderHasBeenIdle()); + _client.setMaxReadIdle(1); + sleepForAtLeast(1500); + assertTrue("Reader should have been idle", _countingEngine.getReaderHasBeenIdle()); + } + + /** + * Opens a connection with a low write idle and check that it gets triggered + * @throws BindException + * @throws OpenException + * @throws UnknownHostException + * + */ + public void testSetWriteIdle() throws BindException, UnknownHostException, OpenException + { + // Open a connection from a counting engine to an echo engine + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + assertFalse("Reader should not have been idle", _countingEngine.getWriterHasBeenIdle()); + _client.setMaxWriteIdle(1); + sleepForAtLeast(1500); + assertTrue("Reader should have been idle", _countingEngine.getWriterHasBeenIdle()); + } + + + /** + * Creates and then closes a connection from client to server and checks that the server + * has its closed() method called. Then creates a new client and closes the server to check + * that the client has its closed() method called. + * @throws BindException + * @throws UnknownHostException + * @throws OpenException + */ + public void testClosed() throws BindException, UnknownHostException, OpenException + { + // Open a connection from a counting engine to an echo engine + EchoProtocolEngineSingletonFactory factory = new EchoProtocolEngineSingletonFactory(); + _server.bind(TEST_PORT, null, factory, null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + EchoProtocolEngine serverEngine = null; + while (serverEngine == null) + { + serverEngine = factory.getEngine(); + if (serverEngine == null) + { + try + { + Thread.sleep(10); + } + catch (InterruptedException e) + { + } + } + } + assertFalse("Server should not have been closed", serverEngine.getClosed()); + serverEngine.setNewLatch(1); + _client.close(); + try + { + serverEngine.getLatch().await(2, TimeUnit.SECONDS); + } + catch (InterruptedException e) + { + } + assertTrue("Server should have been closed", serverEngine.getClosed()); + + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + _countingEngine.setClosed(false); + assertFalse("Client should not have been closed", _countingEngine.getClosed()); + _countingEngine.setNewLatch(1); + _server.close(); + try + { + _countingEngine.getLatch().await(2, TimeUnit.SECONDS); + } + catch (InterruptedException e) + { + } + assertTrue("Client should have been closed", _countingEngine.getClosed()); + } + + /** + * Create a connection and instruct the client to throw an exception when it gets some data + * and that the latch gets counted down. + * @throws BindException + * @throws UnknownHostException + * @throws OpenException + * @throws InterruptedException + */ + public void testExceptionCaught() throws BindException, UnknownHostException, OpenException, InterruptedException + { + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + + + assertEquals("Exception should not have been thrown", 1, + _countingEngine.getExceptionLatch().getCount()); + _countingEngine.setErrorOnNextRead(true); + _countingEngine.setNewLatch(TEST_DATA.getBytes().length); + _client.send(ByteBuffer.wrap(TEST_DATA.getBytes())); + _countingEngine.getExceptionLatch().await(2, TimeUnit.SECONDS); + assertEquals("Exception should have been thrown", 0, + _countingEngine.getExceptionLatch().getCount()); + } + + /** + * Opens a connection and checks that the remote address is the one that was asked for + * @throws BindException + * @throws UnknownHostException + * @throws OpenException + */ + public void testGetRemoteAddress() throws BindException, UnknownHostException, OpenException + { + _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null); + _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null); + assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), TEST_PORT), + _client.getRemoteAddress()); + } + + private class EchoProtocolEngineSingletonFactory implements ProtocolEngineFactory + { + EchoProtocolEngine _engine = null; + + public ProtocolEngine newProtocolEngine(NetworkDriver driver) + { + if (_engine == null) + { + _engine = new EchoProtocolEngine(); + _engine.setNetworkDriver(driver); + } + return getEngine(); + } + + public EchoProtocolEngine getEngine() + { + return _engine; + } + } + + public class CountingProtocolEngine implements ProtocolEngine + { + + protected NetworkDriver _driver; + public ArrayList<ByteBuffer> _receivedBytes = new ArrayList<ByteBuffer>(); + private int _readBytes; + private CountDownLatch _latch = new CountDownLatch(0); + private boolean _readerHasBeenIdle; + private boolean _writerHasBeenIdle; + private boolean _closed = false; + private boolean _nextReadErrors = false; + private CountDownLatch _exceptionLatch = new CountDownLatch(1); + + public void closed() + { + setClosed(true); + _latch.countDown(); + } + + public void setErrorOnNextRead(boolean b) + { + _nextReadErrors = b; + } + + public void setNewLatch(int length) + { + _latch = new CountDownLatch(length); + } + + public long getReadBytes() + { + return _readBytes; + } + + public SocketAddress getRemoteAddress() + { + if (_driver != null) + { + return _driver.getRemoteAddress(); + } + else + { + return null; + } + } + + public SocketAddress getLocalAddress() + { + if (_driver != null) + { + return _driver.getLocalAddress(); + } + else + { + return null; + } + } + + public long getWrittenBytes() + { + return 0; + } + + public void readerIdle() + { + _readerHasBeenIdle = true; + } + + public void setNetworkDriver(NetworkDriver driver) + { + _driver = driver; + } + + public void writeFrame(AMQDataBlock frame) + { + + } + + public void writerIdle() + { + _writerHasBeenIdle = true; + } + + public void exception(Throwable t) + { + _exceptionLatch.countDown(); + } + + public CountDownLatch getExceptionLatch() + { + return _exceptionLatch; + } + + public void received(ByteBuffer msg) + { + // increment read bytes and count down the latch for that many + int bytes = msg.remaining(); + _readBytes += bytes; + for (int i = 0; i < bytes; i++) + { + _latch.countDown(); + } + + // Throw an error if we've been asked too, but we can still count + if (_nextReadErrors) + { + throw new RuntimeException("Was asked to error"); + } + } + + public CountDownLatch getLatch() + { + return _latch; + } + + public boolean getWriterHasBeenIdle() + { + return _writerHasBeenIdle; + } + + public boolean getReaderHasBeenIdle() + { + return _readerHasBeenIdle; + } + + public void setClosed(boolean _closed) + { + this._closed = _closed; + } + + public boolean getClosed() + { + return _closed; + } + + } + + private class EchoProtocolEngine extends CountingProtocolEngine + { + + public void received(ByteBuffer msg) + { + super.received(msg); + msg.rewind(); + _driver.send(msg); + } + } + + public static void sleepForAtLeast(long period) + { + long start = System.currentTimeMillis(); + long timeLeft = period; + while (timeLeft > 0) + { + try + { + Thread.sleep(timeLeft); + } + catch (InterruptedException e) + { + // Ignore it + } + timeLeft = period - (System.currentTimeMillis() - start); + } + } +}
\ No newline at end of file diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java new file mode 100644 index 0000000000..942901f1c0 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/util/CommandLineParserTest.java @@ -0,0 +1,554 @@ +/* + * + * 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.util; + +import junit.framework.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Properties; + +/** + * Unit tests the {@link CommandLineParser} class. + * + * <p><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Check that parsing a single flag works ok. + * <tr><td> Check that parsing multiple flags condensed together works ok. + * <tr><td> Check that parsing an option with a space between it and its argument works ok. + * <tr><td> Check that parsing an option with no space between it and its argument works ok. + * <tr><td> Check that parsing an option with specific argument format works ok. + * <tr><td> Check that parsing an option with specific argument format fails on bad argument. + * <tr><td> Check that parsing a flag condensed together with an option fails. + * <tr><td> Check that parsing a free argument works ok. + * <tr><td> Check that parsing a free argument with specific format works ok. + * <tr><td> Check that parsing a free argument with specific format fails on bad argument. + * <tr><td> Check that parsing a mandatory option works ok. + * <tr><td> Check that parsing a mandatory free argument works ok. + * <tr><td> Check that parsing a mandatory option fails when no option is set. + * <tr><td> Check that parsing a mandatory free argument fails when no argument is specified. + * <tr><td> Check that parsing an unknown option works when unknowns not errors. + * <tr><td> Check that parsing an unknown flag fails when unknowns are to be reported as errors. + * <tr><td> Check that parsing an unknown option fails when unknowns are to be reported as errors. + * <tr><td> Check that get errors returns a string on errors. + * <tr><td> Check that get errors returns an empty string on no errors. + * <tr><td> Check that get usage returns a string. + * <tr><td> Check that get options in force returns an empty string before parsing. + * <tr><td> Check that get options in force return a non-empty string after parsing. + * </table> + */ +public class CommandLineParserTest extends TestCase +{ + private static final Logger log = LoggerFactory.getLogger(CommandLineParserTest.class); + + public CommandLineParserTest(String name) + { + super(name); + } + + /** + * Compile all the tests for the default test implementation of a traversable state into a test suite. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("CommandLineParser Tests"); + + // Add all the tests defined in this class (using the default constructor) + suite.addTestSuite(CommandLineParserTest.class); + + return suite; + } + + /** Check that get errors returns an empty string on no errors. */ + public void testGetErrorsReturnsEmptyStringOnNoErrors() throws Exception + { + // Create a command line parser for some flags and options. + CommandLineParser parser = + new CommandLineParser( + new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Option 2.", "test" }, + { "t3", "Test Option 3.", "test", "true" }, + { "t4", "Test Option 4.", "test", null, "^test$" } + }); + + // Do some legal parsing. + parser.parseCommandLine(new String[] { "-t1", "-t2test", "-t3test", "-t4test" }); + + // Check that the get errors message returns an empty string. + assertTrue("The errors method did not return an empty string.", "".equals(parser.getErrors())); + } + + /** Check that get errors returns a string on errors. */ + public void testGetErrorsReturnsStringOnErrors() throws Exception + { + // Create a command line parser for some flags and options. + CommandLineParser parser = + new CommandLineParser( + new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Option 2.", "test" }, + { "t3", "Test Option 3.", "test", "true" }, + { "t4", "Test Option 4.", "test", null, "^test$" } + }); + + try + { + // Do some illegal parsing. + parser.parseCommandLine(new String[] { "-t1", "-t1t2test", "-t4fail" }); + } + catch (IllegalArgumentException e) + { } + + // Check that the get errors message returns a string. + assertTrue("The errors method returned an empty string.", + !((parser.getErrors() == null) || "".equals(parser.getErrors()))); + + } + + /** Check that get options in force returns an empty string before parsing. */ + public void testGetOptionsInForceReturnsEmptyStringBeforeParsing() throws Exception + { + // Create a command line parser for some flags and options. + CommandLineParser parser = + new CommandLineParser( + new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Option 2.", "test" }, + { "t3", "Test Option 3.", "test", "true" }, + { "t4", "Test Option 4.", "test", null, "^test$" } + }); + + // Check that the options in force method returns an empty string. + assertTrue("The options in force method did not return an empty string.", "".equals(parser.getOptionsInForce())); + } + + /** Check that get options in force return a non-empty string after parsing. */ + public void testGetOptionsInForceReturnsNonEmptyStringAfterParsing() throws Exception + { + // Create a command line parser for some flags and options. + CommandLineParser parser = + new CommandLineParser( + new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Option 2.", "test" }, + { "t3", "Test Option 3.", "test", "true" }, + { "t4", "Test Option 4.", "test", null, "^test$" } + }); + + // Do some parsing. + parser.parseCommandLine(new String[] { "-t1", "-t2test", "-t3test", "-t4test" }); + + // Check that the options in force method returns a string. + assertTrue("The options in force method did not return a non empty string.", + !((parser.getOptionsInForce() == null) || "".equals(parser.getOptionsInForce()))); + } + + /** Check that get usage returns a string. */ + public void testGetUsageReturnsString() throws Exception + { + // Create a command line parser for some flags and options. + CommandLineParser parser = + new CommandLineParser( + new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Option 2.", "test" }, + { "t3", "Test Option 3.", "test", "true" }, + { "t4", "Test Option 4.", "test", null, "^test$" } + }); + + // Check that the usage method returns a string. + assertTrue("The usage method did not return a non empty string.", + !((parser.getUsage() == null) || "".equals(parser.getUsage()))); + } + + /** Check that parsing multiple flags condensed together works ok. */ + public void testParseCondensedFlagsOk() throws Exception + { + // Create a command line parser for multiple flags. + CommandLineParser parser = + new CommandLineParser( + new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Flag 2." }, + { "t3", "Test Flag 3." } + }); + + // Parse a command line with the flags set and condensed together. + Properties testProps = parser.parseCommandLine(new String[] { "-t1t2t3" }); + + // Check that the flags were set in the parsed properties. + assertTrue("The t1 flag was not \"true\", it was: " + testProps.get("t1"), "true".equals(testProps.get("t1"))); + assertTrue("The t2 flag was not \"true\", it was: " + testProps.get("t2"), "true".equals(testProps.get("t2"))); + assertTrue("The t3 flag was not \"true\", it was: " + testProps.get("t3"), "true".equals(testProps.get("t3"))); + } + + /** Check that parsing a flag condensed together with an option fails. */ + public void testParseFlagCondensedWithOptionFails() throws Exception + { + // Create a command line parser for a flag and an option. + CommandLineParser parser = + new CommandLineParser(new String[][] + { + { "t1", "Test Flag 1." }, + { "t2", "Test Option 2.", "test" } + }); + + // Check that the parser reports an error. + boolean testPassed = false; + + try + { + // Parse a command line with the flag and option condensed together. + Properties testProps = parser.parseCommandLine(new String[] { "-t1t2" }); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + assertTrue("IllegalArgumentException not thrown when a flag and option are condensed together.", testPassed); + } + + /** Check that parsing a free argument with specific format fails on bad argument. */ + public void testParseFormattedFreeArgumentFailsBadArgument() throws Exception + { + // Create a command line parser for a formatted free argument. + CommandLineParser parser = + new CommandLineParser(new String[][] + { + { "1", "Test Free Argument.", "test", null, "^test$" } + }); + + // Check that the parser signals an error for a badly formatted argument. + boolean testPassed = false; + + try + { + // Parse a command line with this option set incorrectly. + Properties testProps = parser.parseCommandLine(new String[] { "fail" }); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + assertTrue("IllegalArgumentException not thrown when a badly formatted argument was set.", testPassed); + } + + /** Check that parsing a free argument with specific format works ok. */ + public void testParseFormattedFreeArgumentOk() throws Exception + { + // Create a command line parser for a formatted free argument. + CommandLineParser parser = + new CommandLineParser(new String[][] + { + { "1", "Test Free Argument.", "test", null, "^test$" } + }); + + // Parse a command line with this argument set correctly. + Properties testProps = parser.parseCommandLine(new String[] { "test" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The first free argument was not equal to \"test\" but was: " + testProps.get("1"), + "test".equals(testProps.get("1"))); + } + + /** Check that parsing an option with specific argument format fails on bad argument. */ + public void testParseFormattedOptionArgumentFailsBadArgument() throws Exception + { + // Create a command line parser for a formatted option. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Option.", "test", null, "^test$" } + }); + + // Check that the parser signals an error for a badly formatted argument. + boolean testPassed = false; + + try + { + // Parse a command line with this option set incorrectly. + Properties testProps = parser.parseCommandLine(new String[] { "-t", "fail" }); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + assertTrue("IllegalArgumentException not thrown when a badly formatted argument was set.", testPassed); + } + + /** Check that parsing an option with specific argument format works ok. */ + public void testParseFormattedOptionArgumentOk() throws Exception + { + // Create a command line parser for a formatted option. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Option.", "test", null, "^test$" } + }); + + // Parse a command line with this option set correctly. + Properties testProps = parser.parseCommandLine(new String[] { "-t", "test" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), + "test".equals(testProps.get("t"))); + } + + /** Check that parsing a free argument works ok. */ + public void testParseFreeArgumentOk() throws Exception + { + // Create a command line parser for a free argument. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "1", "Test Free Argument.", "test" } + }); + + // Parse a command line with this argument set. + Properties testProps = parser.parseCommandLine(new String[] { "test" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The first free argument was not equal to \"test\" but was: " + testProps.get("1"), + "test".equals(testProps.get("1"))); + } + + /** Check that parsing a mandatory option works ok. */ + public void testParseMandatoryOptionOk() throws Exception + { + // Create a command line parser for a mandatory option. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Option.", "test", "true" } + }); + + // Parse a command line with this option set correctly. + Properties testProps = parser.parseCommandLine(new String[] { "-t", "test" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), + "test".equals(testProps.get("t"))); + } + + /** Check that parsing a mandatory free argument works ok. */ + public void testParseMandatoryFreeArgumentOk() throws Exception + { + // Create a command line parser for a mandatory free argument. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "1", "Test Option.", "test", "true" } + }); + + // Parse a command line with this argument set. + Properties testProps = parser.parseCommandLine(new String[] { "test" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The first free argument was not equal to \"test\" but was: " + testProps.get("1"), + "test".equals(testProps.get("1"))); + } + + /** Check that parsing a mandatory free argument fails when no argument is specified. */ + public void testParseManadatoryFreeArgumentFailsNoArgument() throws Exception + { + // Create a command line parser for a mandatory free argument. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "1", "Test Option.", "test", "true" } + }); + + // Check that parsing fails when this mandatory free argument is missing. + boolean testPassed = false; + + try + { + // Parse a command line with this free argument not set. + Properties testProps = parser.parseCommandLine(new String[] {}); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("IllegalArgumentException not thrown for a missing mandatory option.", testPassed); + } + + /** Check that parsing a mandatory option fails when no option is set. */ + public void testParseMandatoryFailsNoOption() throws Exception + { + // Create a command line parser for a mandatory option. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Option.", "test", "true" } + }); + + // Check that parsing fails when this mandatory option is missing. + boolean testPassed = false; + + try + { + // Parse a command line with this option not set. + Properties testProps = parser.parseCommandLine(new String[] {}); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("IllegalArgumentException not thrown for a missing mandatory option.", testPassed); + } + + /** Check that parsing an option with no space between it and its argument works ok. */ + public void testParseOptionWithNoSpaceOk() throws Exception + { + // Create a command line parser for an option. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Option.", "test" } + }); + + // Parse a command line with this option set with no space. + Properties testProps = parser.parseCommandLine(new String[] { "-ttest" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), + "test".equals(testProps.get("t"))); + } + + /** Check that parsing an option with a space between it and its argument works ok. */ + public void testParseOptionWithSpaceOk() throws Exception + { + // Create a command line parser for an option. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Option.", "test" } + }); + + // Parse a command line with this option set with a space. + Properties testProps = parser.parseCommandLine(new String[] { "-t", "test" }); + + // Check that the resultant properties contains the correctly parsed option. + assertTrue("The test option was not equal to \"test\" but was: " + testProps.get("t"), + "test".equals(testProps.get("t"))); + } + + /** Check that parsing a single flag works ok. */ + public void testParseSingleFlagOk() throws Exception + { + // Create a command line parser for a single flag. + CommandLineParser parser = new CommandLineParser(new String[][] + { + { "t", "Test Flag." } + }); + + // Parse a command line with the single flag set. + Properties testProps = parser.parseCommandLine(new String[] { "-t" }); + + // Check that the flag is set in the parsed properties. + assertTrue("The t flag was not \"true\", it was: " + testProps.get("t"), "true".equals(testProps.get("t"))); + + // Reset the parser. + parser.reset(); + + // Parse a command line with the single flag not set. + testProps = parser.parseCommandLine(new String[] {}); + + // Check that the flag is cleared in the parsed properties. + assertTrue("The t flag was not \"false\", it was: " + testProps.get("t"), "false".equals(testProps.get("t"))); + } + + /** Check that parsing an unknown option works when unknowns not errors. */ + public void testParseUnknownOptionOk() throws Exception + { + // Create a command line parser for no flags or options + CommandLineParser parser = new CommandLineParser(new String[][] {}); + + // Check that parsing does not fail on an unknown flag. + try + { + parser.parseCommandLine(new String[] { "-t" }); + } + catch (IllegalArgumentException e) + { + fail("The parser threw an IllegalArgumentException on an unknown flag when errors on unkowns is off."); + } + } + + /** Check that parsing an unknown flag fails when unknowns are to be reported as errors. */ + public void testParseUnknownFlagFailsWhenUnknownsAreErrors() throws Exception + { + // Create a command line parser for no flags or options + CommandLineParser parser = new CommandLineParser(new String[][] {}); + + // Turn on fail on unknowns mode. + parser.setErrorsOnUnknowns(true); + + // Check that parsing fails on an unknown flag. + boolean testPassed = false; + + try + { + parser.parseCommandLine(new String[] { "-t" }); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + assertTrue("IllegalArgumentException not thrown for an unknown flag when errors on unknowns mode is on.", + testPassed); + } + + /** Check that parsing an unknown option fails when unknowns are to be reported as errors. */ + public void testParseUnknownOptionFailsWhenUnknownsAreErrors() throws Exception + { + // Create a command line parser for no flags or options + CommandLineParser parser = new CommandLineParser(new String[][] {}); + + // Turn on fail on unknowns mode. + parser.setErrorsOnUnknowns(true); + + // Check that parsing fails on an unknown flag. + boolean testPassed = false; + + try + { + parser.parseCommandLine(new String[] { "-t", "test" }); + } + catch (IllegalArgumentException e) + { + testPassed = true; + } + + assertTrue("IllegalArgumentException not thrown for an unknown option when errors on unknowns mode is on.", + testPassed); + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java new file mode 100644 index 0000000000..7eba5f092e --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java @@ -0,0 +1,612 @@ +/* + * + * 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.util; + +import junit.framework.TestCase; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class FileUtilsTest extends TestCase +{ + private static final String COPY = "-Copy"; + private static final String SUB = "-Sub"; + + /** + * Additional test for the copy method. + * Ensures that the directory count did increase by more than 1 after the copy. + */ + public void testCopyFile() + { + final String TEST_DATA = "FileUtilsTest-testCopy-TestDataTestDataTestDataTestDataTestDataTestData"; + String fileName = "FileUtilsTest-testCopy"; + String fileNameCopy = fileName + COPY; + + File[] beforeCopyFileList = null; + + //Create initial file + File test = createTestFile(fileName, TEST_DATA); + + try + { + //Check number of files before copy + beforeCopyFileList = test.getAbsoluteFile().getParentFile().listFiles(); + int beforeCopy = beforeCopyFileList.length; + + //Perform Copy + File destination = new File(fileNameCopy); + FileUtils.copy(test, destination); + //Ensure the JVM cleans up if cleanup failues + destination.deleteOnExit(); + + //Retrieve counts after copy + int afterCopy = test.getAbsoluteFile().getParentFile().listFiles().length; + + int afterCopyFromCopy = new File(fileNameCopy).getAbsoluteFile().getParentFile().listFiles().length; + + // Validate the copy counts + assertEquals("The file listing from the original and the copy differ in length.", afterCopy, afterCopyFromCopy); + assertEquals("The number of files did not increase.", beforeCopy + 1, afterCopy); + assertEquals("The number of files did not increase.", beforeCopy + 1, afterCopyFromCopy); + + //Validate copy + // Load content + String copiedFileContent = FileUtils.readFileAsString(fileNameCopy); + assertEquals(TEST_DATA, copiedFileContent); + } + finally // Ensure clean + { + //Clean up + assertTrue("Unable to cleanup", FileUtils.deleteFile(fileNameCopy)); + + //Check file list after cleanup + File[] afterCleanup = new File(test.getAbsoluteFile().getParent()).listFiles(); + checkFileLists(beforeCopyFileList, afterCleanup); + + //Remove original file + assertTrue("Unable to cleanup", test.delete()); + } + } + + /** + * Create and Copy the following structure: + * + * testDirectory --+ + * +-- testSubDirectory --+ + * +-- testSubFile + * +-- File + * + * to testDirectory-Copy + * + * Validate that the file count in the copy is correct and contents of the copied files is correct. + */ + public void testCopyRecursive() + { + final String TEST_DATA = "FileUtilsTest-testDirectoryCopy-TestDataTestDataTestDataTestDataTestDataTestData"; + String fileName = "FileUtilsTest-testCopy"; + String TEST_DIR = "testDirectoryCopy"; + + //Create Initial Structure + File testDir = new File(TEST_DIR); + + //Check number of files before copy + File[] beforeCopyFileList = testDir.getAbsoluteFile().getParentFile().listFiles(); + + try + { + //Create Directories + assertTrue("Test directory already exists cannot test.", !testDir.exists()); + + if (!testDir.mkdir()) + { + fail("Unable to make test Directory"); + } + + File testSubDir = new File(TEST_DIR + File.separator + TEST_DIR + SUB); + if (!testSubDir.mkdir()) + { + fail("Unable to make test sub Directory"); + } + + //Create Files + createTestFile(testDir.toString() + File.separator + fileName, TEST_DATA); + createTestFile(testSubDir.toString() + File.separator + fileName + SUB, TEST_DATA); + + //Ensure the JVM cleans up if cleanup failues + testSubDir.deleteOnExit(); + testDir.deleteOnExit(); + + //Perform Copy + File copyDir = new File(testDir.toString() + COPY); + try + { + FileUtils.copyRecursive(testDir, copyDir); + } + catch (FileNotFoundException e) + { + fail(e.getMessage()); + } + catch (FileUtils.UnableToCopyException e) + { + fail(e.getMessage()); + } + + //Validate Copy + assertEquals("Copied directory should only have one file and one directory in it.", 2, copyDir.listFiles().length); + + //Validate Copy File Contents + String copiedFileContent = FileUtils.readFileAsString(copyDir.toString() + File.separator + fileName); + assertEquals(TEST_DATA, copiedFileContent); + + //Validate Name of Sub Directory + assertTrue("Expected subdirectory is not a directory", new File(copyDir.toString() + File.separator + TEST_DIR + SUB).isDirectory()); + + //Assert that it contains only one item + assertEquals("Copied sub directory should only have one directory in it.", 1, new File(copyDir.toString() + File.separator + TEST_DIR + SUB).listFiles().length); + + //Validate content of Sub file + copiedFileContent = FileUtils.readFileAsString(copyDir.toString() + File.separator + TEST_DIR + SUB + File.separator + fileName + SUB); + assertEquals(TEST_DATA, copiedFileContent); + } + finally + { + //Clean up source and copy directory. + assertTrue("Unable to cleanup", FileUtils.delete(testDir, true)); + assertTrue("Unable to cleanup", FileUtils.delete(new File(TEST_DIR + COPY), true)); + + //Check file list after cleanup + File[] afterCleanup = testDir.getAbsoluteFile().getParentFile().listFiles(); + checkFileLists(beforeCopyFileList, afterCleanup); + } + } + + /** + * Helper method to create a test file with a string content + * + * @param fileName The fileName to use in the creation + * @param test_data The data to store in the file + * + * @return The File reference + */ + private File createTestFile(String fileName, String test_data) + { + File test = new File(fileName); + + try + { + test.createNewFile(); + //Ensure the JVM cleans up if cleanup failues + test.deleteOnExit(); + } + catch (IOException e) + { + fail(e.getMessage()); + } + + BufferedWriter writer = null; + try + { + writer = new BufferedWriter(new FileWriter(test)); + try + { + writer.write(test_data); + } + catch (IOException e) + { + fail(e.getMessage()); + } + } + catch (IOException e) + { + fail(e.getMessage()); + } + finally + { + try + { + if (writer != null) + { + writer.close(); + } + } + catch (IOException e) + { + fail(e.getMessage()); + } + } + + return test; + } + + /** Test that deleteFile only deletes the specified file */ + public void testDeleteFile() + { + File test = new File("FileUtilsTest-testDelete"); + //Record file count in parent directory to check it is not changed by delete + String path = test.getAbsolutePath(); + File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountBefore = filesBefore.length; + + try + { + test.createNewFile(); + //Ensure the JVM cleans up if cleanup failues + test.deleteOnExit(); + } + catch (IOException e) + { + fail(e.getMessage()); + } + + assertTrue("File does not exists", test.exists()); + assertTrue("File is not a file", test.isFile()); + + //Check that file creation can be seen on disk + int fileCountCreated = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles().length; + assertEquals("File creation was no registered", fileCountBefore + 1, fileCountCreated); + + //Perform Delete + assertTrue("Unable to cleanup", FileUtils.deleteFile("FileUtilsTest-testDelete")); + + assertTrue("File exists after delete", !test.exists()); + + //Check that after deletion the file count is now accurate + File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountAfter = filesAfter.length; + assertEquals("File creation was no registered", fileCountBefore, fileCountAfter); + + checkFileLists(filesBefore, filesAfter); + } + + public void testDeleteNonExistentFile() + { + File test = new File("FileUtilsTest-testDelete-" + System.currentTimeMillis()); + + assertTrue("File exists", !test.exists()); + assertFalse("File is a directory", test.isDirectory()); + + assertTrue("Delete Succeeded ", !FileUtils.delete(test, true)); + } + + public void testDeleteNull() + { + try + { + FileUtils.delete(null, true); + fail("Delete with null value should throw NPE."); + } + catch (NullPointerException npe) + { + // expected path + } + } + + /** + * Given two lists of File arrays ensure they are the same length and all entries in Before are in After + * + * @param filesBefore File[] + * @param filesAfter File[] + */ + private void checkFileLists(File[] filesBefore, File[] filesAfter) + { + assertNotNull("Before file list cannot be null", filesBefore); + assertNotNull("After file list cannot be null", filesAfter); + + assertEquals("File lists are unequal", filesBefore.length, filesAfter.length); + + for (File fileBefore : filesBefore) + { + boolean found = false; + + for (File fileAfter : filesAfter) + { + if (fileBefore.getAbsolutePath().equals(fileAfter.getAbsolutePath())) + { + found = true; + break; + } + } + + assertTrue("File'" + fileBefore.getName() + "' was not in directory afterwards", found); + } + } + + public void testNonRecursiveNonEmptyDirectoryDeleteFails() + { + String directoryName = "FileUtilsTest-testRecursiveDelete"; + File test = new File(directoryName); + + //Record file count in parent directory to check it is not changed by delete + String path = test.getAbsolutePath(); + File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountBefore = filesBefore.length; + + assertTrue("Directory exists", !test.exists()); + + test.mkdir(); + + //Create a file in the directory + String fileName = test.getAbsolutePath() + File.separatorChar + "testFile"; + File subFile = new File(fileName); + try + { + subFile.createNewFile(); + //Ensure the JVM cleans up if cleanup failues + subFile.deleteOnExit(); + } + catch (IOException e) + { + fail(e.getMessage()); + } + //Ensure the JVM cleans up if cleanup failues + // This must be after the subFile as the directory must be empty before + // the delete is performed + test.deleteOnExit(); + + //Try and delete the non-empty directory + assertFalse("Non Empty Directory was successfully deleted.", FileUtils.deleteDirectory(directoryName)); + + //Check directory is still there + assertTrue("Directory was deleted.", test.exists()); + + // Clean up + assertTrue("Unable to cleanup", FileUtils.delete(test, true)); + + //Check that after deletion the file count is now accurate + File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountAfter = filesAfter.length; + assertEquals("File creation was no registered", fileCountBefore, fileCountAfter); + + checkFileLists(filesBefore, filesAfter); + } + + /** Test that an empty directory can be deleted with deleteDirectory */ + public void testEmptyDirectoryDelete() + { + String directoryName = "FileUtilsTest-testRecursiveDelete"; + File test = new File(directoryName); + + //Record file count in parent directory to check it is not changed by delete + String path = test.getAbsolutePath(); + File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountBefore = filesBefore.length; + + assertTrue("Directory exists", !test.exists()); + + test.mkdir(); + //Ensure the JVM cleans up if cleanup failues + test.deleteOnExit(); + + //Try and delete the empty directory + assertTrue("Non Empty Directory was successfully deleted.", FileUtils.deleteDirectory(directoryName)); + + //Check directory is still there + assertTrue("Directory was deleted.", !test.exists()); + + //Check that after deletion the file count is now accurate + File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountAfter = filesAfter.length; + assertEquals("File creation was no registered", fileCountBefore, fileCountAfter); + + checkFileLists(filesBefore, filesAfter); + + } + + /** Test that deleteDirectory on a non empty directory to complete */ + public void testNonEmptyDirectoryDelete() + { + String directoryName = "FileUtilsTest-testRecursiveDelete"; + File test = new File(directoryName); + + assertTrue("Directory exists", !test.exists()); + + //Record file count in parent directory to check it is not changed by delete + String path = test.getAbsolutePath(); + File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountBefore = filesBefore.length; + + test.mkdir(); + + //Create a file in the directory + String fileName = test.getAbsolutePath() + File.separatorChar + "testFile"; + File subFile = new File(fileName); + try + { + subFile.createNewFile(); + //Ensure the JVM cleans up if cleanup failues + subFile.deleteOnExit(); + } + catch (IOException e) + { + fail(e.getMessage()); + } + + // Ensure the JVM cleans up if cleanup failues + // This must be after the subFile as the directory must be empty before + // the delete is performed + test.deleteOnExit(); + + //Try and delete the non-empty directory non-recursively + assertFalse("Non Empty Directory was successfully deleted.", FileUtils.delete(test, false)); + + //Check directory is still there + assertTrue("Directory was deleted.", test.exists()); + + // Clean up + assertTrue("Unable to cleanup", FileUtils.delete(test, true)); + + //Check that after deletion the file count is now accurate + File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountAfter = filesAfter.length; + assertEquals("File creation was no registered", fileCountBefore, fileCountAfter); + + checkFileLists(filesBefore, filesAfter); + + } + + /** Test that a recursive delete successeds */ + public void testRecursiveDelete() + { + String directoryName = "FileUtilsTest-testRecursiveDelete"; + File test = new File(directoryName); + + assertTrue("Directory exists", !test.exists()); + + //Record file count in parent directory to check it is not changed by delete + String path = test.getAbsolutePath(); + File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountBefore = filesBefore.length; + + test.mkdir(); + + createSubDir(directoryName, 2, 4); + + //Ensure the JVM cleans up if cleanup failues + // This must be after the sub dir creation as the delete order is + // recorded and the directory must be empty to be deleted. + test.deleteOnExit(); + + assertFalse("Non recursive delete was able to directory", FileUtils.delete(test, false)); + + assertTrue("File does not exist after non recursive delete", test.exists()); + + assertTrue("Unable to cleanup", FileUtils.delete(test, true)); + + assertTrue("File exist after recursive delete", !test.exists()); + + //Check that after deletion the file count is now accurate + File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles(); + int fileCountAfter = filesAfter.length; + assertEquals("File creation was no registered", fileCountBefore, fileCountAfter); + + checkFileLists(filesBefore, filesAfter); + + } + + private void createSubDir(String path, int directories, int files) + { + File directory = new File(path); + + assertTrue("Directory" + path + " does not exists", directory.exists()); + + for (int dir = 0; dir < directories; dir++) + { + String subDirName = path + File.separatorChar + "sub" + dir; + File subDir = new File(subDirName); + + subDir.mkdir(); + + createSubDir(subDirName, directories - 1, files); + //Ensure the JVM cleans up if cleanup failues + // This must be after the sub dir creation as the delete order is + // recorded and the directory must be empty to be deleted. + subDir.deleteOnExit(); + } + + for (int file = 0; file < files; file++) + { + String subDirName = path + File.separatorChar + "file" + file; + File subFile = new File(subDirName); + try + { + subFile.createNewFile(); + //Ensure the JVM cleans up if cleanup failues + subFile.deleteOnExit(); + } + catch (IOException e) + { + fail(e.getMessage()); + } + } + } + + public static final String SEARCH_STRING = "testSearch"; + + /** + * Test searchFile(File file, String search) will find a match when it + * exists. + * + * @throws java.io.IOException if unable to perform test setup + */ + public void testSearchSucceed() throws IOException + { + File _logfile = File.createTempFile("FileUtilsTest-testSearchSucceed", ".out"); + + prepareFileForSearchTest(_logfile); + + List<String> results = FileUtils.searchFile(_logfile, SEARCH_STRING); + + assertNotNull("Null result set returned", results); + + assertEquals("Results do not contain expected count", 1, results.size()); + } + + /** + * Test searchFile(File file, String search) will not find a match when the + * test string does not exist. + * + * @throws java.io.IOException if unable to perform test setup + */ + public void testSearchFail() throws IOException + { + File _logfile = File.createTempFile("FileUtilsTest-testSearchFail", ".out"); + + prepareFileForSearchTest(_logfile); + + List<String> results = FileUtils.searchFile(_logfile, "Hello"); + + assertNotNull("Null result set returned", results); + + //Validate we only got one message + if (results.size() > 0) + { + System.err.println("Unexpected messages"); + + for (String msg : results) + { + System.err.println(msg); + } + } + + assertEquals("Results contains data when it was not expected", + 0, results.size()); + } + + /** + * Write the SEARCH_STRING in to the given file. + * + * @param logfile The file to write the SEARCH_STRING into + * + * @throws IOException if an error occurs + */ + private void prepareFileForSearchTest(File logfile) throws IOException + { + BufferedWriter writer = new BufferedWriter(new FileWriter(logfile)); + writer.append(SEARCH_STRING); + writer.flush(); + writer.close(); + } + +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/PropertyUtilsTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/PropertyUtilsTest.java new file mode 100644 index 0000000000..9fd18d461a --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/util/PropertyUtilsTest.java @@ -0,0 +1,48 @@ +/* + * + * 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.util; + +import org.apache.qpid.configuration.PropertyException; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.test.utils.QpidTestCase; + +public class PropertyUtilsTest extends QpidTestCase +{ + public void testSimpleExpansion() throws PropertyException + { + System.setProperty("banana", "fruity"); + String expandedProperty = PropertyUtils.replaceProperties("${banana}"); + assertEquals(expandedProperty, "fruity"); + } + + public void testDualExpansion() throws PropertyException + { + System.setProperty("banana", "fruity"); + System.setProperty("concrete", "horrible"); + String expandedProperty = PropertyUtils.replaceProperties("${banana}xyz${concrete}"); + assertEquals(expandedProperty, "fruityxyzhorrible"); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(PropertyUtilsTest.class); + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/SerialTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/SerialTest.java new file mode 100644 index 0000000000..b2578563e0 --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/util/SerialTest.java @@ -0,0 +1,82 @@ +package org.apache.qpid.util; +/* + * + * 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 junit.framework.TestCase; + +import java.util.Random; + +import org.apache.qpid.SerialException; + +/** + *Junit tests for the Serial class + */ +public class SerialTest extends TestCase +{ + + /** + * Test the key boundaries where wraparound occurs. + */ + public void testBoundaries() + { + assertTrue(Serial.gt(1, 0)); + assertTrue(Serial.lt(0, 1)); + + assertTrue(Serial.gt(Integer.MAX_VALUE+1, Integer.MAX_VALUE)); + assertTrue(Serial.lt(Integer.MAX_VALUE, Integer.MAX_VALUE+1)); + + assertTrue(Serial.gt(0xFFFFFFFF + 1, 0xFFFFFFFF)); + assertTrue(Serial.lt(0xFFFFFFFF, 0xFFFFFFFF + 1)); + } + + /** + * Test the first Corollary of RFC 1982 + * For any sequence number s and any integer n such that addition of n + * to s is well defined, (s + n) >= s. Further (s + n) == s only when + * n == 0, in all other defined cases, (s + n) > s. + */ + public void testCorollary1() + { + int wrapcount = 0; + + int s = 0; + + for (int i = 0; i < 67108664; i++) + { + for (int n = 1; n < 4096; n += 512) + { + assertTrue(Serial.gt(s+n, s)); + assertTrue(Serial.lt(s, s+n)); + } + + s += 1024; + + if (s == 0) + { + wrapcount += 1; + } + } + + assertTrue(wrapcount > 0); + } + +} |