/*
* ******************************************************************************
*
* Copyright (C) 2002-2015 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.getxmldata;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.pentaho.di.core.exception.KettleValueException;
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.TransMeta;
import org.pentaho.di.trans.step.BaseStepMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.dictionary.DictionaryConst;
import org.pentaho.metaverse.api.IAnalysisContext;
import org.pentaho.metaverse.api.IComponentDescriptor;
import org.pentaho.metaverse.api.IMetaverseBuilder;
import org.pentaho.metaverse.api.IMetaverseNode;
import org.pentaho.metaverse.api.INamespace;
import org.pentaho.metaverse.api.MetaverseComponentDescriptor;
import org.pentaho.metaverse.api.MetaverseObjectFactory;
import org.pentaho.metaverse.api.StepField;
import org.pentaho.metaverse.api.analyzer.kettle.ComponentDerivationRecord;
import org.pentaho.metaverse.api.analyzer.kettle.step.ExternalResourceStepAnalyzer;
import org.pentaho.metaverse.api.analyzer.kettle.step.StepNodes;
import org.pentaho.metaverse.api.model.IExternalResourceInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* Created by mburgess on 4/24/15.
*/
@RunWith( MockitoJUnitRunner.class )
public class GetXMLDataStepAnalyzerTest {
GetXMLDataStepAnalyzer analyzer;
@Mock GetXMLDataMeta meta;
@Mock INamespace mockNamespace;
@Mock IMetaverseNode node;
@Mock IMetaverseBuilder builder;
@Mock TransMeta parentTransMeta;
@Mock StepMeta parentStepMeta;
@Mock RowMetaInterface rmi;
@Mock GetXMLData data;
IComponentDescriptor descriptor;
static MetaverseObjectFactory metaverseObjectFactory = new MetaverseObjectFactory();
@Before
public void setUp() throws Exception {
when( mockNamespace.getParentNamespace() ).thenReturn( mockNamespace );
descriptor = new MetaverseComponentDescriptor( "test", DictionaryConst.NODE_TYPE_TRANS_STEP, mockNamespace );
analyzer = spy( new GetXMLDataStepAnalyzer() );
analyzer.setDescriptor( descriptor );
analyzer.setObjectFactory( metaverseObjectFactory );
analyzer.setRootNode( node );
analyzer.setParentTransMeta( parentTransMeta );
analyzer.setParentStepMeta( parentStepMeta );
}
@Test
public void testGetResourceInputNodeType() throws Exception {
assertEquals( DictionaryConst.NODE_TYPE_FILE_FIELD, analyzer.getResourceInputNodeType() );
}
@Test
public void testGetResourceOutputNodeType() throws Exception {
assertNull( analyzer.getResourceOutputNodeType() );
}
@Test
public void testIsOutput() throws Exception {
assertFalse( analyzer.isOutput() );
}
@Test
public void testIsInput() throws Exception {
assertTrue( analyzer.isInput() );
}
@Test
public void testGetSupportedSteps() {
GetXMLDataStepAnalyzer analyzer = new GetXMLDataStepAnalyzer();
Set<Class<? extends BaseStepMeta>> types = analyzer.getSupportedSteps();
assertNotNull( types );
assertEquals( types.size(), 1 );
assertTrue( types.contains( GetXMLDataMeta.class ) );
}
@Test
public void testGetUsedFields_xmlNotInField() throws Exception {
when( meta.isInFields() ).thenReturn( false );
Set<StepField> usedFields = analyzer.getUsedFields( meta );
assertEquals( 0, usedFields.size() );
}
@Test
public void testGetUsedFields() throws Exception {
when( meta.isInFields() ).thenReturn( true );
when( meta.getXMLField() ).thenReturn( "xml" );
StepNodes inputs = new StepNodes();
inputs.addNode( "previousStep", "xml", node );
inputs.addNode( "previousStep", "otherField", node );
doReturn( inputs ).when( analyzer ).getInputs();
Set<StepField> usedFields = analyzer.getUsedFields( meta );
assertEquals( 1, usedFields.size() );
assertEquals( "xml", usedFields.iterator().next().getFieldName() );
}
@Test
public void testCreateResourceNode() throws Exception {
IExternalResourceInfo res = mock( IExternalResourceInfo.class );
when( res.getName() ).thenReturn( "file:///Users/home/tmp/xyz.xml" );
IMetaverseNode resourceNode = analyzer.createResourceNode( res );
assertNotNull( resourceNode );
assertEquals( DictionaryConst.NODE_TYPE_FILE, resourceNode.getType() );
}
@Test
public void testCreateOutputFieldNode() throws Exception {
doReturn( builder ).when( analyzer ).getMetaverseBuilder();
analyzer.setBaseStepMeta( meta );
GetXMLDataField[] fields = new GetXMLDataField[2];
GetXMLDataField field1 = new GetXMLDataField( "name" );
GetXMLDataField field2 = new GetXMLDataField( "age" );
field1.setXPath( "field1/xpath" );
field2.setElementType( 1 );
field1.setResultType( 1 );
field2.setRepeated( true );
fields[0] = field1;
fields[1] = field2;
when( meta.getInputFields() ).thenReturn( fields );
IAnalysisContext context = mock( IAnalysisContext.class );
doReturn( "thisStepName" ).when( analyzer ).getStepName();
when( node.getLogicalId() ).thenReturn( "logical id" );
ValueMetaInterface vmi = new ValueMeta( "name", 1 );
IMetaverseNode outputFieldNode = analyzer.createOutputFieldNode(
context,
vmi,
ExternalResourceStepAnalyzer.RESOURCE,
DictionaryConst.NODE_TYPE_TRANS_FIELD );
assertNotNull( outputFieldNode );
assertNotNull( outputFieldNode.getProperty( DictionaryConst.PROPERTY_KETTLE_TYPE ) );
assertEquals( ExternalResourceStepAnalyzer.RESOURCE,
outputFieldNode.getProperty( DictionaryConst.PROPERTY_TARGET_STEP ) );
assertEquals( "field1/xpath", outputFieldNode.getProperty( "xpath" ) );
assertNotNull( outputFieldNode.getProperty( "resultType" ) );
assertNotNull( outputFieldNode.getProperty( "element" ) );
assertEquals( false, outputFieldNode.getProperty( "repeat" ) );
// the input node should be added by this step
verify( builder ).addNode( outputFieldNode );
}
@Test
public void testGetInputRowMetaInterfaces_isInFields() throws Exception {
when( parentTransMeta.getPrevStepNames( parentStepMeta ) ).thenReturn( null );
RowMetaInterface rowMetaInterface = mock( RowMetaInterface.class );
doReturn( rowMetaInterface ).when( analyzer ).getOutputFields( meta );
when( meta.isInFields() ).thenReturn( true );
when( meta.getIsAFile() ).thenReturn( false );
when( meta.isReadUrl() ).thenReturn( false );
Map<String, RowMetaInterface> rowMetaInterfaces = analyzer.getInputRowMetaInterfaces( meta );
assertNotNull( rowMetaInterfaces );
assertEquals( 0, rowMetaInterfaces.size() );
}
@Test
public void testGetInputRowMetaInterfaces_isNotInField() throws Exception {
Map<String, RowMetaInterface> inputs = new HashMap<>();
RowMetaInterface inputRmi = mock( RowMetaInterface.class );
List<ValueMetaInterface> vmis = new ArrayList<>();
ValueMetaInterface vmi = new ValueMeta( "filename" );
vmis.add( vmi );
when( inputRmi.getValueMetaList() ).thenReturn( vmis );
inputs.put( "test", inputRmi );
doReturn( inputs ).when( analyzer ).getInputFields( meta );
when( parentTransMeta.getPrevStepNames( parentStepMeta ) ).thenReturn( null );
RowMetaInterface rowMetaInterface = new RowMeta();
rowMetaInterface.addValueMeta( vmi );
ValueMetaInterface vmi2 = new ValueMeta( "otherField" );
rowMetaInterface.addValueMeta( vmi2 );
doReturn( rowMetaInterface ).when( analyzer ).getOutputFields( meta );
when( meta.isInFields() ).thenReturn( false );
when( meta.getIsAFile() ).thenReturn( false );
when( meta.isReadUrl() ).thenReturn( false );
Map<String, RowMetaInterface> rowMetaInterfaces = analyzer.getInputRowMetaInterfaces( meta );
assertNotNull( rowMetaInterfaces );
assertEquals( 2, rowMetaInterfaces.size() );
RowMetaInterface metaInterface = rowMetaInterfaces.get( ExternalResourceStepAnalyzer.RESOURCE );
// the row meta interface should only have 1 value meta in it, and it should NOT be filename
assertEquals( 1, metaInterface.size() );
assertEquals( "otherField", metaInterface.getFieldNames()[0] );
}
@Test
public void testGetChangeRecords() throws Exception {
when( meta.isInFields() ).thenReturn( true );
when( meta.getIsAFile() ).thenReturn( false );
when( meta.isReadUrl() ).thenReturn( false );
when( meta.getXMLField() ).thenReturn( "xml" );
analyzer.setBaseStepMeta( meta );
GetXMLDataField[] fields = new GetXMLDataField[2];
GetXMLDataField field1 = new GetXMLDataField( "name" );
GetXMLDataField field2 = new GetXMLDataField( "age" );
field1.setXPath( "field1/xpath" );
field2.setElementType( 1 );
field1.setResultType( 1 );
field2.setRepeated( true );
fields[0] = field1;
fields[1] = field2;
when( meta.getInputFields() ).thenReturn( fields );
StepNodes inputs = new StepNodes();
inputs.addNode( "previousStep", "xml", node );
doReturn( inputs ).when( analyzer ).getInputs();
Set<ComponentDerivationRecord> changeRecords = analyzer.getChangeRecords( meta );
assertNotNull( changeRecords );
assertEquals( 2, changeRecords.size() );
}
@Test
public void testCustomAnalyze() throws Exception {
when( meta.getLoopXPath() ).thenReturn( "file/xpath/name" );
analyzer.customAnalyze( meta, node );
verify( node ).setProperty( "loopXPath", "file/xpath/name" );
}
@Test
public void testGetXMLDataExternalResourceConsumer() throws Exception {
GetXMLDataExternalResourceConsumer consumer = new GetXMLDataExternalResourceConsumer();
StepMeta spyMeta = spy( new StepMeta( "test", meta ) );
when( meta.getParentStepMeta() ).thenReturn( spyMeta );
when( spyMeta.getParentTransMeta() ).thenReturn( parentTransMeta );
when( data.getStepMetaInterface() ).thenReturn( meta );
when( meta.isInFields() ).thenReturn( false );
String[] filePaths = { "/path/to/file1", "/another/path/to/file2" };
when( meta.getFileName() ).thenReturn( filePaths );
when( parentTransMeta.environmentSubstitute( any( String[].class ) ) ).thenReturn( filePaths );
assertFalse( consumer.isDataDriven( meta ) );
Collection<IExternalResourceInfo> resources = consumer.getResourcesFromMeta( meta );
assertFalse( resources.isEmpty() );
assertEquals( 2, resources.size() );
when( meta.isInFields() ).thenReturn( true );
when( meta.getIsAFile() ).thenReturn( true );
assertTrue( consumer.isDataDriven( meta ) );
assertTrue( consumer.getResourcesFromMeta( meta ).isEmpty() );
when( rmi.getString( Mockito.any( Object[].class ), anyString(), anyString() ) )
.thenReturn( "/path/to/row/file" );
resources = consumer.getResourcesFromRow( data, rmi, new String[]{ "id", "name" } );
assertFalse( resources.isEmpty() );
assertEquals( 1, resources.size() );
when( rmi.getString( Mockito.any( Object[].class ), anyString(), anyString() ) )
.thenThrow( new KettleValueException() );
resources = consumer.getResourcesFromRow( data, rmi, new String[]{ "id", "name" } );
assertTrue( resources.isEmpty() );
assertEquals( GetXMLDataMeta.class, consumer.getMetaClass() );
}
}