/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 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.steps.mergerows; import java.util.ArrayList; import java.util.List; import java.util.Iterator; import org.junit.Test; import static org.junit.Assert.*; import org.pentaho.di.core.Const; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.RowMetaAndData; import org.pentaho.di.core.exception.KettleValueException; import org.pentaho.di.core.plugins.PluginRegistry; import org.pentaho.di.core.plugins.StepPluginType; import org.pentaho.di.core.row.RowMeta; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMeta; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.trans.RowProducer; import org.pentaho.di.core.row.value.ValueMetaFactory; import org.pentaho.di.trans.RowStepCollector; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransHopMeta; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.StepInterface; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.trans.step.errorhandling.StreamInterface; import org.pentaho.di.trans.steps.rowgenerator.RowGeneratorMeta; public class MergeRowsTest { String keyField = "key"; String compareField = "compareValue"; String extraField = "extraValue"; String flagField = "flagField"; // Stuff to set up row generators String[] fieldName = { keyField, compareField, extraField }; String[] type = { "String", "String", "String" }; String[] fieldFormat = { "", "", "" }; String[] group = { "", "", "" }; String[] decimal = { "", "", "" }; String[] currency = { "", "", "" }; int[] intDummies = { -1, -1, -1 }; boolean[] setEmptystring = { false, false, false }; public RowMetaInterface createResultRowMetaInterface() { RowMetaInterface rm = new RowMeta(); try { ValueMetaInterface[] valuesMeta = { ValueMetaFactory.createValueMeta( keyField, ValueMetaInterface.TYPE_STRING ), ValueMetaFactory.createValueMeta( compareField, ValueMetaInterface.TYPE_STRING ), ValueMetaFactory.createValueMeta( extraField, ValueMetaInterface.TYPE_STRING ), ValueMetaFactory.createValueMeta( flagField, ValueMetaInterface.TYPE_STRING ) }; for ( int i = 0; i < valuesMeta.length; i++ ) { rm.addValueMeta( valuesMeta[i] ); } } catch ( Exception ex ) { return null; } return rm; } public List<RowMetaAndData> createResultData(Object[] values) { List<RowMetaAndData> list = new ArrayList<RowMetaAndData>(); RowMetaInterface rm = createResultRowMetaInterface(); list.add( new RowMetaAndData( rm, values ) ); return list; } /** * Check the 2 lists comparing the rows in order. * If they are not the same fail the test. */ public void checkRows( List<RowMetaAndData> rows1, List<RowMetaAndData> rows2 ) { int idx = 1; if ( rows1.size() != rows2.size() ) { fail( "Number of rows is not the same: " + rows1.size() + " and " + rows2.size() ); } Iterator<RowMetaAndData> it1 = rows1.iterator(); Iterator<RowMetaAndData> it2 = rows2.iterator(); while ( it1.hasNext() && it2.hasNext() ) { RowMetaAndData rm1 = it1.next(); RowMetaAndData rm2 = it2.next(); Object[] r1 = rm1.getData(); Object[] r2 = rm2.getData(); if ( rm1.size() != rm2.size() ) { fail( "row size of row at " + idx + " is not equal (" + rm1.size() + "," + rm2.size() + ")" ); } int[] fields = new int[1]; for ( int ydx = 0; ydx < rm1.size(); ydx++ ) { fields[0] = ydx; try { if ( rm1.getRowMeta().compare( r1, r2, fields ) != 0 ) { fail( "row nr " + idx + " is not equal at field nr " + ydx + "(" + rm1.toString() + ";" + rm2.toString() + ")" ); } } catch ( KettleValueException e ) { fail( "row nr " + idx + " is not equal at field nr " + ydx + "(" + rm1.toString() + ";" + rm2.toString() + ")" ); } } idx++; } } void createRowGenerator( TransMeta transMeta, PluginRegistry registry, String stepName, String[] values, StepMeta mergeRowsStep, MergeRowsMeta mergeRowsMeta, int index ) { RowGeneratorMeta rowGeneratorMeta = new RowGeneratorMeta(); String rowGeneratorPid = registry.getPluginId( StepPluginType.class, rowGeneratorMeta ); StepMeta rowGeneratorStep = new StepMeta( rowGeneratorPid, stepName, rowGeneratorMeta ); transMeta.addStep( rowGeneratorStep ); rowGeneratorMeta.setDefault(); rowGeneratorMeta.setFieldName( fieldName ); rowGeneratorMeta.setFieldType( type ); rowGeneratorMeta.setFieldLength( intDummies ); rowGeneratorMeta.setFieldPrecision( intDummies ); rowGeneratorMeta.setRowLimit( "1" ); rowGeneratorMeta.setFieldFormat( fieldFormat ); rowGeneratorMeta.setGroup( group ); rowGeneratorMeta.setDecimal( decimal ); rowGeneratorMeta.setCurrency( currency ); rowGeneratorMeta.setEmptyString( setEmptystring ); rowGeneratorMeta.setValue( values ); TransHopMeta hi1 = new TransHopMeta( rowGeneratorStep, mergeRowsStep ); transMeta.addTransHop( hi1 ); List<StreamInterface> infoStreams = mergeRowsMeta.getStepIOMeta().getInfoStreams(); StreamInterface infoStream = infoStreams.get( index ); infoStream.setStepMeta( transMeta.findStep( stepName ) ); } void testOneRow(String transName, String[] referenceValues, String[] comparisonValues, Object[] goldenImageRowValues) throws Exception { KettleEnvironment.init(); // Create a new transformation... TransMeta transMeta = new TransMeta(); transMeta.setName( transName ); PluginRegistry registry = PluginRegistry.getInstance(); // Create a merge rows step String mergeRowsStepName = "merge rows step"; MergeRowsMeta mergeRowsMeta = new MergeRowsMeta(); String mergeRowsStepPid = registry.getPluginId( StepPluginType.class, mergeRowsMeta ); StepMeta mergeRowsStep = new StepMeta( mergeRowsStepPid, mergeRowsStepName, mergeRowsMeta ); transMeta.addStep( mergeRowsStep ); mergeRowsMeta.setKeyFields( new String[]{ keyField } ); mergeRowsMeta.setValueFields( new String[]{ compareField } ); mergeRowsMeta.setFlagField( flagField ); List<StreamInterface> infoStreams = mergeRowsMeta.getStepIOMeta().getInfoStreams(); // // create a reference stream (row generator step) // createRowGenerator( transMeta, registry, "reference row generator", referenceValues, mergeRowsStep, mergeRowsMeta, 0 ); // // create a comparison stream (row generator step) // createRowGenerator( transMeta, registry, "comparison row generator", comparisonValues, mergeRowsStep, mergeRowsMeta, 1 ); // Now execute the transformation Trans trans = new Trans( transMeta ); trans.prepareExecution( null ); StepInterface si = trans.getStepInterface( mergeRowsStepName, 0 ); RowStepCollector endRc = new RowStepCollector(); si.addRowListener( endRc ); trans.startThreads(); trans.waitUntilFinished(); // Now check whether the output is still as we expect. List<RowMetaAndData> goldenImageRows = createResultData( goldenImageRowValues ); List<RowMetaAndData> resultRows1 = endRc.getRowsWritten(); checkRows( resultRows1, goldenImageRows ); } @Test public void testMergeRowsIdentical() throws Exception { //if not in backwards compatible mode, use the comparison values when values are "identical" System.setProperty( Const.KETTLE_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL, "N" ); String[] refs = new String[]{ "key", "compareValue1", "extraValue1" }; String[] comp = new String[]{ "key", "compareValue1", "extraValue2" }; Object[] gold = new Object[]{ "key", "compareValue1", "extraValue2", "identical" }; testOneRow("testMergeRowsIdentical", refs, comp, gold); } @Test public void testMergeRowsIdenticalPDI736Compatible() throws Exception { //if not in backwards compatible mode, use the reference values when values are "identical" System.setProperty( Const.KETTLE_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL, "Y" ); String[] refs = new String[]{ "key", "compareValue1", "extraValue1" }; String[] comp = new String[]{ "key", "compareValue1", "extraValue2" }; Object[] gold = new Object[]{ "key", "compareValue1", "extraValue1", "identical" }; testOneRow("testMergeRowsIdenticalPDI736Compatible", refs, comp, gold); } @Test public void testMergeRowsChanged() throws Exception { //regardless of backwards compatible mode, use the comparison values when values are "changed" System.setProperty( Const.KETTLE_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL, "N" ); String[] refs = new String[]{ "key", "compareValue1", "extraValue1" }; String[] comp = new String[]{ "key", "this value changed", "extraValue2" }; Object[] gold = new Object[]{ "key", "this value changed", "extraValue2", "changed" }; testOneRow("testMergeRowsChanged", refs, comp, gold); } @Test public void testMergeRowsChangedPDI736Compatible() throws Exception { //regardless of backwards compatible mode, use the comparison values when values are "changed" System.setProperty( Const.KETTLE_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL, "Y" ); String[] refs = new String[]{ "key", "compareValue1", "extraValue1" }; String[] comp = new String[]{ "key", "this value changed", "extraValue2" }; Object[] gold = new Object[]{ "key", "this value changed", "extraValue2", "changed" }; testOneRow("testMergeRowsChangedPDI736Compatible", refs, comp, gold); } }