/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2017 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.dataaccess.datasource.wizard.service.impl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.pentaho.platform.api.engine.IApplicationContext;
import org.pentaho.platform.api.engine.IAuthorizationPolicy;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.ISystemSettings;
import org.pentaho.platform.dataaccess.datasource.wizard.models.CsvFileInfo;
import org.pentaho.platform.dataaccess.datasource.wizard.models.DatasourceDTO;
import org.pentaho.platform.dataaccess.datasource.wizard.models.FileInfo;
import org.pentaho.platform.dataaccess.datasource.wizard.models.ModelInfo;
import org.pentaho.platform.dataaccess.datasource.wizard.sources.csv.FileTransformStats;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import java.io.File;
import java.io.PrintWriter;
import java.util.List;
import static org.junit.Assert.*;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
/**
* @author Andrey Khayrutdinov
*/
public class CsvDatasourceServiceImplTest {
private static final String TMP_DIR = System.getProperty( "java.io.tmpdir" );
private IApplicationContext mockContext;
private IApplicationContext existingContext;
private CsvDatasourceServiceImpl service;
private static boolean hasPermissions;
private final IAuthorizationPolicy policy = new IAuthorizationPolicy() {
@Override public boolean isAllowed( String s ) {
return hasPermissions;
}
@Override public List<String> getAllowedActions( String s ) {
return null;
}
};
@Before
public void setUp() throws Exception {
assertNotNull( "Temp directory was not found", TMP_DIR );
existingContext = PentahoSystem.getApplicationContext();
mockContext = mock( IApplicationContext.class );
when( mockContext.getSolutionPath( anyString() ) ).thenReturn( TMP_DIR + '/' );
PentahoSystem.setApplicationContext( mockContext );
service = new CsvDatasourceServiceImpl();
//Skip permission check by default
final ISystemSettings systemSettings = mock( ISystemSettings.class );
when( systemSettings.getSystemSetting( "data-access-override", "false" ) ).thenReturn( "true" );
PentahoSystem.setSystemSettingsService( systemSettings );
PentahoSessionHolder.setSession( mock( IPentahoSession.class ) );
PentahoSystem.registerObject( policy );
}
@After
public void tearDown() throws Exception {
hasPermissions = false;
PentahoSystem.setApplicationContext( existingContext );
PentahoSessionHolder.removeSession();
mockContext = null;
service = null;
}
@Test( expected = Exception.class )
public void stageFile_InvalidPath_Csv_ThrowsException() throws Exception {
service.stageFile( "../../../secret-file.csv", ",", "\n", false, "utf-8" );
}
@Test( expected = Exception.class )
public void stageFile_InvalidPath_Tmp_ThrowsException() throws Exception {
service.stageFile( "../../../secret-file.tmp", ",", "\n", false, "utf-8" );
}
@Test( expected = Exception.class )
public void stageFile_InvalidPath_WindowsStyle_ThrowsException() throws Exception {
service.stageFile( "..\\..\\..\\secret-file.csv", ",", "\n", false, "utf-8" );
}
@Test( expected = Exception.class )
public void stageFile_InvalidPath_SlashAtEnd_ThrowsException() throws Exception {
service.stageFile( "../../../secret-file/", ",", "\n", false, "utf-8" );
}
@Test
public void stageFile_InvalidPath_DoesNotRevealInternalDetails() throws Exception {
try {
service.stageFile( "../../../secret-file.tmp", ",", "\n", false, "utf-8" );
fail( "Should throw exception" );
} catch ( Exception e ) {
String message = e.getMessage();
assertFalse( message, message.contains( TMP_DIR ) );
}
}
@Test
public void stageFile_CsvFile() throws Exception {
String filename = "stageFile_CsvFile.csv";
File file = createTmpCsvFile( filename );
file.deleteOnExit();
try {
ModelInfo modelInfo = service.stageFile( filename, ",", "\n", true, "utf-8" );
CsvFileInfo fileInfo = modelInfo.getFileInfo();
assertEquals( "One header row", 1, fileInfo.getHeaderRows() );
assertEquals( "Header + content row", 2, fileInfo.getContents().size() );
assertEquals( filename, fileInfo.getTmpFilename() );
} finally {
file.delete();
}
}
@Test
public void testNoPermissions() throws Exception {
final ISystemSettings systemSettings = mock( ISystemSettings.class );
when( systemSettings.getSystemSetting( "data-access-override", "false" ) ).thenReturn( "false" );
PentahoSystem.setSystemSettingsService( systemSettings );
String filename = "stageFile_CsvFile.csv";
File file = createTmpCsvFile( filename );
file.deleteOnExit();
try {
boolean thrown = false;
try {
service.stageFile( filename, ",", "\n", true, "utf-8" );
} catch ( SecurityException e ) {
thrown = true;
}
assertTrue( thrown );
thrown = false;
try {
service.getStagedFiles();
} catch ( SecurityException e ) {
thrown = true;
}
assertTrue( thrown );
thrown = false;
try {
service.getPreviewRows( filename, true, 1, "utf-8" );
} catch ( SecurityException e ) {
thrown = true;
}
assertTrue( thrown );
thrown = false;
try {
service.getEncoding( filename );
} catch ( SecurityException e ) {
thrown = true;
}
assertTrue( thrown );
thrown = false;
try {
service.generateDomain( mock( DatasourceDTO.class ) );
} catch ( SecurityException e ) {
thrown = true;
}
assertTrue( thrown );
} finally {
file.delete();
}
}
@Test
public void testHasPermissions() throws Exception {
hasPermissions = true;
final ISystemSettings systemSettings = mock( ISystemSettings.class );
when( systemSettings.getSystemSetting( "data-access-override", "false" ) ).thenReturn( "false" );
PentahoSystem.setSystemSettingsService( systemSettings );
String filename = "anotherStageFile_CsvFile.csv";
File file = createTmpCsvFile( filename );
file.deleteOnExit();
try {
ModelInfo modelInfo = service.stageFile( filename, ",", "\n", true, "utf-8" );
CsvFileInfo fileInfo = modelInfo.getFileInfo();
assertEquals( "One header row", 1, fileInfo.getHeaderRows() );
assertEquals( "Header + content row", 2, fileInfo.getContents().size() );
assertEquals( filename, fileInfo.getTmpFilename() );
final FileInfo[] stagedFiles = service.getStagedFiles();
assertNotNull( stagedFiles );
boolean present = false;
for ( FileInfo info : stagedFiles ) {
if ( filename.equals( info.getName() ) ) {
present = true;
break;
}
}
assertTrue( present );
final String encoding = service.getEncoding( filename );
assertNotNull( encoding );
final List<String> previewRows = service.getPreviewRows( filename, true, 1, "utf-8" );
assertNotNull( previewRows );
assertEquals( 1, previewRows.size() );
assertEquals( "col1,col2", previewRows.get( 0 ) );
final DatasourceDTO datasourceDto = mock( DatasourceDTO.class );
when( datasourceDto.getCsvModelInfo() ).thenReturn( modelInfo );
try {
final FileTransformStats fileTransformStats = service.generateDomain( datasourceDto );
} catch ( Exception e ) {
//Testing this logic is not a purpose of this junit
}
//Passed permissions check
verify( datasourceDto, times( 1 ) ).getCsvModelInfo();
} finally {
file.delete();
}
}
private static File createTmpCsvFile( String filename ) throws Exception {
File csvFile = new File( TMP_DIR, filename );
PrintWriter pw = new PrintWriter( csvFile );
try {
pw.println( "col1,col2" );
pw.println( "1,2" );
} finally {
pw.close();
}
return csvFile;
}
}