/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.client; import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.List; import org.junit.Test; import org.teiid.core.types.ArrayImpl; import org.teiid.core.types.BinaryType; import org.teiid.core.types.DataTypeManager; import org.teiid.core.types.GeometryType; import org.teiid.core.util.TimestampWithTimezone; import org.teiid.query.unittest.TimestampUtil; /** * @since 4.2 */ @SuppressWarnings("nls") public class TestBatchSerializer { private static List<List<Object>> helpTestSerialization(String[] types, List<?>[] batch, byte version) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteStream); List<List<?>> batchList = Arrays.asList(batch); BatchSerializer.writeBatch(out, types, batchList, version); out.flush(); byte[] bytes = byteStream.toByteArray(); ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(bytesIn); List<List<Object>> newBatch = BatchSerializer.readBatch(in, types); out.close(); in.close(); assertTrue(batchList.equals(newBatch)); return newBatch; } private static final String[] sampleBatchTypes = {DataTypeManager.DefaultDataTypes.BIG_DECIMAL, DataTypeManager.DefaultDataTypes.BIG_INTEGER, DataTypeManager.DefaultDataTypes.BOOLEAN, DataTypeManager.DefaultDataTypes.BYTE, DataTypeManager.DefaultDataTypes.CHAR, DataTypeManager.DefaultDataTypes.DATE, DataTypeManager.DefaultDataTypes.DOUBLE, DataTypeManager.DefaultDataTypes.FLOAT, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.LONG, DataTypeManager.DefaultDataTypes.SHORT, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.TIME, DataTypeManager.DefaultDataTypes.TIMESTAMP, DataTypeManager.DefaultDataTypes.OBJECT, DataTypeManager.DefaultDataTypes.VARBINARY, }; private static String sampleString(int length) { char[] chars = new char[length]; for (int i = 0; i < length; i++) { chars[i] = (char)i; } return new String(chars); } private static List<?>[] sampleBatchWithNulls(int rows) { List<?>[] batch = new List[rows]; for (int i = 0; i < rows; i++) { java.util.Date d = new java.util.Date(); int mod = i%16; Object[] data = { (mod == 0) ? null : new BigDecimal("" + i), //$NON-NLS-1$ (mod == 1) ? null : new BigInteger(Integer.toString(i)), (mod == 2) ? null : ((i%2 == 0) ? Boolean.FALSE: Boolean.TRUE), (mod == 3) ? null : new Byte((byte)i), (mod == 4) ? null : new Character((char)i), (mod == 5) ? null : TimestampWithTimezone.createDate(d), (mod == 6) ? null : new Double(i), (mod == 7) ? null : new Float(i), (mod == 8) ? null : new Integer(i), (mod == 9) ? null : new Long(i), (mod == 10) ? null : new Short((short)i), (mod == 11) ? null : sampleString(i), (mod == 12) ? null : TimestampWithTimezone.createTime(d), (mod == 13) ? null : TimestampWithTimezone.createTimestamp(d), (mod == 14) ? null : TimestampWithTimezone.createTimestamp(d), (mod == 15) ? null : new BinaryType(new byte[] {(byte)i}), }; batch[i] = Arrays.asList(data); } return batch; } @Test public void testSerializeBasicTypes() throws Exception { // The number 8 is important here because boolean isNull information is packed into bytes, // so we want to make sure the boundary cases are handled correctly helpTestSerialization(sampleBatchTypes, sampleBatchWithNulls(1), BatchSerializer.CURRENT_VERSION); // Less than 8 rows helpTestSerialization(sampleBatchTypes, sampleBatchWithNulls(8), BatchSerializer.CURRENT_VERSION); // Exactly 8 rows helpTestSerialization(sampleBatchTypes, sampleBatchWithNulls(17), BatchSerializer.CURRENT_VERSION); // More than 8 rows, but not a multiple of 8 helpTestSerialization(sampleBatchTypes, sampleBatchWithNulls(120), BatchSerializer.CURRENT_VERSION); // A multiple of 8 rows helpTestSerialization(sampleBatchTypes, sampleBatchWithNulls(833), BatchSerializer.CURRENT_VERSION); // A bunch of rows. This should also test large strings helpTestSerialization(sampleBatchTypes, sampleBatchWithNulls(4096), BatchSerializer.CURRENT_VERSION); // A bunch of rows. This should also test large strings } @Test public void testSerializeLargeStrings() throws Exception { List<?> row = Arrays.asList(new Object[] {sampleString(66666)}); helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.STRING}, new List[] {row}, BatchSerializer.CURRENT_VERSION); } @Test public void testSerializeNoData() throws Exception { helpTestSerialization(sampleBatchTypes, new List[0], BatchSerializer.CURRENT_VERSION); } @Test public void testSerializeDatatypeMismatch() throws Exception { try { helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.DOUBLE}, new List[] {Arrays.asList(new Object[] {"Hello!"})}, BatchSerializer.CURRENT_VERSION); //$NON-NLS-1$ } catch (RuntimeException e) { assertEquals("TEIID20001 The modeled datatype double for column 0 doesn't match the runtime type \"java.lang.String\". Please ensure that the column's modeled datatype matches the expected data.", e.getMessage()); //$NON-NLS-1$ } } @Test(expected=IOException.class) public void testOutOfRangeDate() throws Exception { helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.DATE}, new List[] {Arrays.asList(TimestampUtil.createDate(-2, 0, 1))}, (byte)1); } @Test public void testStringArray() throws IOException, ClassNotFoundException { helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.LONG, "string[]"}, new List[] {Arrays.asList(1l, new ArrayImpl(new String[] {"Silly String", "Silly String"}))}, BatchSerializer.CURRENT_VERSION); } @Test public void testGeometry() throws IOException, ClassNotFoundException { GeometryType geometryType = new GeometryType(new byte[0]); geometryType.setReferenceStreamId(null); geometryType.setSrid(10000); Object val = helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.GEOMETRY}, new List[] {Arrays.asList(geometryType)}, BatchSerializer.CURRENT_VERSION).get(0).get(0); assertTrue(val instanceof GeometryType); assertEquals(10000, ((GeometryType)val).getSrid()); helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.GEOMETRY}, new List[] {Arrays.asList(geometryType)}, (byte)0); //object serialization - should fail on the client side val = helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.GEOMETRY}, new List[] {Arrays.asList(geometryType)}, (byte)1); //blob serialization assertFalse(val instanceof GeometryType); val = helpTestSerialization(new String[] {DataTypeManager.DefaultDataTypes.OBJECT}, new List[] {Arrays.asList(geometryType)}, (byte)1); //blob serialization assertFalse(val instanceof GeometryType); } }