/*! ******************************************************************************
*
* 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.mailinput;
import org.mockito.AdditionalMatchers;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.regex.Pattern;
import javax.mail.Address;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import org.apache.commons.lang.StringUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.core.row.RowDataUtil;
import org.pentaho.di.job.entries.getpop.MailConnection;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.steps.mailinput.MailInput.MessageParser;
import org.pentaho.di.trans.steps.mock.StepMockHelper;
public class ParseMailInputTest {
// mock is existed per-class instance loaded by junit loader
private static StepMockHelper<MailInputMeta, StepDataInterface> stepMockHelper;
// test data
public static final int MSG_NUMB = 3;
public static final String MSG_BODY = "msg_body";
public static final String FLD_NAME = "junit_folder";
public static final int ATTCH_COUNT = 3;
public static final String CNTNT_TYPE = "text/html";
public static final String FROM1 = "localhost_1";
public static final String FROM2 = "localhost_2";
public static final String REP1 = "127.0.0.1";
public static final String REP2 = "127.0.0.2";
public static final String REC1 = "Vasily";
public static final String REC2 = "Pupkin";
public static final String SUBJ = "mocktest";
public static final String DESC = "desc";
public static final Date DATE1 = new Date( 0 );
public static final Date DATE2 = new Date( 60000 );
public static final String CNTNT_TYPE_EMAIL = "application/acad";
public static int CNTNT_SIZE = 23;
public static String HDR_EX1 = "header_ex1";
public static String HDR_EX1V = "header_ex1_value";
public static String HDR_EX2 = "header_ex2";
public static String HDR_EX2V = "header_ex2_value";
// this objects re-created for every test method
private Message message;
private MailInputData data;
private MailInputMeta meta;
private MailInput mailInput;
@BeforeClass
public static void setup() {
stepMockHelper =
new StepMockHelper<MailInputMeta, StepDataInterface>(
"ABORT TEST", MailInputMeta.class, StepDataInterface.class );
when( stepMockHelper.logChannelInterfaceFactory.create( any(), any( LoggingObjectInterface.class ) ) )
.thenReturn( stepMockHelper.logChannelInterface );
when( stepMockHelper.trans.isRunning() ).thenReturn( true );
}
@AfterClass
public static void tearDown() {
stepMockHelper.cleanUp();
}
@Before
public void beforeTest() throws MessagingException, IOException, KettleException {
message = Mockito.mock( Message.class );
MailConnection conn = mock( MailConnection.class );
when( conn.getMessageBody( any( Message.class ) ) ).thenReturn( MSG_BODY );
when( conn.getFolderName() ).thenReturn( FLD_NAME );
when( conn.getAttachedFilesCount( any( Message.class ), any( Pattern.class ) ) ).thenReturn( ATTCH_COUNT );
when( conn.getMessageBodyContentType( any( Message.class ) ) ).thenReturn( CNTNT_TYPE );
data = mock( MailInputData.class );
data.mailConn = conn;
mailInput = new MailInput( stepMockHelper.stepMeta, data, 0, stepMockHelper.transMeta, stepMockHelper.trans );
Address addrFrom1 = mock( Address.class );
when( addrFrom1.toString() ).thenReturn( FROM1 );
Address addrFrom2 = mock( Address.class );
when( addrFrom2.toString() ).thenReturn( FROM2 );
Address addrRep1 = mock( Address.class );
when( addrRep1.toString() ).thenReturn( REP1 );
Address addrRep2 = mock( Address.class );
when( addrRep2.toString() ).thenReturn( REP2 );
Address allRec1 = mock( Address.class );
when( allRec1.toString() ).thenReturn( REC1 );
Address allRec2 = mock( Address.class );
when( allRec2.toString() ).thenReturn( REC2 );
Address[] adrFr = { addrFrom1, addrFrom2 };
Address[] adrRep = { addrRep1, addrRep2 };
Address[] adrRecip = { allRec1, allRec2 };
message = Mockito.mock( Message.class );
when( message.getMessageNumber() ).thenReturn( MSG_NUMB );
when( message.getSubject() ).thenReturn( SUBJ );
when( message.getFrom() ).thenReturn( adrFr );
when( message.getReplyTo() ).thenReturn( adrRep );
when( message.getAllRecipients() ).thenReturn( adrRecip );
when( message.getDescription() ).thenReturn( DESC );
when( message.getReceivedDate() ).thenReturn( DATE1 );
when( message.getSentDate() ).thenReturn( DATE2 );
when( message.getContentType() ).thenReturn( CNTNT_TYPE_EMAIL );
when( message.getSize() ).thenReturn( CNTNT_SIZE );
Header ex1 = new Header( HDR_EX1, HDR_EX1V );
Header ex2 = new Header( HDR_EX2, HDR_EX2V );
// for fixed [PDI-6532]
when( message.getMatchingHeaders( AdditionalMatchers.aryEq( new String[] { HDR_EX1 } ) ) ).thenReturn(
getEnum( new Header[] { ex1 } ) );
when( message.getMatchingHeaders( AdditionalMatchers.aryEq( new String[] { HDR_EX2 } ) ) ).thenReturn(
getEnum( new Header[] { ex2 } ) );
when( message.getMatchingHeaders( AdditionalMatchers.aryEq( new String[] { HDR_EX1, HDR_EX2 } ) ) ).thenReturn(
getEnum( new Header[] { ex1, ex2 } ) );
// for previous implementation
when( message.getHeader( eq( HDR_EX1 ) ) ).thenReturn( new String[] { ex1.getValue() } );
when( message.getHeader( eq( HDR_EX2 ) ) ).thenReturn( new String[] { ex2.getValue() } );
}
/**
* [PDI-6532] When mail header is found returns his actual value.
*
* @throws Exception
* @throws KettleException
*/
@Test
public void testHeadersParsedPositive() throws Exception {
// add expected fields:
int[] fields = { MailInputField.COLUMN_HEADER };
MailInputField[] farr = this.getDefaultInputFields( fields );
// points to existed header
farr[0].setName( HDR_EX1 );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Header is correct", HDR_EX1V, String.class.cast( r[0] ) );
}
/**
* [PDI-6532] When mail header is not found returns empty String
*
* @throws Exception
*
*/
@Test
public void testHeadersParsedNegative() throws Exception {
int[] fields = { MailInputField.COLUMN_HEADER };
MailInputField[] farr = this.getDefaultInputFields( fields );
farr[0].setName( HDR_EX1 + "salt" );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Header is correct", "", String.class.cast( r[0] ) );
}
/**
* Test, message number can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageNumberIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_MESSAGE_NR };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message number is correct", new Long( MSG_NUMB ), Long.class.cast( r[0] ) );
}
/**
* Test message subject can be parsed
*
* @throws Exception
*/
@Test
public void testMessageSubjectIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_SUBJECT };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message subject is correct", SUBJ, String.class.cast( r[0] ) );
}
/**
* Test message From can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageFromIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_SENDER };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
// expect, that from is concatenated with ';'
String expected = StringUtils.join( new String[] { FROM1, FROM2 }, ";" );
Assert.assertEquals( "Message From is correct", expected, String.class.cast( r[0] ) );
}
/**
* Test message ReplayTo can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageReplayToIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_REPLY_TO };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
// is concatenated with ';'
String expected = StringUtils.join( new String[] { REP1, REP2 }, ";" );
Assert.assertEquals( "Message ReplayTo is correct", expected, String.class.cast( r[0] ) );
}
/**
* Test message recipients can be parsed
*
* @throws Exception
*/
@Test
public void testMessageRecipientsIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_RECIPIENTS };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
// is concatenated with ';'
String expected = StringUtils.join( new String[] { REC1, REC2 }, ";" );
Assert.assertEquals( "Message Recipients is correct", expected, String.class.cast( r[0] ) );
}
/**
* Test message description is correct
*
* @throws Exception
*/
@Test
public void testMessageDescriptionIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_DESCRIPTION };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Description is correct", DESC, String.class.cast( r[0] ) );
}
/**
* Test message received date is correct
*
* @throws Exception
*/
@Test
public void testMessageRecivedDateIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_RECEIVED_DATE };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Recived date is correct", DATE1, Date.class.cast( r[0] ) );
}
/**
* Test message sent date is correct
*
* @throws Exception
*/
@Test
public void testMessageSentDateIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_SENT_DATE };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Sent date is correct", DATE2, Date.class.cast( r[0] ) );
}
/**
* Message content type is correct
*
* @throws Exception
*/
@Test
public void testMessageContentTypeIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_CONTENT_TYPE };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Content type is correct", CNTNT_TYPE_EMAIL, String.class.cast( r[0] ) );
}
/**
* Test message size is correct
*
* @throws Exception
*/
@Test
public void testMessageSizeIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_SIZE };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Size is correct", new Long( CNTNT_SIZE ), Long.class.cast( r[0] ) );
}
/**
* Test that message body can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageBodyIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_BODY };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Body is correct", MSG_BODY, String.class.cast( r[0] ) );
}
/**
* Test that message folder name can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageFolderNameIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_FOLDER_NAME };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Folder Name is correct", FLD_NAME, String.class.cast( r[0] ) );
}
/**
* Test that message folder name can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageAttachedFilesCountNameIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_ATTACHED_FILES_COUNT };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message Attached files count is correct", new Long( ATTCH_COUNT ), Long.class
.cast( r[0] ) );
}
/**
* Test that message body content type can be parsed correctly
*
* @throws Exception
*/
@Test
public void testMessageBodyContentTypeIsParsed() throws Exception {
int[] fields = { MailInputField.COLUMN_BODY_CONTENT_TYPE };
MailInputField[] farr = this.getDefaultInputFields( fields );
this.mockMailInputMeta( farr );
try {
mailInput.processRow( meta, data );
} catch ( KettleException e ) {
// don't worry about it
}
MessageParser underTest = mailInput.new MessageParser();
Object[] r = RowDataUtil.allocateRowData( data.nrFields );
underTest.parseToArray( r, message );
Assert.assertEquals( "Message body content type is correct", CNTNT_TYPE, String.class.cast( r[0] ) );
}
private void mockMailInputMeta( MailInputField[] arr ) {
data.nrFields = arr.length;
meta = mock( MailInputMeta.class );
when( meta.getInputFields() ).thenReturn( arr );
}
private MailInputField[] getDefaultInputFields( int[] arr ) {
MailInputField[] fields = new MailInputField[arr.length];
for ( int i = 0; i < arr.length; i++ ) {
fields[i] = new MailInputField();
fields[i].setColumn( arr[i] );
fields[i].setName( MailInputField.getColumnDesc( arr[i] ) );
}
return fields;
}
private Enumeration<?> getEnum( Header[] headers ) {
return Collections.enumeration( Arrays.asList( headers ) );
}
}