/*! ******************************************************************************
*
* 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.streamlookup;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.pentaho.di.core.row.ValueMetaInterface;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.pentaho.di.core.QueueRowSet;
import org.pentaho.di.core.RowSet;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.trans.step.StepIOMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.errorhandling.Stream;
import org.pentaho.di.trans.step.errorhandling.StreamIcon;
import org.pentaho.di.trans.step.errorhandling.StreamInterface;
import org.pentaho.di.trans.steps.mock.StepMockHelper;
import org.pentaho.metastore.api.IMetaStore;
/**
* Test for StreamLookup step
*
* @author Pavel Sakun
* @see StreamLookup
*/
public class StreamLookupTest {
private StepMockHelper<StreamLookupMeta, StreamLookupData> smh;
@Before
public void setUp() {
smh =
new StepMockHelper<StreamLookupMeta, StreamLookupData>( "StreamLookup", StreamLookupMeta.class,
StreamLookupData.class );
when( smh.logChannelInterfaceFactory.create( any(), any( LoggingObjectInterface.class ) ) ).thenReturn(
smh.logChannelInterface );
when( smh.trans.isRunning() ).thenReturn( true );
}
private void convertDataToBinary( Object[][] data ) {
for ( int i = 0; i < data.length; i++ ) {
for ( int j = 0; j < data[i].length; j++ ) {
data[i][j] = ( (String) data[i][j] ).getBytes();
}
}
}
private RowSet mockLookupRowSet( boolean binary ) {
final int storageType = binary ? ValueMetaInterface.STORAGE_TYPE_BINARY_STRING : ValueMetaInterface.STORAGE_TYPE_NORMAL;
Object[][] data = { { "Value1", "1" }, { "Value2", "2" } };
if ( binary ) {
convertDataToBinary( data );
}
RowSet lookupRowSet =
smh.getMockInputRowSet( data );
doReturn( "Lookup" ).when( lookupRowSet ).getOriginStepName();
doReturn( "StreamLookup" ).when( lookupRowSet ).getDestinationStepName();
RowMeta lookupRowMeta = new RowMeta();
ValueMetaString valueMeta = new ValueMetaString( "Value" );
valueMeta.setStorageType( storageType );
valueMeta.setStorageMetadata( new ValueMetaString() );
lookupRowMeta.addValueMeta( valueMeta );
ValueMetaString idMeta = new ValueMetaString( "Id" );
idMeta.setStorageType( storageType );
idMeta.setStorageMetadata( new ValueMetaString() );
lookupRowMeta.addValueMeta( idMeta );
doReturn( lookupRowMeta ).when( lookupRowSet ).getRowMeta();
return lookupRowSet;
}
private RowSet mockDataRowSet( boolean binary ) {
final int storageType = binary ? ValueMetaInterface.STORAGE_TYPE_BINARY_STRING : ValueMetaInterface.STORAGE_TYPE_NORMAL;
Object[][] data = { { "Name1", "1" }, { "Name2", "2" } };
if ( binary ) {
convertDataToBinary( data );
}
RowSet dataRowSet = smh.getMockInputRowSet( data );
RowMeta dataRowMeta = new RowMeta();
ValueMetaString valueMeta = new ValueMetaString( "Name" );
valueMeta.setStorageType( storageType );
valueMeta.setStorageMetadata( new ValueMetaString() );
dataRowMeta.addValueMeta( valueMeta );
ValueMetaString idMeta = new ValueMetaString( "Id" );
idMeta.setStorageType( storageType );
idMeta.setStorageMetadata( new ValueMetaString() );
dataRowMeta.addValueMeta( idMeta );
doReturn( dataRowMeta ).when( dataRowSet ).getRowMeta();
return dataRowSet;
}
private StreamLookupMeta mockProcessRowMeta( boolean memoryPreservationActive ) throws KettleStepException {
StreamLookupMeta meta = smh.processRowsStepMetaInterface;
StepMeta lookupStepMeta = when( mock( StepMeta.class ).getName() ).thenReturn( "Lookup" ).getMock();
doReturn( lookupStepMeta ).when( smh.transMeta ).findStep( "Lookup" );
StepIOMeta stepIOMeta = new StepIOMeta( true, true, false, false, false, false );
stepIOMeta.addStream( new Stream( StreamInterface.StreamType.INFO, lookupStepMeta, null, StreamIcon.INFO, null ) );
doReturn( stepIOMeta ).when( meta ).getStepIOMeta();
doReturn( new String[] { "Id" } ).when( meta ).getKeylookup();
doReturn( new String[] { "Id" } ).when( meta ).getKeystream();
doReturn( new String[] { "Value" } ).when( meta ).getValue();
doReturn( memoryPreservationActive ).when( meta ).isMemoryPreservationActive();
doReturn( false ).when( meta ).isUsingSortedList();
doReturn( false ).when( meta ).isUsingIntegerPair();
doReturn( new int[] { -1 } ).when( meta ).getValueDefaultType();
doReturn( new String[] { "" } ).when( meta ).getValueDefault();
doReturn( new String[] { "Value" } ).when( meta ).getValueName();
doReturn( new String[] { "Value" } ).when( meta ).getValue();
doCallRealMethod().when( meta ).getFields( any( RowMetaInterface.class ), anyString(), any( RowMetaInterface[].class ), any( StepMeta.class ),
any( VariableSpace.class ), any( Repository.class ), any( IMetaStore.class ) );
return meta;
}
private void doTest( boolean memoryPreservationActive, boolean binaryLookupStream, boolean binaryDataStream ) throws KettleException {
StreamLookup step = new StreamLookup( smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans );
step.init( smh.initStepMetaInterface, smh.initStepDataInterface );
step.getInputRowSets().add( mockLookupRowSet( binaryLookupStream ) );
step.getInputRowSets().add( mockDataRowSet( binaryDataStream ) );
step.getOutputRowSets().add( new QueueRowSet() );
StreamLookupMeta meta = mockProcessRowMeta( memoryPreservationActive );
StreamLookupData data = new StreamLookupData();
data.readLookupValues = true;
RowSet outputRowSet = step.getOutputRowSets().get( 0 );
// Process rows and collect output
int rowNumber = 0;
String[] expectedOutput = { "Name", "", "Value" };
while ( step.processRow( meta, data ) ) {
Object[] rowData = outputRowSet.getRow();
if ( rowData != null ) {
RowMetaInterface rowMeta = outputRowSet.getRowMeta();
Assert.assertEquals( "Output row is of wrong size", 3, rowMeta.size() );
rowNumber++;
// Verify output
for ( int valueIndex = 0; valueIndex < rowMeta.size(); valueIndex++ ) {
String expectedValue = expectedOutput[valueIndex] + rowNumber;
Object actualValue = rowMeta.getValueMeta( valueIndex ).convertToNormalStorageType( rowData[valueIndex] );
Assert.assertEquals( "Unexpected value at row " + rowNumber + " position " + valueIndex, expectedValue,
actualValue );
}
}
}
Assert.assertEquals( "Incorrect output row number", 2, rowNumber );
}
@Test
public void testWithNormalStreams() throws KettleException {
doTest( false, false, false );
}
@Test
public void testWithBinaryLookupStream() throws KettleException {
doTest( false, true, false );
}
@Test
public void testWithBinaryDateStream() throws KettleException {
doTest( false, false, true );
}
@Test
public void testWithBinaryStreams() throws KettleException {
doTest( false, false, true );
}
@Test
public void testMemoryPreservationWithNormalStreams() throws KettleException {
doTest( true, false, false );
}
@Test
public void testMemoryPreservationWithBinaryLookupStream() throws KettleException {
doTest( true, true, false );
}
@Test
public void testMemoryPreservationWithBinaryDateStream() throws KettleException {
doTest( true, false, true );
}
@Test
public void testMemoryPreservationWithBinaryStreams() throws KettleException {
doTest( true, false, true );
}
}