/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 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.repository;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import junit.framework.Assert;
import org.apache.commons.vfs2.FileObject;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.pentaho.di.core.ProgressMonitorListener;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.imp.ImportRules;
import org.pentaho.di.imp.rule.ImportRuleInterface;
import org.pentaho.di.imp.rules.JobHasDescriptionImportRule;
import org.pentaho.di.imp.rules.TransformationHasDescriptionImportRule;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.utils.TestUtils;
import org.xml.sax.InputSource;
public class RepositoryExporterTest {
@Mock
Repository repository;
@Mock
LogChannelInterface log;
@Mock
private RepositoryDirectoryInterface root;
private FileObject fileObject;
private String xmlFileName;
@Before
public void beforeTest() throws IOException, KettleException {
MockitoAnnotations.initMocks( this );
Mockito.when( repository.getLog() ).thenReturn( log );
ObjectId id = new ObjectId() {
@Override
public String getId() {
return "1";
}
};
Mockito.when( root.getDirectoryIDs() ).thenReturn( new ObjectId[] { id } );
Mockito.when( root.findDirectory( Mockito.any( ObjectId.class ) ) ).thenReturn( root );
Mockito.when( repository.getJobNames( Mockito.any( ObjectId.class ), Mockito.anyBoolean() ) ).thenReturn(
new String[] { "job1" } );
Mockito.when( repository.getTransformationNames( Mockito.any( ObjectId.class ), Mockito.anyBoolean() ) )
.thenReturn( new String[] { "trans1" } );
Mockito.when( root.getPath() ).thenReturn( "path" );
// here we are stubbing load jobs from repository
Answer<JobMeta> jobLoader = new Answer<JobMeta>() {
@Override
public JobMeta answer( InvocationOnMock invocation ) throws Throwable {
String jobName = String.class.cast( invocation.getArguments()[ 0 ] );
JobMeta jobMeta = Mockito.mock( JobMeta.class );
Mockito.when( jobMeta.getXML() ).thenReturn( "<" + jobName + ">" + "found" + "</" + jobName + ">" );
Mockito.when( jobMeta.getName() ).thenReturn( jobName );
return jobMeta;
}
};
Mockito.when(
repository.loadJob( Mockito.anyString(), Mockito.any( RepositoryDirectoryInterface.class ), Mockito
.any( ProgressMonitorListener.class ), Mockito.anyString() ) ).thenAnswer( jobLoader );
// and this is for transformation load
Answer<TransMeta> transLoader = new Answer<TransMeta>() {
@Override
public TransMeta answer( InvocationOnMock invocation ) throws Throwable {
String transName = String.class.cast( invocation.getArguments()[ 0 ] );
TransMeta transMeta = Mockito.mock( TransMeta.class );
Mockito.when( transMeta.getXML() ).thenReturn( "<" + transName + ">" + "found" + "</" + transName + ">" );
Mockito.when( transMeta.getName() ).thenReturn( transName );
return transMeta;
}
};
Mockito.when(
repository.loadTransformation( Mockito.anyString(), Mockito.any( RepositoryDirectoryInterface.class ), Mockito
.any( ProgressMonitorListener.class ), Mockito.anyBoolean(), Mockito.anyString() ) ).thenAnswer( transLoader );
// export file
xmlFileName = TestUtils.createRamFile( getClass().getSimpleName() + "/export.xml" );
fileObject = TestUtils.getFileObject( xmlFileName );
}
/**
* Test that jobs can be exported with feedback
*
* @throws Exception
*/
@Test
public void testExportJobsWithFeedback() throws Exception {
RepositoryExporter exporter = new RepositoryExporter( repository );
List<ExportFeedback> feedback =
exporter.exportAllObjectsWithFeedback( null, xmlFileName, root, RepositoryExporter.ExportType.JOBS.toString() );
Assert.assertEquals( "Feedback contains all items recorded", 2, feedback.size() );
ExportFeedback fb = feedback.get( 1 );
Assert.assertEquals( "Job1 was exproted", "job1", fb.getItemName() );
Assert.assertEquals( "Repository path for Job1 is specified", "path", fb.getItemPath() );
String res = this.validateXmlFile( fileObject.getContent().getInputStream(), "//job1" );
Assert.assertEquals( "Export xml contains exported job xml", "found", res );
}
/**
* Test that transformations can be exported with feedback
*
* @throws Exception
*/
@Test
public void testExportTransformationsWithFeedback() throws Exception {
RepositoryExporter exporter = new RepositoryExporter( repository );
List<ExportFeedback> feedback =
exporter.exportAllObjectsWithFeedback( null, xmlFileName, root, RepositoryExporter.ExportType.TRANS.toString() );
Assert.assertEquals( "Feedback contains all items recorded", 2, feedback.size() );
ExportFeedback fb = feedback.get( 1 );
Assert.assertEquals( "Job1 was exproted", "trans1", fb.getItemName() );
Assert.assertEquals( "Repository path for Job1 is specified", "path", fb.getItemPath() );
String res = this.validateXmlFile( fileObject.getContent().getInputStream(), "//trans1" );
Assert.assertEquals( "Export xml contains exported job xml", "found", res );
}
/**
* Test that we can have some feedback on rule violations
*
* @throws KettleException
*/
@Test
public void testExportAllRulesViolation() throws Exception {
RepositoryExporter exporter = new RepositoryExporter( repository );
exporter.setImportRulesToValidate( getImportRules() );
List<ExportFeedback> feedback =
exporter.exportAllObjectsWithFeedback( null, xmlFileName, root, RepositoryExporter.ExportType.ALL.toString() );
Assert.assertEquals( "Feedback contains all items recorded", 3, feedback.size() );
for ( ExportFeedback feed : feedback ) {
if ( feed.isSimpleString() ) {
continue;
}
Assert.assertEquals( "all items rejected: " + feed.toString(), ExportFeedback.Status.REJECTED, feed.getStatus() );
}
Assert.assertTrue( "Export file is deleted", !fileObject.exists() );
}
/**
* PDI-7734 - EE Repository export with Rules: When it fails, no UI feedback is given and the file is incomplete
* <p/>
* this tests bachward compatibility mode when attempt to export repository is called from code that does not support
* feddbacks.
*
* @throws KettleException
*/
@Test( expected = KettleException.class )
public void testExportAllExceptionThrown() throws KettleException {
RepositoryExporter exporter = new RepositoryExporter( repository );
exporter.setImportRulesToValidate( getImportRules() );
try {
exporter.exportAllObjects( null, xmlFileName, root, RepositoryExporter.ExportType.ALL.toString() );
} catch ( KettleException e ) {
// some debugging palce e.getStackTrace();
throw e;
}
}
private ImportRules getImportRules() {
ImportRules imp = new ImportRules();
List<ImportRuleInterface> impRules = new ArrayList<ImportRuleInterface>( 1 );
JobHasDescriptionImportRule rule = new JobHasDescriptionImportRule();
rule.setEnabled( true );
rule.setMinLength( 19000 );
impRules.add( rule );
TransformationHasDescriptionImportRule trRule = new TransformationHasDescriptionImportRule() {
public String toString() {
return "stub to avoid call to Plugin registry";
}
};
trRule.setEnabled( true );
trRule.setMinLength( 19001 );
impRules.add( trRule );
imp.setRules( impRules );
return imp;
}
private String validateXmlFile( InputStream is, String xpath ) throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expression = xPath.compile( xpath );
BufferedReader in = new BufferedReader( new InputStreamReader( is, "UTF8" ) );
InputSource input = new InputSource( in );
String result = expression.evaluate( input );
return result;
}
}