/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* 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 org.pentaho.di.trans;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.gui.Point;
import org.pentaho.di.core.listeners.ContentChangedListener;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaFactory;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.metastore.DatabaseMetaStoreUtil;
import org.pentaho.di.repository.ObjectRevision;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.RepositoryDirectoryInterface;
import org.pentaho.di.trans.step.StepIOMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaChangeListenerInterface;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.di.trans.steps.datagrid.DataGridMeta;
import org.pentaho.di.trans.steps.userdefinedjavaclass.StepDefinition;
import org.pentaho.di.trans.steps.userdefinedjavaclass.UserDefinedJavaClassDef;
import org.pentaho.di.trans.steps.userdefinedjavaclass.UserDefinedJavaClassMeta;
import org.pentaho.metastore.api.IMetaStore;
import org.pentaho.metastore.stores.memory.MemoryMetaStore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class TransMetaTest {
public static final String STEP_NAME = "Any step name";
@BeforeClass
public static void initKettle() throws Exception {
KettleEnvironment.init( false );
}
private TransMeta transMeta;
@Before
public void setUp() throws Exception {
transMeta = new TransMeta();
}
@Test
public void testGetMinimum() {
final Point minimalCanvasPoint = new Point( 0, 0 );
//for test goal should content coordinate more than NotePadMetaPoint
final Point stepPoint = new Point( 500, 500 );
//empty Trans return 0 coordinate point
Point point = transMeta.getMinimum();
assertEquals( minimalCanvasPoint.x, point.x );
assertEquals( minimalCanvasPoint.y, point.y );
//when Trans content Step than trans should return minimal coordinate of step
StepMeta stepMeta = mock( StepMeta.class );
when( stepMeta.getLocation() ).thenReturn( stepPoint );
transMeta.addStep( stepMeta );
Point actualStepPoint = transMeta.getMinimum();
assertEquals( stepPoint.x - TransMeta.BORDER_INDENT, actualStepPoint.x );
assertEquals( stepPoint.y - TransMeta.BORDER_INDENT, actualStepPoint.y );
}
@Test
public void getThisStepFieldsPassesCloneRowMeta() throws Exception {
final String overriddenValue = "overridden";
StepMeta nextStep = mockStepMeta( "nextStep" );
StepMetaInterface smi = mock( StepMetaInterface.class );
StepIOMeta ioMeta = mock( StepIOMeta.class );
when( smi.getStepIOMeta() ).thenReturn( ioMeta );
doAnswer( new Answer<Object>() {
@Override public Object answer( InvocationOnMock invocation ) throws Throwable {
RowMetaInterface rmi = (RowMetaInterface) invocation.getArguments()[ 0 ];
rmi.clear();
rmi.addValueMeta( new ValueMetaString( overriddenValue ) );
return null;
} } ).when( smi ).getFields(
any( RowMetaInterface.class ), anyString(), any( RowMetaInterface[].class ), eq( nextStep ),
any( VariableSpace.class ), any( Repository.class ), any( IMetaStore.class ) );
StepMeta thisStep = mockStepMeta( "thisStep" );
when( thisStep.getStepMetaInterface() ).thenReturn( smi );
RowMeta rowMeta = new RowMeta();
rowMeta.addValueMeta( new ValueMetaString( "value" ) );
RowMetaInterface thisStepsFields = transMeta.getThisStepFields( thisStep, nextStep, rowMeta );
assertEquals( 1, thisStepsFields.size() );
assertEquals( overriddenValue, thisStepsFields.getValueMeta( 0 ).getName() );
}
@Test
public void testDatabaseNotOverridden() throws Exception {
final String name = "db meta";
DatabaseMeta dbMetaShared = new DatabaseMeta();
dbMetaShared.setName( name );
dbMetaShared.setHostname( "host" );
DatabaseMeta dbMetaStore = new DatabaseMeta();
dbMetaStore.setName( name );
dbMetaStore.setHostname( "anotherhost" );
IMetaStore mstore = new MemoryMetaStore();
DatabaseMetaStoreUtil.createDatabaseElement( mstore, dbMetaStore );
TransMeta trans = new TransMeta();
trans.addOrReplaceDatabase( dbMetaShared );
trans.setMetaStore( mstore );
trans.importFromMetaStore();
DatabaseMeta dbMeta = trans.findDatabase( name );
assertEquals( dbMetaShared.getHostname(), dbMeta.getHostname() );
}
@Test
public void testContentChangeListener() throws Exception {
ContentChangedListener listener = mock( ContentChangedListener.class );
transMeta.addContentChangedListener( listener );
transMeta.setChanged();
transMeta.setChanged( true );
verify( listener, times( 2 ) ).contentChanged( same( transMeta ) );
transMeta.clearChanged();
transMeta.setChanged( false );
verify( listener, times( 2 ) ).contentSafe( same( transMeta ) );
transMeta.removeContentChangedListener( listener );
transMeta.setChanged();
transMeta.setChanged( true );
verifyNoMoreInteractions( listener );
}
@Test
public void testCompare() throws Exception {
TransMeta transMeta = new TransMeta( "aFile", "aName" );
TransMeta transMeta2 = new TransMeta( "aFile", "aName" );
assertEquals( 0, transMeta.compare( transMeta, transMeta2 ) );
transMeta2.setVariable( "myVariable", "myValue" );
assertEquals( 0, transMeta.compare( transMeta, transMeta2 ) );
transMeta2.setFilename( null );
assertEquals( 1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( -1, transMeta.compare( transMeta2, transMeta ) );
transMeta2.setFilename( "aFile" );
transMeta2.setName( null );
assertEquals( 1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( -1, transMeta.compare( transMeta2, transMeta ) );
transMeta2.setFilename( "aFile2" );
transMeta2.setName( "aName" );
assertEquals( -1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( 1, transMeta.compare( transMeta2, transMeta ) );
transMeta2.setFilename( "aFile" );
transMeta2.setName( "aName2" );
assertEquals( -1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( 1, transMeta.compare( transMeta2, transMeta ) );
transMeta.setFilename( null );
transMeta2.setFilename( null );
transMeta2.setName( "aName" );
assertEquals( 0, transMeta.compare( transMeta, transMeta2 ) );
RepositoryDirectoryInterface path1 = mock( RepositoryDirectoryInterface.class );
transMeta.setRepositoryDirectory( path1 );
when( path1.getPath() ).thenReturn( "aPath2" );
RepositoryDirectoryInterface path2 = mock( RepositoryDirectoryInterface.class );
when( path2.getPath() ).thenReturn( "aPath" );
transMeta2.setRepositoryDirectory( path2 );
assertEquals( 1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( -1, transMeta.compare( transMeta2, transMeta ) );
when( path1.getPath() ).thenReturn( "aPath" );
assertEquals( 0, transMeta.compare( transMeta, transMeta2 ) );
ObjectRevision revision2 = mock( ObjectRevision.class );
transMeta2.setObjectRevision( revision2 );
assertEquals( -1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( 1, transMeta.compare( transMeta2, transMeta ) );
ObjectRevision revision1 = mock( ObjectRevision.class );
transMeta.setObjectRevision( revision1 );
when( revision1.getName() ).thenReturn( "aRevision" );
when( revision2.getName() ).thenReturn( "aRevision" );
assertEquals( 0, transMeta.compare( transMeta, transMeta2 ) );
when( revision2.getName() ).thenReturn( "aRevision2" );
assertEquals( -1, transMeta.compare( transMeta, transMeta2 ) );
assertEquals( 1, transMeta.compare( transMeta2, transMeta ) );
}
@Test
public void testEquals() throws Exception {
TransMeta transMeta = new TransMeta( "1", "2" );
assertFalse( transMeta.equals( "somethingelse" ) );
assertTrue( transMeta.equals( new TransMeta( "1", "2" ) ) );
}
@Test
public void testTransHops() throws Exception {
TransMeta transMeta = new TransMeta( "transFile", "myTrans" );
StepMeta step1 = new StepMeta( "name1", null );
StepMeta step2 = new StepMeta( "name2", null );
StepMeta step3 = new StepMeta( "name3", null );
StepMeta step4 = new StepMeta( "name4", null );
TransHopMeta hopMeta1 = new TransHopMeta( step1, step2, true );
TransHopMeta hopMeta2 = new TransHopMeta( step2, step3, true );
TransHopMeta hopMeta3 = new TransHopMeta( step3, step4, false );
transMeta.addTransHop( 0, hopMeta1 );
transMeta.addTransHop( 1, hopMeta2 );
transMeta.addTransHop( 2, hopMeta3 );
List<StepMeta> hops = transMeta.getTransHopSteps( true );
assertSame( step1, hops.get( 0 ) );
assertSame( step2, hops.get( 1 ) );
assertSame( step3, hops.get( 2 ) );
assertSame( step4, hops.get( 3 ) );
assertEquals( hopMeta2, transMeta.findTransHop( "name2 --> name3 (enabled)" ) );
assertEquals( hopMeta3, transMeta.findTransHopFrom( step3 ) );
assertEquals( hopMeta2, transMeta.findTransHop( hopMeta2 ) );
assertEquals( hopMeta1, transMeta.findTransHop( step1, step2 ) );
assertEquals( null, transMeta.findTransHop( step3, step4, false ) );
assertEquals( hopMeta3, transMeta.findTransHop( step3, step4, true ) );
assertEquals( hopMeta2, transMeta.findTransHopTo( step3 ) );
transMeta.removeTransHop( 0 );
hops = transMeta.getTransHopSteps( true );
assertSame( step2, hops.get( 0 ) );
assertSame( step3, hops.get( 1 ) );
assertSame( step4, hops.get( 2 ) );
transMeta.removeTransHop( hopMeta2 );
hops = transMeta.getTransHopSteps( true );
assertSame( step3, hops.get( 0 ) );
assertSame( step4, hops.get( 1 ) );
}
@Test
public void testGetAllTransHops() throws Exception {
TransMeta transMeta = new TransMeta( "transFile", "myTrans" );
StepMeta step1 = new StepMeta( "name1", null );
StepMeta step2 = new StepMeta( "name2", null );
StepMeta step3 = new StepMeta( "name3", null );
StepMeta step4 = new StepMeta( "name4", null );
TransHopMeta hopMeta1 = new TransHopMeta( step1, step2, true );
TransHopMeta hopMeta2 = new TransHopMeta( step2, step3, true );
TransHopMeta hopMeta3 = new TransHopMeta( step2, step4, true );
transMeta.addTransHop( 0, hopMeta1 );
transMeta.addTransHop( 1, hopMeta2 );
transMeta.addTransHop( 2, hopMeta3 );
List<TransHopMeta> allTransHopFrom = transMeta.findAllTransHopFrom( step2 );
assertEquals( step3, allTransHopFrom.get( 0 ).getToStep() );
assertEquals( step4, allTransHopFrom.get( 1 ).getToStep() );
}
@Test
public void testGetPrevInfoFields() throws KettleStepException {
DataGridMeta dgm1 = new DataGridMeta();
dgm1.setFieldName( new String[]{ "id", "colA" } );
dgm1.allocate( 2 );
dgm1.setFieldType( new String[]{
ValueMetaFactory.getValueMetaName( ValueMetaInterface.TYPE_INTEGER ),
ValueMetaFactory.getValueMetaName( ValueMetaInterface.TYPE_STRING ) } );
List<List<String>> dgm1Data = new ArrayList<>();
dgm1Data.add( Arrays.asList( new String[]{ "1", "A" } ) );
dgm1Data.add( Arrays.asList( new String[]{ "2", "B" } ) );
dgm1.setDataLines( dgm1Data );
DataGridMeta dgm2 = new DataGridMeta();
dgm2.allocate( 1 );
dgm2.setFieldName( new String[]{ "moreData" } );
dgm2.setFieldType( new String[]{
ValueMetaFactory.getValueMetaName( ValueMetaInterface.TYPE_STRING ) } );
List<List<String>> dgm2Data = new ArrayList<>();
dgm2Data.add( Arrays.asList( new String[]{ "Some Informational Data" } ) );
dgm2.setDataLines( dgm2Data );
StepMeta dg1 = new StepMeta( "input1", dgm1 );
StepMeta dg2 = new StepMeta( "input2", dgm2 );
final String UDJC_METHOD =
"public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException { return false; }";
UserDefinedJavaClassMeta udjcMeta = new UserDefinedJavaClassMeta();
udjcMeta.getInfoStepDefinitions().add( new StepDefinition( dg2.getName(), dg2.getName(), dg2, "info_data" ) );
udjcMeta.replaceDefinitions( Arrays.asList( new UserDefinedJavaClassDef[]{
new UserDefinedJavaClassDef( UserDefinedJavaClassDef.ClassType.TRANSFORM_CLASS, "MainClass", UDJC_METHOD ) } ) );
StepMeta udjc = new StepMeta( "PDI-14910", udjcMeta );
TransHopMeta hop1 = new TransHopMeta( dg1, udjc, true );
TransHopMeta hop2 = new TransHopMeta( dg2, udjc, true );
transMeta.addStep( dg1 );
transMeta.addStep( dg2 );
transMeta.addStep( udjc );
transMeta.addTransHop( hop1 );
transMeta.addTransHop( hop2 );
RowMetaInterface row = null;
row = transMeta.getPrevInfoFields( udjc );
assertNotNull( row );
assertEquals( 1, row.size() );
assertEquals( "moreData", row.getValueMeta( 0 ).getName() );
assertEquals( ValueMetaInterface.TYPE_STRING, row.getValueMeta( 0 ).getType() );
}
@Test
public void testAddStepWithChangeListenerInterface() {
StepMeta stepMeta = mock( StepMeta.class );
StepMetaChangeListenerInterfaceMock metaInterface = mock( StepMetaChangeListenerInterfaceMock.class );
when( stepMeta.getStepMetaInterface() ).thenReturn( metaInterface );
assertEquals( 0, transMeta.steps.size() );
assertEquals( 0, transMeta.stepChangeListeners.size() );
// should not throw exception if there are no steps in step meta
transMeta.addStep( 0, stepMeta );
assertEquals( 1, transMeta.steps.size() );
assertEquals( 1, transMeta.stepChangeListeners.size() );
transMeta.addStep( 0, stepMeta );
assertEquals( 2, transMeta.steps.size() );
assertEquals( 2, transMeta.stepChangeListeners.size() );
}
@Test
public void testIsAnySelectedStepUsedInTransHopsNothingSelectedCase() {
List<StepMeta> selectedSteps = Arrays.asList( new StepMeta(), new StepMeta(), new StepMeta() );
transMeta.getSteps().addAll( selectedSteps );
assertFalse( transMeta.isAnySelectedStepUsedInTransHops() );
}
@Test
public void testIsAnySelectedStepUsedInTransHopsAnySelectedCase() {
StepMeta stepMeta = new StepMeta();
stepMeta.setName( STEP_NAME );
TransHopMeta transHopMeta = new TransHopMeta();
stepMeta.setSelected( true );
List<StepMeta> selectedSteps = Arrays.asList( new StepMeta(), stepMeta, new StepMeta() );
transHopMeta.setToStep( stepMeta );
transHopMeta.setFromStep( stepMeta );
transMeta.getSteps().addAll( selectedSteps );
transMeta.addTransHop( transHopMeta );
assertTrue( transMeta.isAnySelectedStepUsedInTransHops() );
}
@Test
public void testCloneWithParam() throws Exception {
TransMeta transMeta = new TransMeta( "transFile", "myTrans" );
transMeta.addParameterDefinition( "key", "defValue", "description" );
Object clone = transMeta.realClone( true );
assertNotNull( clone );
}
private static StepMeta mockStepMeta( String name ) {
StepMeta meta = mock( StepMeta.class );
when( meta.getName() ).thenReturn( name );
return meta;
}
private abstract static class StepMetaChangeListenerInterfaceMock implements StepMetaInterface, StepMetaChangeListenerInterface {
@Override
public abstract Object clone();
}
}