/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 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.memgroupby;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.exception.KettleException;
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.ValueMetaBigNumber;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaNumber;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.TransTestFactory;
import org.pentaho.di.trans.steps.groupby.GroupByMeta;
public class MemoryGroupByIntTest {
public static final String stepName = "MemoryGroupBY";
public static final String KEY1 = "s1";
public static final String KEY2 = "i2";
public static final String KEY3 = "n3";
public static final String KEY4 = "bn4";
public static final String OUT1 = "out1";
public static final String OUT2 = "out2";
public static final String OUT3 = "out3";
public static final String OUT4 = "out4";
@BeforeClass
public static void before() throws KettleException {
KettleEnvironment.init( false );
}
RowMetaInterface getTestRowMeta() {
RowMetaInterface rm = new RowMeta();
rm.addValueMeta( new ValueMetaString( KEY1 ) );
rm.addValueMeta( new ValueMetaInteger( KEY2 ) );
rm.addValueMeta( new ValueMetaNumber( KEY3 ) );
rm.addValueMeta( new ValueMetaBigNumber( KEY4 ) );
return rm;
}
List<RowMetaAndData> getTestRowMetaAndData( int count, Integer[] nulls ) {
List<RowMetaAndData> list = new ArrayList<RowMetaAndData>();
RowMetaInterface rm = getTestRowMeta();
Object[] row = new Object[4];
List<Integer> nullsList = Arrays.asList( nulls );
for ( int i = 0; i < count; i++ ) {
if ( nullsList.contains( i ) ) {
for ( int j = 0; j < row.length; j++ ) {
row[j] = null;
}
} else {
row[0] = "";
row[1] = 1L;
row[2] = 2.0;
row[3] = new BigDecimal( 3 );
}
list.add( new RowMetaAndData( rm, row ) );
}
return list;
}
/**
* This case tests when the MemoryGroupBy step receives 0 input rows, and also no row meta is in the previous step,
* whether it throws an error and fails, or ends successfully without error, while passing no output rows.
* See PDI-12501 for details
*/
@Test
public void testMemoryGroupByNoInputData() throws KettleException {
MemoryGroupByMeta meta = new MemoryGroupByMeta();
meta.setSubjectField( new String[]{ KEY2 } );
meta.setAggregateField( new String[]{ OUT1 } );
meta.setGroupField( new String[]{ KEY1 } );
meta.setAggregateType( new int[] { GroupByMeta.TYPE_GROUP_CONCAT_COMMA } );
TransMeta transMeta = TransTestFactory.generateTestTransformation( null, meta, stepName, getTestRowMeta() );
List<RowMetaAndData> inputList = new ArrayList<RowMetaAndData>();
List<RowMetaAndData> result = null;
try {
result =
TransTestFactory.executeTestTransformation( transMeta, stepName, inputList );
} catch ( KettleException e ) {
Assert.fail();
}
Assert.assertNotNull( result );
Assert.assertEquals( 0, result.size() );
}
/**
* This case tests when the MemoryGroupBy step receives 0 input rows, and also no row meta is in the previous step,
* whether it throws an error and fails, or ends successfully without error, while passing no output rows.
* See PDI-15415 for details
*/
@Test
public void testMemoryGroupByAlwaysReturnARow() throws KettleException {
MemoryGroupByMeta meta = new MemoryGroupByMeta();
meta.setSubjectField( new String[]{ KEY2 } );
meta.setAggregateField( new String[]{ OUT1 } );
meta.setGroupField( new String[]{ KEY1 } );
meta.setAggregateType( new int[] { GroupByMeta.TYPE_GROUP_CONCAT_COMMA } );
meta.setAlwaysGivingBackOneRow( true );
TransMeta transMeta = TransTestFactory.generateTestTransformation( null, meta, stepName, getTestRowMeta() );
List<RowMetaAndData> inputList = new ArrayList<RowMetaAndData>();
List<RowMetaAndData> result = null;
try {
result =
TransTestFactory.executeTestTransformation( transMeta, stepName, inputList );
} catch ( KettleException e ) {
Assert.fail();
}
Assert.assertNotNull( result );
Assert.assertEquals( 1, result.size() );
Assert.assertEquals( KEY1, result.get( 0 ).getValueMeta( 0 ).getName() );
Assert.assertEquals( ValueMetaInterface.TYPE_STRING, result.get( 0 ).getValueMeta( 0 ).getType() );
Assert.assertNull( result.get( 0 ).getString( 0, null ) );
Assert.assertEquals( OUT1, result.get( 0 ).getValueMeta( 1 ).getName() );
Assert.assertEquals( ValueMetaInterface.TYPE_STRING, result.get( 0 ).getValueMeta( 1 ).getType() );
Assert.assertNull( result.get( 0 ).getString( 1, null ) );
}
/**
* This case to test calculation value conversion for MemoryGroupBy, see PDI-11530
* See PDI-11897 for additional details - this case has commented lines which can be real
* bugs. Uncomment code when PDI-11897 will be fixed some day.
*/
@Test
public void testMemoryGroupByNullAggregationsConversion() throws KettleException {
// this to force null aggregations becomes nulls
System.getProperties().setProperty( Const.KETTLE_AGGREGATION_ALL_NULLS_ARE_ZERO, "Y" );
MemoryGroupByMeta meta = new MemoryGroupByMeta();
meta.setSubjectField( new String[] { KEY1, KEY2, KEY3, KEY4 } );
meta.setAggregateField( new String[] { OUT1, OUT2, OUT3, OUT4 } );
meta.setGroupField( new String[] { KEY1 } );
meta.setAggregateType( new int[] { GroupByMeta.TYPE_GROUP_CONCAT_COMMA, GroupByMeta.TYPE_GROUP_SUM,
GroupByMeta.TYPE_GROUP_SUM, GroupByMeta.TYPE_GROUP_SUM } );
TransMeta transMeta = TransTestFactory.generateTestTransformation( null, meta, stepName );
List<RowMetaAndData> inputList = getTestRowMetaAndData( 2, new Integer[] { 0, 1 } );
List<RowMetaAndData> ret =
TransTestFactory.executeTestTransformation( transMeta, stepName, inputList );
Assert.assertNotNull( "At least it is not null", ret );
Assert.assertEquals( "Ouput is just one row", 1, ret.size() );
RowMetaAndData rmd = ret.get( 0 );
// now take a closer look at value meta types we do have at the end:
ValueMetaInterface vmi = rmd.getValueMeta( 0 );
Assert.assertEquals( "First is usually is grouping field", ValueMetaInterface.TYPE_STRING, vmi.getType() );
Assert.assertEquals( "This is key1 field", KEY1, vmi.getName() );
vmi = rmd.getValueMeta( 1 );
Assert.assertEquals( "The next value is first aggregation", OUT1, vmi.getName() );
Assert.assertEquals( "Since it was null String output will be empty string", "", rmd.getData()[1] );
vmi = rmd.getValueMeta( 2 );
Assert.assertEquals( "Third field is second output field", OUT2, vmi.getName() );
// TODO fix it for GroupBy or MemoryGroupBy
/*
* Assert.assertEquals( "This is a bug of MemoryGroupBy - memory group by returns Double, while" +
* "GroupBy returns Long. So this test will fail here", 0L, rmd .getData()[2] );
*/
vmi = rmd.getValueMeta( 3 );
Assert.assertEquals( "4 is 3 output field", OUT3, vmi.getName() );
Assert.assertEquals( "And since it was null it become correct 0", 0.0, rmd.getData()[3] );
// TODO fix Memory Group By. Waiting for clarification.
/*vmi = rmd.getValueMeta( 4 );
Assert.assertEquals( "For this case we have silent BigDecimal to Double conversion that can"
+ " lead to loss of accuracy. This is serious issue and we can't just ignore it.", BigDecimal.class, rmd
.getData()[4].getClass() );
Assert.assertEquals( "And the last one is null which becomes 0 BigNumber", new BigDecimal( 0 ),
rmd.getData()[4] );*/
}
}