/*
* Copyright 2009 Red Hat, Inc.
* Red Hat 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.hornetq.tests.integration.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicLong;
import junit.framework.Assert;
import org.hornetq.api.core.Message;
import org.hornetq.api.core.SimpleString;
import org.hornetq.api.core.client.ClientConsumer;
import org.hornetq.api.core.client.ClientMessage;
import org.hornetq.api.core.client.ClientProducer;
import org.hornetq.api.core.client.ClientSession;
import org.hornetq.api.core.client.ClientSessionFactory;
import org.hornetq.api.core.client.HornetQClient;
import org.hornetq.api.core.client.ServerLocator;
import org.hornetq.core.server.HornetQServer;
import org.hornetq.core.settings.impl.AddressSettings;
import org.hornetq.tests.util.UnitTestCase;
import org.hornetq.utils.DeflaterReader;
/**
* The test extends the LargeMessageTest and tests
* the functionality of option avoid-large-messages
*
* @author <a href="mailto:hgao@redhat.com">Howard Gao</a>
*/
public class LargeMessageAvoidLargeMessagesTest extends LargeMessageTest
{
public LargeMessageAvoidLargeMessagesTest()
{
isCompressedTest = true;
}
@Override
protected boolean isNetty()
{
return false;
}
@Override
protected ServerLocator createFactory(final boolean isNetty) throws Exception
{
ServerLocator locator1 = super.createFactory(isNetty);
locator1.setMinLargeMessageSize(10240);
locator1.setCompressLargeMessage(true);
return locator1;
}
//send some messages that can be compressed into regular size.
public void testSendRegularAfterCompression() throws Exception
{
HornetQServer server = createServer(true, isNetty());
try
{
server.start();
ClientSessionFactory sf = locator.createSessionFactory();
ClientSession session = sf.createSession(false, false, false);
session.createTemporaryQueue(LargeMessageTest.ADDRESS, LargeMessageTest.ADDRESS);
ClientProducer producer = session.createProducer(LargeMessageTest.ADDRESS);
int minLargeSize = locator.getMinLargeMessageSize();
TestLargeMessageInputStream input = new TestLargeMessageInputStream(minLargeSize);
this.adjustLargeCompression(true, input, 1024);
int num = 20;
for (int i = 0; i < num; i++)
{
ClientMessage clientFile = session.createMessage(true);
clientFile.setBodyInputStream(input.clone());
producer.send(clientFile);
}
session.commit();
session.start();
//no file should be in the dir as we send it as regular
validateNoFilesOnLargeDir();
ClientConsumer consumer = session.createConsumer(LargeMessageTest.ADDRESS);
for (int j = 0; j < num; j++)
{
ClientMessage msg1 = consumer.receive(1000);
Assert.assertNotNull(msg1);
for (int i = 0 ; i < input.getSize(); i++)
{
byte b = msg1.getBodyBuffer().readByte();
assertEquals("incorrect char ", input.getChar(i), b);
}
msg1.acknowledge();
}
session.commit();
consumer.close();
session.close();
}
finally
{
server.stop();
}
}
//send some messages that cannot be compressed into regular messages
public void testSendLargeAfterUnableToSendRegular() throws Exception
{
HornetQServer server = createServer(true, isNetty());
try
{
server.start();
//reduce the minLargeMessageSize to make the test faster
locator.setMinLargeMessageSize(5*1024);
ClientSessionFactory sf = locator.createSessionFactory();
ClientSession session = sf.createSession(false, false, false);
session.createTemporaryQueue(LargeMessageTest.ADDRESS, LargeMessageTest.ADDRESS);
ClientProducer producer = session.createProducer(LargeMessageTest.ADDRESS);
int minLargeSize = locator.getMinLargeMessageSize();
TestLargeMessageInputStream input = new TestLargeMessageInputStream(minLargeSize);
input.setSize(80 * minLargeSize);
this.adjustLargeCompression(false, input, 40 * minLargeSize);
int num = 10;
for (int i = 0; i < num; i++)
{
ClientMessage clientFile = session.createMessage(true);
clientFile.setBodyInputStream(input.clone());
producer.send(clientFile);
}
session.commit();
session.start();
//no file should be in the dir as we send it as regular
validateNoFilesOnLargeDir(num);
ClientConsumer consumer = session.createConsumer(LargeMessageTest.ADDRESS);
for (int j = 0; j < num; j++)
{
ClientMessage msg1 = consumer.receive(1000);
Assert.assertNotNull(msg1);
for (int i = 0 ; i < input.getSize(); i++)
{
byte b = msg1.getBodyBuffer().readByte();
assertEquals("incorrect char", input.getChar(i), b);
}
msg1.acknowledge();
}
session.commit();
consumer.close();
session.close();
}
finally
{
server.stop();
}
}
public void testMixedCompressionSendReceive() throws Exception
{
HornetQServer server = createServer(true, isNetty());
try
{
server.start();
ClientSessionFactory sf = locator.createSessionFactory();
ClientSession session = sf.createSession(false, false, false);
session.createTemporaryQueue(LargeMessageTest.ADDRESS, LargeMessageTest.ADDRESS);
ClientProducer producer = session.createProducer(LargeMessageTest.ADDRESS);
final int minLargeSize = locator.getMinLargeMessageSize();
TestLargeMessageInputStream regularInput = new TestLargeMessageInputStream(minLargeSize);
this.adjustLargeCompression(true, regularInput, 1024);
TestLargeMessageInputStream largeInput = new TestLargeMessageInputStream(minLargeSize);
largeInput.setSize(100 * minLargeSize);
this.adjustLargeCompression(false, largeInput, 50 * minLargeSize);
int num = 6;
for (int i = 0; i < num; i++)
{
ClientMessage clientFile = session.createMessage(true);
if (i%2 == 0)
{
clientFile.setBodyInputStream(regularInput.clone());
}
else
{
clientFile.setBodyInputStream(largeInput.clone());
}
producer.send(clientFile);
}
session.commit();
session.start();
//half the messages are sent as large
validateNoFilesOnLargeDir(num/2);
ClientConsumer consumer = session.createConsumer(LargeMessageTest.ADDRESS);
for (int j = 0; j < num; j++)
{
ClientMessage msg1 = consumer.receive(1000);
Assert.assertNotNull(msg1);
if (j%2 == 0)
{
for (int i = 0 ; i < regularInput.getSize(); i++)
{
byte b = msg1.getBodyBuffer().readByte();
assertEquals("incorrect char ", regularInput.getChar(i), b);
}
}
else
{
for (int i = 0; i < largeInput.getSize(); i++)
{
byte b = msg1.getBodyBuffer().readByte();
assertEquals("incorrect char ", largeInput.getChar(i), b);
}
}
msg1.acknowledge();
}
session.commit();
consumer.close();
session.close();
}
finally
{
server.stop();
}
}
private void adjustLargeCompression(boolean regular, TestLargeMessageInputStream stream, int step) throws IOException
{
int absoluteStep = Math.abs(step);
while (true)
{
DeflaterReader compressor = new DeflaterReader(stream, new AtomicLong());
try
{
byte[] buffer = new byte[1048 * 50];
int totalCompressed = 0;
int n = compressor.read(buffer);
while (n != -1)
{
totalCompressed += n;
n = compressor.read(buffer);
}
// check compressed size
if (regular && (totalCompressed < stream.getMinLarge()))
{
// ok it can be sent as regular
stream.resetAdjust(0);
break;
}
else if ((!regular) && (totalCompressed > stream.getMinLarge()))
{
// now it cannot be sent as regular
stream.resetAdjust(0);
break;
}
else
{
stream.resetAdjust(regular ? -absoluteStep : absoluteStep);
}
}
finally
{
compressor.close();
}
}
}
private static class TestLargeMessageInputStream extends InputStream
{
private final int minLarge;
private int size;
private int pos;
public TestLargeMessageInputStream(int minLarge)
{
pos = 0;
this.minLarge = minLarge;
this.size = minLarge + 1024;
}
public int getChar(int index)
{
return 'A' + index % 26;
}
public void setSize(int size)
{
this.size = size;
}
public TestLargeMessageInputStream(TestLargeMessageInputStream other)
{
this.minLarge = other.minLarge;
this.size = other.size;
this.pos = other.pos;
}
public int getSize()
{
return size;
}
public int getMinLarge()
{
return this.minLarge;
}
@Override
public int read() throws IOException
{
if (pos == size) return -1;
pos++;
return getChar(pos - 1);
}
public void resetAdjust(int step)
{
size += step;
if (size <= minLarge)
{
throw new IllegalStateException("Couldn't adjust anymore, size smaller than minLarge " + minLarge);
}
pos = 0;
}
public TestLargeMessageInputStream clone()
{
return new TestLargeMessageInputStream(this);
}
}
//this test won't leave any large messages in the large-messages dir
//because after compression, the messages are regulars at server.
@Override
public void testDLALargeMessage() throws Exception
{
final int messageSize = (int) (3.5 * HornetQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
ClientSession session = null;
HornetQServer server = createServer(true, isNetty());
server.start();
ClientSessionFactory sf = locator.createSessionFactory();
session = sf.createSession(false, false, false);
session.createQueue(LargeMessageTest.ADDRESS, LargeMessageTest.ADDRESS,
true);
session.createQueue(LargeMessageTest.ADDRESS,
LargeMessageTest.ADDRESS.concat("-2"), true);
SimpleString ADDRESS_DLA = LargeMessageTest.ADDRESS.concat("-dla");
AddressSettings addressSettings = new AddressSettings();
addressSettings.setDeadLetterAddress(ADDRESS_DLA);
addressSettings.setMaxDeliveryAttempts(1);
server.getAddressSettingsRepository().addMatch("*", addressSettings);
session.createQueue(ADDRESS_DLA, ADDRESS_DLA, true);
ClientProducer producer = session
.createProducer(LargeMessageTest.ADDRESS);
Message clientFile = createLargeClientMessage(session, messageSize, true);
producer.send(clientFile);
session.commit();
session.start();
ClientConsumer consumer = session.createConsumer(ADDRESS_DLA);
ClientConsumer consumerRollback = session
.createConsumer(LargeMessageTest.ADDRESS);
ClientMessage msg1 = consumerRollback.receive(1000);
Assert.assertNotNull(msg1);
msg1.acknowledge();
session.rollback();
consumerRollback.close();
msg1 = consumer.receive(10000);
Assert.assertNotNull(msg1);
for (int i = 0; i < messageSize; i++)
{
Assert.assertEquals(UnitTestCase.getSamplebyte(i), msg1
.getBodyBuffer().readByte());
}
session.close();
server.stop();
server = createServer(true, isNetty());
server.start();
sf = locator.createSessionFactory();
session = sf.createSession(false, false, false);
session.start();
consumer = session.createConsumer(ADDRESS_DLA);
msg1 = consumer.receive(10000);
Assert.assertNotNull(msg1);
for (int i = 0; i < messageSize; i++)
{
Assert.assertEquals(UnitTestCase.getSamplebyte(i), msg1
.getBodyBuffer().readByte());
}
msg1.acknowledge();
session.commit();
//large message becomes a regular at server.
validateNoFilesOnLargeDir(0);
consumer = session.createConsumer(LargeMessageTest.ADDRESS.concat("-2"));
msg1 = consumer.receive(10000);
Assert.assertNotNull(msg1);
for (int i = 0; i < messageSize; i++)
{
Assert.assertEquals(UnitTestCase.getSamplebyte(i), msg1
.getBodyBuffer().readByte());
}
msg1.acknowledge();
session.commit();
session.close();
validateNoFilesOnLargeDir();
server.stop();
}
@Override
public void testSendServerMessage() throws Exception
{
// doesn't make sense as compressed
}
}