blob: ecfa8d2fdbea607d5edc67b6915b97668edfcdb9 [file] [log] [blame]
/*
*
* 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.server.protocol.v0_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Test;
import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
import org.apache.qpid.test.utils.UnitTestBase;
public class FieldTableTest extends UnitTestBase
{
/**
* 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
*/
@Test
public void testBoolean()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", true));
assertTrue(table1.containsKey("value"));
assertEquals(true, table1.get("value"));
}
/**
* 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
*/
@Test
public void testByte()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", Byte.MAX_VALUE));
assertTrue(table1.containsKey("value"));
assertEquals(Byte.MAX_VALUE, table1.get("value"));
}
/**
* 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
*/
@Test
public void testShort()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", Short.MAX_VALUE));
assertTrue(table1.containsKey("value"));
assertEquals(Short.MAX_VALUE, table1.get("value"));
}
/**
* 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
*/
@Test
public void testChar()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", 'c'));
assertTrue(table1.containsKey("value"));
assertEquals('c', table1.get("value"));
}
/**
* 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
*/
@Test
public void testDouble()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", Double.MAX_VALUE));
assertTrue(table1.containsKey("value"));
assertEquals(Double.MAX_VALUE, table1.get("value"));
}
/**
* 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
*/
@Test
public void testFloat()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", Float.MAX_VALUE));
assertTrue(table1.containsKey("value"));
assertEquals(Float.MAX_VALUE, table1.get("value"));
}
/**
* 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
*/
@Test
public void testInt()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", Integer.MAX_VALUE));
assertTrue(table1.containsKey("value"));
assertEquals(Integer.MAX_VALUE, table1.get("value"));
}
/**
* 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
*/
@Test
public void testLong()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", Long.MAX_VALUE));
assertTrue(table1.containsKey("value"));
assertEquals(Long.MAX_VALUE, table1.get("value"));
}
/**
* 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
*/
@Test
public void testBytes()
{
byte[] bytes = { 99, 98, 97, 96, 95 };
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", bytes));
assertTrue(table1.containsKey("value"));
assertBytesEqual(bytes, (byte[])table1.get("value"));
}
/**
* 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
*/
@Test
public void testString()
{
FieldTable table1 = FieldTableFactory.createFieldTable(Collections.singletonMap("value", "Hello"));
assertTrue(table1.containsKey("value"));
assertEquals("Hello", table1.get("value"));
}
/** Check that a nested field table parameter correctly encodes and decodes to a byte buffer. */
@Test
public void testNestedFieldTable() throws AMQFrameDecodingException
{
byte[] testBytes = new byte[] { 0, 1, 2, 3, 4, 5 };
Map<String, Object> innerTable = new LinkedHashMap<>();
// Put some stuff in the inner table.
innerTable.put("bool", true);
innerTable.put("byte", Byte.MAX_VALUE);
innerTable.put("bytes", testBytes);
innerTable.put("char", 'c');
innerTable.put("double", Double.MAX_VALUE);
innerTable.put("float", Float.MAX_VALUE);
innerTable.put("int", Integer.MAX_VALUE);
innerTable.put("long", Long.MAX_VALUE);
innerTable.put("short", Short.MAX_VALUE);
innerTable.put("string", "hello");
innerTable.put("null-string", null);
innerTable.put("field-array",Arrays.asList("hello", 42, Collections.emptyList()));
// Put the inner table in the outer one.
FieldTable outerTable = FieldTableFactory.createFieldTable(Collections.singletonMap("innerTable",
FieldTableFactory.createFieldTable(innerTable)));
// Write the outer table into the buffer.
QpidByteBuffer buf = QpidByteBuffer.allocate(EncodingUtils.encodedFieldTableLength(outerTable));
outerTable.writeToBuffer(buf);
buf.flip();
// Extract the table back from the buffer again.
FieldTable extractedOuterTable = EncodingUtils.readFieldTable(buf);
assertNotNull("Unexpected outer table", extractedOuterTable);
FieldTable extractedTable = (FieldTable)extractedOuterTable.get("innerTable");
assertEquals(Boolean.TRUE, extractedTable.get("bool"));
assertEquals(Byte.MAX_VALUE, extractedTable.get("byte"));
assertBytesEqual(testBytes, (byte[])extractedTable.get("bytes"));
assertEquals('c', extractedTable.get("char"));
assertEquals(Double.MAX_VALUE, extractedTable.get("double"));
assertEquals(Float.MAX_VALUE, extractedTable.get("float"));
assertEquals(Integer.MAX_VALUE, extractedTable.get("int"));
assertEquals(Long.MAX_VALUE, extractedTable.get("long"));
assertEquals(Short.MAX_VALUE, extractedTable.get("short"));
assertEquals("hello", extractedTable.get("string"));
assertNull(extractedTable.get("null-string"));
Collection fieldArray = (Collection) extractedTable.get("field-array");
assertEquals(3, fieldArray.size());
Iterator iter = fieldArray.iterator();
assertEquals("hello", iter.next());
assertEquals(42, iter.next());
assertTrue(((Collection)iter.next()).isEmpty());
}
public void testUnsupportedObject()
{
try
{
FieldTableFactory.createFieldTable(Collections.singletonMap("value", 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());
}
}
@Test
public void testValues() throws Exception
{
Map<String, Object> map = new LinkedHashMap<>();
map.put("bool", true);
map.put("byte", Byte.MAX_VALUE);
byte[] bytes = { 99, 98, 97, 96, 95 };
map.put("bytes", bytes);
map.put("char", 'c');
map.put("double", Double.MAX_VALUE);
map.put("float", Float.MAX_VALUE);
map.put("int", Integer.MAX_VALUE);
map.put("long", Long.MAX_VALUE);
map.put("short", Short.MAX_VALUE);
map.put("string", "Hello");
map.put("null-string", null);
map.put("object-bool", true);
map.put("object-byte", Byte.MAX_VALUE);
map.put("object-bytes", bytes);
map.put("object-char", 'c');
map.put("object-double", Double.MAX_VALUE);
map.put("object-float", Float.MAX_VALUE);
map.put("object-int", Integer.MAX_VALUE);
map.put("object-long", Long.MAX_VALUE);
map.put("object-short", Short.MAX_VALUE);
map.put("object-string", "Hello");
FieldTable mapTable = FieldTableFactory.createFieldTable(map);
QpidByteBuffer buf = QpidByteBuffer.allocate(EncodingUtils.encodedFieldTableLength(mapTable));
mapTable.writeToBuffer(buf);
buf.flip();
FieldTable table = EncodingUtils.readFieldTable(buf);
assertNotNull(table);
assertEquals(Boolean.TRUE, table.get("bool"));
assertEquals(Byte.MAX_VALUE, table.get("byte"));
assertBytesEqual(bytes, (byte[])table.get("bytes"));
assertEquals('c', table.get("char"));
assertEquals(Double.MAX_VALUE, table.get("double"));
assertEquals(Float.MAX_VALUE, table.get("float"));
assertEquals(Integer.MAX_VALUE, table.get("int"));
assertEquals(Long.MAX_VALUE, table.get("long"));
assertEquals(Short.MAX_VALUE, table.get("short"));
assertEquals("Hello", table.get("string"));
assertNull(table.get("null-string"));
assertEquals(true, table.get("object-bool"));
assertEquals(Byte.MAX_VALUE, table.get("object-byte"));
assertBytesEqual(bytes, (byte[]) table.get("object-bytes"));
assertEquals('c', table.get("object-char"));
assertEquals(Double.MAX_VALUE, table.get("object-double"));
assertEquals(Float.MAX_VALUE, table.get("object-float"));
assertEquals(Integer.MAX_VALUE, table.get("object-int"));
assertEquals(Long.MAX_VALUE, table.get("object-long"));
assertEquals(Short.MAX_VALUE, table.get("object-short"));
assertEquals("Hello", table.get("object-string"));
}
@Test
public void testWriteBuffer()
{
byte[] bytes = { 99, 98, 97, 96, 95 };
Map<String, Object> map = new LinkedHashMap<>();
map.put("bool", true);
map.put("byte", Byte.MAX_VALUE);
map.put("bytes", bytes);
map.put("char", 'c');
map.put("int", Integer.MAX_VALUE);
map.put("long", Long.MAX_VALUE);
map.put("double", Double.MAX_VALUE);
map.put("float", Float.MAX_VALUE);
map.put("short", Short.MAX_VALUE);
map.put("string", "hello");
map.put("null-string", null);
FieldTable table = FieldTableFactory.createFieldTable(map);
QpidByteBuffer buf = QpidByteBuffer.allocate((int) table.getEncodedSize() + 4);
table.writeToBuffer(buf);
buf.flip();
long length = buf.getInt() & 0xFFFFFFFFL;
QpidByteBuffer bufSlice = buf.slice();
bufSlice.limit((int)length);
FieldTable table2 = FieldTableFactory.createFieldTable(buf);
assertNotNull(table2);
assertEquals(true, table2.get("bool"));
assertEquals(Byte.MAX_VALUE, table2.get("byte"));
assertBytesEqual(bytes, (byte[])table2.get("bytes"));
assertEquals('c', table2.get("char"));
assertEquals(Double.MAX_VALUE, table2.get("double"));
assertEquals(Float.MAX_VALUE, table2.get("float"));
assertEquals(Integer.MAX_VALUE, table2.get("int"));
assertEquals(Long.MAX_VALUE, table2.get("long"));
assertEquals(Short.MAX_VALUE, table2.get("short"));
assertEquals("hello", table2.get("string"));
assertNull(table2.get("null-string"));
buf.dispose();
bufSlice.dispose();
table.dispose();
table2.dispose();
}
@Test
public void testEncodingSize()
{
Map<String, Object> result = new LinkedHashMap<>();
int size = 0;
result.put("boolean", true);
size += 1 + EncodingUtils.encodedShortStringLength("boolean") + EncodingUtils.encodedBooleanLength();
result.put("byte", Byte.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("byte") + EncodingUtils.encodedByteLength();
byte[] _bytes = { 99, 98, 97, 96, 95 };
result.put("bytes", _bytes);
size += 1 + EncodingUtils.encodedShortStringLength("bytes") + 4 + _bytes.length;
result.put("char", 'c');
size += 1 + EncodingUtils.encodedShortStringLength("char") + EncodingUtils.encodedCharLength();
result.put("double", Double.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("double") + EncodingUtils.encodedDoubleLength();
result.put("float", Float.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("float") + EncodingUtils.encodedFloatLength();
result.put("int", Integer.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("int") + EncodingUtils.encodedIntegerLength();
result.put("long", Long.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("long") + EncodingUtils.encodedLongLength();
result.put("short", Short.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("short") + EncodingUtils.encodedShortLength();
result.put("result", "Hello");
size += 1 + EncodingUtils.encodedShortStringLength("result") + EncodingUtils.encodedLongStringLength("Hello");
result.put("object-bool", true);
size += 1 + EncodingUtils.encodedShortStringLength("object-bool") + EncodingUtils.encodedBooleanLength();
result.put("object-byte", Byte.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-byte") + EncodingUtils.encodedByteLength();
result.put("object-bytes", _bytes);
size += 1 + EncodingUtils.encodedShortStringLength("object-bytes") + 4 + _bytes.length;
result.put("object-char", 'c');
size += 1 + EncodingUtils.encodedShortStringLength("object-char") + EncodingUtils.encodedCharLength();
result.put("object-double", Double.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-double") + EncodingUtils.encodedDoubleLength();
result.put("object-float", Float.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-float") + EncodingUtils.encodedFloatLength();
result.put("object-int", Integer.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-int") + EncodingUtils.encodedIntegerLength();
result.put("object-long", Long.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-long") + EncodingUtils.encodedLongLength();
result.put("object-short", Short.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-short") + EncodingUtils.encodedShortLength();
assertEquals(size, FieldTableFactory.createFieldTable(result).getEncodedSize());
}
/**
* Additional test checkPropertyName doesn't accept Null
*/
@Test
public void testCheckPropertyNameIsNull()
{
try
{
FieldTableFactory.createFieldTable(Collections.singletonMap(null, "String"));
fail("Null property name is not allowed");
}
catch (IllegalArgumentException iae)
{
// normal path
}
}
/**
* Additional test checkPropertyName doesn't accept an empty String
*/
@Test
public void testCheckPropertyNameIsEmptyString()
{
try
{
FieldTableFactory.createFieldTable(Collections.singletonMap("", "String"));
fail("empty property name is not allowed");
}
catch (IllegalArgumentException iae)
{
// normal path
}
}
/**
* Additional test checkPropertyName doesn't accept an empty String
*/
@Test
public void testCheckPropertyNameHasMaxLength()
{
StringBuilder longPropertyName = new StringBuilder(129);
for (int i = 0; i < 129; i++)
{
longPropertyName.append("x");
}
boolean strictAMQP = FieldTable._strictAMQP;
try
{
FieldTable._strictAMQP = true;
new FieldTable(Collections.singletonMap(longPropertyName.toString(), "String"));
fail("property name must be < 128 characters");
}
catch (IllegalArgumentException iae)
{
// normal path
}
finally
{
FieldTable._strictAMQP = strictAMQP;
}
}
/**
* Additional test checkPropertyName starts with a letter
*/
@Test
public void testCheckPropertyNameStartCharacterIsLetter()
{
boolean strictAMQP = FieldTable._strictAMQP;
// Try a name that starts with a number
try
{
FieldTable._strictAMQP = true;
new FieldTable(Collections.singletonMap("1", "String"));
fail("property name must start with a letter");
}
catch (IllegalArgumentException iae)
{
// normal path
}
finally
{
FieldTable._strictAMQP = strictAMQP;
}
}
/**
* Additional test checkPropertyName starts with a hash or a dollar
*/
@Test
public void testCheckPropertyNameStartCharacterIsHashOrDollar()
{
try
{
FieldTableFactory.createFieldTable(Collections.singletonMap("#", "String"));
}
catch (IllegalArgumentException iae)
{
fail("property name are allowed to start with # and $s");
}
try
{
FieldTableFactory.createFieldTable(Collections.singletonMap("$", "String"));
}
catch (IllegalArgumentException iae)
{
fail("property name are allowed to start with # and $s");
}
}
@Test
public void testValidateMalformedFieldTable()
{
final FieldTable fieldTable = buildMalformedFieldTable();
try
{
fieldTable.validate();
fail("Exception is expected");
}
catch (RuntimeException e)
{
// pass
}
}
@Test
public void testValidateCorrectFieldTable()
{
final FieldTable ft = new FieldTable(Collections.singletonMap("testKey", "testValue"));
final int encodedSize = (int)ft.getEncodedSize() + Integer.BYTES;
final QpidByteBuffer buf = QpidByteBuffer.allocate(encodedSize);
ft.writeToBuffer(buf);
buf.flip();
buf.position(Integer.BYTES);
final FieldTable fieldTable = new FieldTable(buf);
assertEquals(1, fieldTable.size());
fieldTable.validate();
assertTrue("Expected key is not found", fieldTable.containsKey("testKey"));
}
private FieldTable buildMalformedFieldTable()
{
final QpidByteBuffer buf = QpidByteBuffer.allocate(1);
buf.put((byte) -1);
buf.flip();
return FieldTableFactory.createFieldTable(buf);
}
private void assertBytesEqual(byte[] expected, byte[] actual)
{
assertEquals(expected.length, actual.length);
for (int index = 0; index < expected.length; index++)
{
assertEquals(expected[index], actual[index]);
}
}
public static junit.framework.Test suite()
{
return new junit.framework.TestSuite(FieldTableTest.class);
}
}