/* * 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 parquet.thrift; import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import thrift.test.OneOfEach; import org.apache.pig.data.Tuple; import org.apache.pig.impl.logicalLayer.schema.Schema; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.junit.Test; import parquet.io.ColumnIOFactory; import parquet.io.ConverterConsumer; import parquet.io.MessageColumnIO; import parquet.io.RecordConsumerLoggingWrapper; import parquet.io.api.RecordConsumer; import parquet.pig.PigSchemaConverter; import parquet.pig.convert.TupleRecordMaterializer; import parquet.schema.MessageType; import parquet.thrift.struct.ThriftType.StructType; import com.twitter.data.proto.tutorial.thrift.AddressBook; import com.twitter.data.proto.tutorial.thrift.Name; import com.twitter.data.proto.tutorial.thrift.Person; import com.twitter.data.proto.tutorial.thrift.PhoneNumber; import com.twitter.data.proto.tutorial.thrift.PhoneType; import com.twitter.elephantbird.pig.util.ThriftToPig; import com.twitter.elephantbird.thrift.test.TestMap; import com.twitter.elephantbird.thrift.test.TestMapInSet; import com.twitter.elephantbird.thrift.test.TestName; import com.twitter.elephantbird.thrift.test.TestNameList; import com.twitter.elephantbird.thrift.test.TestPerson; import com.twitter.elephantbird.thrift.test.TestPhoneType; import com.twitter.elephantbird.thrift.test.TestStructInMap; public class TestThriftToPigCompatibility { public void testMap() throws Exception { Map<String, String> map = new TreeMap<String, String>(); map.put("foo", "bar"); map.put("foo2", "bar2"); TestMap testMap = new TestMap("map_name", map); validateSameTupleAsEB(testMap); } @Test public void testMapInSet() throws Exception { final Set<Map<String, String>> set = new HashSet<Map<String,String>>(); final Map<String, String> map = new HashMap<String, String>(); map.put("foo", "bar"); set.add(map); TestMapInSet o = new TestMapInSet("top", set); validateSameTupleAsEB(o); } @Test public void testStructInMap() throws Exception { final Map<String, TestPerson> map = new HashMap<String, TestPerson>(); map.put("foo", new TestPerson(new TestName("john", "johnson"), new HashMap<TestPhoneType, String>())); final Map<String, Integer> stringToIntMap = Collections.singletonMap("bar", 10); TestStructInMap testMap = new TestStructInMap("map_name", map, stringToIntMap); validateSameTupleAsEB(testMap); } @Test public void testProtocolEmptyAdressBook() throws Exception { AddressBook a = new AddressBook(new ArrayList<Person>()); validateSameTupleAsEB(a); } @Test public void testProtocolAddressBook() throws Exception { ArrayList<Person> persons = new ArrayList<Person>(); final PhoneNumber phoneNumber = new PhoneNumber("555 999 9998"); phoneNumber.type = PhoneType.HOME; persons.add( new Person( new Name("Bob", "Roberts"), 1, "bob@roberts.com", Arrays.asList(new PhoneNumber("555 999 9999"), phoneNumber))); persons.add( new Person( new Name("Dick", "Richardson"), 2, "dick@richardson.com", Arrays.asList(new PhoneNumber("555 999 9997"), new PhoneNumber("555 999 9996")))); AddressBook a = new AddressBook(persons); validateSameTupleAsEB(a); } @Test public void testOneOfEach() throws Exception { OneOfEach a = new OneOfEach( true, false, (byte)8, (short)16, (int)32, (long)64, (double)1234, "string", "å", false, ByteBuffer.wrap("a".getBytes()), new ArrayList<Byte>(), new ArrayList<Short>(), new ArrayList<Long>()); validateSameTupleAsEB(a); } @Test public void testStringList() throws Exception { final List<String> names = new ArrayList<String>(); names.add("John"); names.add("Jack"); TestNameList o = new TestNameList("name", names); validateSameTupleAsEB(o); } /** * <ul> steps: * <li>Writes using the thrift mapping * <li>Reads using the pig mapping * <li>Use Elephant bird to convert from thrift to pig * <li>Check that both transformations give the same result * @param o the object to convert * @throws TException */ public static <T extends TBase<?,?>> void validateSameTupleAsEB(T o) throws TException { final ThriftSchemaConverter thriftSchemaConverter = new ThriftSchemaConverter(); @SuppressWarnings("unchecked") final Class<T> class1 = (Class<T>) o.getClass(); final MessageType schema = thriftSchemaConverter.convert(class1); final StructType structType = thriftSchemaConverter.toStructType(class1); final ThriftToPig<T> thriftToPig = new ThriftToPig<T>(class1); final Schema pigSchema = thriftToPig.toSchema(); final TupleRecordMaterializer tupleRecordConverter = new TupleRecordMaterializer(schema, pigSchema, true); RecordConsumer recordConsumer = new ConverterConsumer(tupleRecordConverter.getRootConverter(), schema); final MessageColumnIO columnIO = new ColumnIOFactory().getColumnIO(schema); ParquetWriteProtocol p = new ParquetWriteProtocol(new RecordConsumerLoggingWrapper(recordConsumer), columnIO, structType); o.write(p); final Tuple t = tupleRecordConverter.getCurrentRecord(); final Tuple expected = thriftToPig.getPigTuple(o); assertEquals(expected.toString(), t.toString()); final MessageType filtered = new PigSchemaConverter().filter(schema, pigSchema); assertEquals(schema.toString(), filtered.toString()); } }