/*! ******************************************************************************
*
* Pentaho Data Integration
*
* 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.mysqlbulkloader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.Before;
import org.junit.BeforeClass;
import org.mockito.Mockito;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.database.MySQLDatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleXMLException;
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.ValueMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaNumber;
import org.pentaho.di.core.row.value.ValueMetaPluginType;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.xml.XMLHandler;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.metastore.api.IMetaStore;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class MySQLBulkLoaderTest {
MySQLBulkLoaderMeta lmeta;
MySQLBulkLoaderData ldata;
MySQLBulkLoader lder;
StepMeta smeta;
@BeforeClass
public static void initEnvironment() throws Exception {
KettleEnvironment.init();
}
@Before
public void setUp() {
TransMeta transMeta = new TransMeta();
transMeta.setName( "MysqlBulkLoader" );
Map<String, String> vars = new HashMap<String, String>();
vars.put( "delim", "," );
vars.put( "enclos", "'" );
vars.put( "charset", "UTF8" );
vars.put( "tbl", "sometable" );
vars.put( "schema", "someschema" );
transMeta.injectVariables( vars );
MySQLDatabaseMeta mysql = new MySQLDatabaseMeta();
mysql.setName( "MySQL" );
DatabaseMeta dbMeta = new DatabaseMeta();
dbMeta.setDatabaseInterface( mysql );
dbMeta.setQuoteAllFields( true );
lmeta = new MySQLBulkLoaderMeta();
lmeta.setDelimiter( "${delim}" );
lmeta.setEnclosure( "${enclos}" );
lmeta.setEncoding( "${charset}" );
lmeta.setTableName( "${tbl}" );
lmeta.setSchemaName( "${schema}" );
lmeta.setDatabaseMeta( dbMeta );
ldata = new MySQLBulkLoaderData();
PluginRegistry plugReg = PluginRegistry.getInstance();
String mblPid = plugReg.getPluginId( StepPluginType.class, lmeta );
smeta = new StepMeta( mblPid, "MySqlBulkLoader", lmeta );
Trans trans = new Trans( transMeta );
transMeta.addStep( smeta );
lder = new MySQLBulkLoader( smeta, ldata, 1, transMeta, trans );
lder.copyVariablesFrom( transMeta );
}
@Test
public void testFieldFormatType() throws KettleXMLException {
MySQLBulkLoaderMeta lm = new MySQLBulkLoaderMeta();
Document document = XMLHandler.loadXMLFile( this.getClass().getResourceAsStream( "step.xml" ) );
IMetaStore metastore = null;
Node stepNode = (Node) document.getDocumentElement();
lm.loadXML( stepNode, Collections.EMPTY_LIST, metastore );
int[] codes = lm.getFieldFormatType();
Assert.assertEquals( 3, codes[0] );
Assert.assertEquals( 4, codes[1] );
}
@Test
public void testVariableSubstitution() throws KettleException {
lder.init( lmeta, ldata );
String is = null;
is = new String( ldata.quote );
Assert.assertEquals( "'", is );
is = new String( ldata.separator );
Assert.assertEquals( ",", is );
Assert.assertEquals( "UTF8", ldata.bulkTimestampMeta.getStringEncoding() );
Assert.assertEquals( "UTF8", ldata.bulkDateMeta.getStringEncoding() );
Assert.assertEquals( "UTF8", ldata.bulkNumberMeta.getStringEncoding() );
Assert.assertEquals( "`someschema`.`sometable`", ldata.schemaTable );
}
@Test
public void testEscapeCharacters() throws KettleException, IOException {
PluginRegistry.addPluginType( ValueMetaPluginType.getInstance() );
PluginRegistry.init( true );
MySQLBulkLoader loader;
MySQLBulkLoaderData ld = new MySQLBulkLoaderData();
MySQLBulkLoaderMeta lm = new MySQLBulkLoaderMeta();
TransMeta transMeta = new TransMeta();
transMeta.setName( "loader" );
PluginRegistry plugReg = PluginRegistry.getInstance();
String loaderPid = plugReg.getPluginId( StepPluginType.class, lm );
StepMeta stepMeta = new StepMeta( loaderPid, "loader", lm );
Trans trans = new Trans( transMeta );
transMeta.addStep( stepMeta );
trans.setRunning( true );
loader = Mockito.spy( new MySQLBulkLoader( stepMeta, ld, 1, transMeta, trans ) );
RowMeta rm = new RowMeta();
ValueMetaString vm = new ValueMetaString( "I don't want NPE!" );
rm.addValueMeta( vm );
RowMeta spyRowMeta = Mockito.spy( new RowMeta() );
Mockito.when( spyRowMeta.getValueMeta( Mockito.anyInt() ) ).thenReturn( vm );
loader.setInputRowMeta( spyRowMeta );
MySQLBulkLoaderMeta smi = new MySQLBulkLoaderMeta();
smi.setFieldStream( new String[] { "Test" } );
smi.setFieldFormatType( new int[] { MySQLBulkLoaderMeta.FIELD_FORMAT_TYPE_STRING_ESCAPE } );
smi.setEscapeChar( "\\" );
smi.setEnclosure( "\"" );
smi.setDatabaseMeta( Mockito.mock( DatabaseMeta.class ) );
MySQLBulkLoaderData sdi = new MySQLBulkLoaderData();
sdi.keynrs = new int[1];
sdi.keynrs[0] = 0;
sdi.fifoStream = Mockito.mock( OutputStream.class );
loader.init( smi, sdi );
loader.first = false;
Mockito.when( loader.getRow() ).thenReturn( new String[] { "test\"Escape\\" } );
loader.processRow( smi, sdi );
Mockito.verify( sdi.fifoStream, Mockito.times( 1 ) ).write( "test\\\"Escape\\\\".getBytes() );
}
/**
* Default conversion mask for Number column type should be calculated according to length and precision.
* For example, for type NUMBER(6,3) conversion mask should be: " #000.000;-#000.000"
*/
@Test
public void testNumberFormatting() throws KettleException, IOException {
PluginRegistry.addPluginType( ValueMetaPluginType.getInstance() );
PluginRegistry.init( true );
MySQLBulkLoader loader;
MySQLBulkLoaderData ld = new MySQLBulkLoaderData();
MySQLBulkLoaderMeta lm = new MySQLBulkLoaderMeta();
TransMeta transMeta = new TransMeta();
transMeta.setName( "loader" );
PluginRegistry plugReg = PluginRegistry.getInstance();
String loaderPid = plugReg.getPluginId( StepPluginType.class, lm );
StepMeta stepMeta = new StepMeta( loaderPid, "loader", lm );
Trans trans = new Trans( transMeta );
transMeta.addStep( stepMeta );
trans.setRunning( true );
loader = Mockito.spy( new MySQLBulkLoader( stepMeta, ld, 1, transMeta, trans ) );
RowMeta rm = new RowMeta();
ValueMetaNumber vm = new ValueMetaNumber( "Test" );
rm.addValueMeta( vm );
RowMeta spyRowMeta = Mockito.spy( new RowMeta() );
Mockito.when( spyRowMeta.getValueMeta( Mockito.anyInt() ) ).thenReturn( vm );
loader.setInputRowMeta( spyRowMeta );
MySQLBulkLoaderMeta smi = new MySQLBulkLoaderMeta();
smi.setFieldStream( new String[] { "Test" } );
smi.setFieldFormatType( new int[] { MySQLBulkLoaderMeta.FIELD_FORMAT_TYPE_OK } );
smi.setDatabaseMeta( Mockito.mock( DatabaseMeta.class ) );
ValueMetaNumber vmn = new ValueMetaNumber( "Test" );
vmn.setLength( 6, 3 );
MySQLBulkLoaderData sdi = new MySQLBulkLoaderData();
sdi.keynrs = new int[1];
sdi.keynrs[0] = 0;
sdi.fifoStream = Mockito.mock( OutputStream.class );
sdi.bulkFormatMeta = new ValueMetaInterface[] { vmn };
loader.init( smi, sdi );
loader.first = false;
Mockito.when( loader.getRow() ).thenReturn( new Double[] { 1.023 } );
loader.processRow( smi, sdi );
Mockito.verify( sdi.fifoStream, Mockito.times( 1 ) ).write( " 001.023".getBytes() );
Assert.assertEquals( " #000.000;-#000.000", vmn.getDecimalFormat().toPattern() );
}
}