/* * Copyright © 2015 Cask Data, Inc. * * 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 co.cask.cdap.etl.common; import co.cask.cdap.etl.api.Transform; import co.cask.cdap.etl.api.Transformation; import co.cask.cdap.etl.api.batch.BatchSink; import com.google.common.collect.Lists; import com.google.common.reflect.TypeToken; import org.apache.avro.generic.GenericRecord; import org.apache.avro.ipc.trace.TimestampedEvent; import org.junit.Test; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * Testing the Validation of etl stage hookups. */ public class PipelineTypeValidatorTest { @Test(expected = IllegalArgumentException.class) public void testSimpleInvalidMatch() throws Exception { // String --> Integer ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(String.class); typeList.add(Integer.class); PipelineTypeValidator.validateTypes(typeList); } @Test(expected = IllegalArgumentException.class) public void testAnotherInvalidMatch() throws Exception { // String --> Object | Object --> T | List<T> --> List<String> // List<Object> -> List<String> should fail. ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(String.class); typeList.add(Object.class); typeList.add(Object.class); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.add(getFirstTypeParameter(StringListSink.class)); PipelineTypeValidator.validateTypes(typeList); } @Test public void testSimpleValidType() throws Exception { // Child --> Parent | Integer --> Object ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(TimestampedEvent.class); typeList.add(GenericRecord.class); typeList.add(Integer.class); typeList.add(Object.class); PipelineTypeValidator.validateTypes(typeList); } @Test public void testParameterType() throws Exception { // String --> T | List<T> --> List<String> ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(String.class); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.add(getFirstTypeParameter(StringListSink.class)); PipelineTypeValidator.validateTypes(typeList); } @Test public void testRepeatStageType() throws Exception { // String --> T | List<T> --> T | List<T> --> T | List<T> --> Object ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(String.class); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.add(getFirstTypeParameter(NoOpSink.class)); PipelineTypeValidator.validateTypes(typeList); } @Test public void testGenericArrayType() throws Exception { // String[] --> E[] | List<E[]> --> Object ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(String[].class); typeList.addAll(getBothParameters(ArrayToListArray.class)); typeList.add(getFirstTypeParameter(NoOpSink.class)); PipelineTypeValidator.validateTypes(typeList); } @Test public void testGenericParameterType() throws Exception { // String[] --> E[] | List<E[]> --> T | List<T> --> Object ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(String[].class); typeList.addAll(getBothParameters(ArrayToListArray.class)); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.add(getFirstTypeParameter(NoOpSink.class)); PipelineTypeValidator.validateTypes(typeList); } @Test public void testSourceParamType() throws Exception { // T --> N | List<N> --> M ArrayList<Type> typeList = Lists.newArrayList(); typeList.add(getFirstTypeParameter(ParamToListParam.class)); typeList.addAll(getBothParameters(ParamToListParam.class)); typeList.add(getFirstTypeParameter(ParamToListParam.class)); PipelineTypeValidator.validateTypes(typeList); } private static List<Type> getBothParameters(Class klass) { return Lists.newArrayList(getFirstTypeParameter(klass), getSecondTypeParameter(klass)); } private static Type getTypeParameter(Class klass, int index) { return TypeToken.of(klass).resolveType(Transformation.class.getTypeParameters()[index]).getType(); } private static Type getFirstTypeParameter(Class klass) { return getTypeParameter(klass, 0); } private static Type getSecondTypeParameter(Class klass) { return getTypeParameter(klass, 1); } private abstract static class ParamToListParam<T> extends Transform<T, List<T>> { } private abstract static class ArrayToListArray<E> extends Transform<E[], List<E[]>> { } private abstract static class StringListSink<A, B> extends BatchSink<List<String>, A, B> { } private abstract static class NoOpSink<X, Y> extends BatchSink<Object, X, Y> { } }