/*! * 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 static org.mockito.Mockito.*; import java.sql.Connection; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.TreeSet; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.mockito.ArgumentMatcher; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.pentaho.agilebi.modeler.ModelerException; import org.pentaho.agilebi.modeler.ModelerPerspective; import org.pentaho.agilebi.modeler.ModelerWorkspace; import org.pentaho.commons.connection.IPentahoConnection; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.database.model.DatabaseConnection; import org.pentaho.database.model.DatabaseType; import org.pentaho.database.model.IDatabaseConnection; import org.pentaho.database.model.IDatabaseType; import org.pentaho.metadata.model.Domain; import org.pentaho.metadata.model.LogicalModel; import org.pentaho.metadata.model.SqlDataSource; import org.pentaho.metadata.model.SqlPhysicalModel; import org.pentaho.metadata.model.SqlPhysicalTable; import org.pentaho.metadata.model.concept.types.LocaleType; import org.pentaho.metadata.repository.DomainAlreadyExistsException; import org.pentaho.metadata.repository.DomainIdNullException; import org.pentaho.metadata.repository.DomainStorageException; import org.pentaho.metadata.repository.IMetadataDomainRepository; import org.pentaho.platform.api.engine.IPentahoObjectFactory; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.dataaccess.datasource.DatasourceType; import org.pentaho.platform.dataaccess.datasource.beans.BusinessData; import org.pentaho.platform.dataaccess.datasource.beans.LogicalModelSummary; import org.pentaho.platform.dataaccess.datasource.beans.SerializedResultSet; 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.DatasourceModel; import org.pentaho.platform.dataaccess.datasource.wizard.models.ModelInfo; import org.pentaho.platform.dataaccess.datasource.wizard.service.DatasourceServiceException; import org.pentaho.platform.dataaccess.datasource.wizard.service.SqlQueriesNotSupportedException; import org.pentaho.platform.dataaccess.datasource.wizard.sources.query.QueryDatasourceSummary; import org.pentaho.platform.engine.core.TestObjectFactory; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.plugin.action.mondrian.catalog.IMondrianCatalogService; import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalog; import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalogServiceException; import org.pentaho.platform.plugin.services.connections.sql.SQLConnection; import org.pentaho.platform.plugin.services.connections.sql.SQLMetaData; import org.junit.Test; public class DSWDatasourceServiceImplTest { private static final String CONNECTION_NAME = "connection"; private static final String DB_TYPE = "jdbc"; private static final String VALID_QUERY = "valid query"; private static final String QUERY_COLUMN_ALREADY_EXIST = "invalid query"; private static final String PREVIEW_LIMIT = "100"; private static final String DOMAIN_ID_2MODELS = "DOMAIN_ID_2MODELS"; private static final String DOMAIN_ID_DOES_NOT_EXIST = "DOMAIN_ID_DOESNOT_EXIST"; private static final String MODEL_NAME = "modelName"; private static final String LOGICAL_MODEL_ID_DEFAULT = "<def>"; private static final String LOGICAL_MODEL_ID_REPORTING = "Reporting"; private static final String LOGICAL_MODEL_ID_ANALYSIS = "Analysis"; private static final String LOGICAL_MODEL_CONTEXTNAME = "contextName"; private static final String STRING_DEFAULT = "<def>"; private LogicalModel analysisModel; private LogicalModel reportingModel; private DSWDatasourceServiceImpl dswService; private Domain domain2Models; private final IMetadataDomainRepository domainRepository = mock( IMetadataDomainRepository.class ); private ModelerWorkspace workspace2Models; private IPentahoObjectFactory pentahoObjectFactory; private final IMondrianCatalogService mondrianService = mock( IMondrianCatalogService.class ); private final SQLConnection sqlConnection = mock( SQLConnection.class ); private final Connection nativeConnection = mock( Connection.class ); private final ModelerService modelerService = mock( ModelerService.class ); private int[] columnTypes = new int[]{ Types.INTEGER }; private Object[] columns = new Object[]{ "id" }; @Before public void setUp() throws Exception { SqlDataSource dataSource = new SqlDataSource(); dataSource.setDatabaseName( CONNECTION_NAME ); SqlPhysicalTable sqlTable = new SqlPhysicalTable(); sqlTable.setTargetTable( VALID_QUERY ); SqlPhysicalModel sqlModel = new SqlPhysicalModel(); sqlModel.addPhysicalTable( sqlTable ); sqlModel.setDatasource( dataSource ); analysisModel = new LogicalModel(); analysisModel.setId( LOGICAL_MODEL_ID_ANALYSIS ); analysisModel.setProperty( DSWDatasourceServiceImpl.LM_PROP_VISIBLE, LOGICAL_MODEL_CONTEXTNAME ); reportingModel = new LogicalModel(); reportingModel.setId( LOGICAL_MODEL_ID_REPORTING ); domain2Models = new Domain(); domain2Models.setId( DOMAIN_ID_2MODELS ); domain2Models.addLogicalModel( analysisModel ); domain2Models.addLogicalModel( reportingModel ); domain2Models.setLocales( Arrays.asList( new LocaleType( "en_US", "Test locale" ) ) ); domain2Models.addPhysicalModel( sqlModel ); Set<String> domains = new TreeSet<String>(); domains.add( DOMAIN_ID_2MODELS ); doReturn( domain2Models ).when( domainRepository ).getDomain( DOMAIN_ID_2MODELS ); doReturn( domains ).when( domainRepository ).getDomainIds(); doAnswer( new Answer<Object>() { @Override public Void answer( InvocationOnMock invocation ) throws Throwable { final String modelId = (String) invocation.getArguments()[ 1 ]; final LogicalModel modelToRemove = domain2Models.findLogicalModel( modelId ); domain2Models.getLogicalModels().remove( modelToRemove ); return null; } } ).when( domainRepository ).removeModel( anyString(), anyString() ); workspace2Models = mock( ModelerWorkspace.class ); when( workspace2Models.getLogicalModel( ModelerPerspective.ANALYSIS ) ).thenReturn( analysisModel ); when( workspace2Models.getLogicalModel( ModelerPerspective.REPORTING ) ).thenReturn( reportingModel ); dswService = spy( new DSWDatasourceServiceImpl( mock( ConnectionServiceImpl.class ) ) ); doNothing().when( dswService ).checkSqlQueriesSupported( anyString() ); dswService.setMetadataDomainRepository( domainRepository ); Object[][] coumnHeaders = new Object[][]{ columns }; SQLMetaData metadata = mock( SQLMetaData.class ); when( metadata.getColumnHeaders() ).thenReturn( coumnHeaders ); when( metadata.getJDBCColumnTypes() ).thenReturn( columnTypes ); IPentahoResultSet resultSet = mock( IPentahoResultSet.class ); when( resultSet.getMetaData() ).thenReturn( metadata ); doReturn( resultSet ).when( sqlConnection ).executeQuery( matches( "(.*" + VALID_QUERY + ".*)" ) ); when( sqlConnection.executeQuery( matches( "(.*" + QUERY_COLUMN_ALREADY_EXIST + ".*)" ) ) ).thenThrow( new SQLException( "Reason", "S0021", 21 ) ); doReturn( nativeConnection ).when( sqlConnection ).getNativeConnection(); MondrianCatalog catalog = mock( MondrianCatalog.class ); doReturn( catalog ).when( mondrianService ).getCatalog( anyString(), any( IPentahoSession.class ) ); pentahoObjectFactory = mock( IPentahoObjectFactory.class ); when( pentahoObjectFactory.objectDefined( anyString() ) ).thenReturn( true ); when( pentahoObjectFactory.get( this.anyClass(), anyString(), any( IPentahoSession.class ) ) ) .thenAnswer( new Answer<Object>() { @Override public Object answer( InvocationOnMock invocation ) throws Throwable { if ( invocation.getArguments()[0].equals( IMondrianCatalogService.class ) ) { return mondrianService; } if ( invocation.getArguments()[0].equals( IPentahoConnection.class ) ) { return sqlConnection; } if ( invocation.getArguments()[0].equals( IMetadataDomainRepository.class ) ) { return domainRepository; } return null; } } ); PentahoSystem.registerObjectFactory( pentahoObjectFactory ); } @After public void tearDown() { PentahoSystem.deregisterObjectFactory( pentahoObjectFactory ); PentahoSystem.clearObjectFactory(); } @Test public void testDeleteLogicalModel_allModelsRemoved() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); assertTrue( dswService.deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ) ); verify( domainRepository ).removeModel( DOMAIN_ID_2MODELS, LOGICAL_MODEL_ID_REPORTING ); verify( domainRepository ).removeModel( DOMAIN_ID_2MODELS, LOGICAL_MODEL_ID_ANALYSIS ); } @Test public void testDeleteLogicalModel_removeReportingModelIfAnalysisModelDoesNotExist() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); ModelerWorkspace workspace = mock( ModelerWorkspace.class ); when( workspace.getLogicalModel( ModelerPerspective.REPORTING ) ).thenReturn( reportingModel ); doReturn( workspace ).when( dswService ).createModelerWorkspace(); doCallRealMethod().when( dswService ).deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ); assertTrue( dswService.deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ) ); verify( domainRepository ).removeModel( DOMAIN_ID_2MODELS, LOGICAL_MODEL_ID_REPORTING ); } @Test public void testDeleteLogicalModel_keepDomainIfLogicalModelExist() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); LogicalModel logicalModel = new LogicalModel(); logicalModel.setId( LOGICAL_MODEL_ID_DEFAULT ); domain2Models.getLogicalModels().add( logicalModel ); assertTrue( dswService.deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ) ); List<LogicalModel> logicalModels = domain2Models.getLogicalModels(); assertNotNull( logicalModels ); assertEquals( 1, logicalModels.size() ); verify( domainRepository, never() ).removeDomain( domain2Models.getId() ); } @Test public void testDeleteLogicalModel_removeDomainIfLogicalModelDoesNotExist() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); assertTrue( dswService.deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ) ); assertTrue( domain2Models.getLogicalModels().isEmpty() ); verify( domainRepository ).removeDomain( domain2Models.getId() ); } @Test public void testDeleteLogicalModel_DoNotDeleteAnyWithoutPermissions() throws Exception { doReturn( false ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); assertFalse( dswService.deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ) ); List<LogicalModel> logicalModels = domain2Models.getLogicalModels(); assertNotNull( logicalModels ); assertEquals( 2, logicalModels.size() ); verify( domainRepository, never() ).removeDomain( domain2Models.getId() ); verify( domainRepository, never() ).removeModel( DOMAIN_ID_2MODELS, LOGICAL_MODEL_ID_REPORTING ); } @Test public void testDeleteLogicalModel_DomainDoesNotExist() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); //domain already deleted or does not exist, we return that delete operation was successful assertTrue( dswService.deleteLogicalModel( DOMAIN_ID_DOES_NOT_EXIST, MODEL_NAME ) ); } @Test public void testDeleteLogicalModel_MondrianDeleted() throws Exception { String mondrianName = "mondrianRef"; analysisModel.setProperty( DSWDatasourceServiceImpl.LM_PROP_MONDRIAN_CATALOG_REF, mondrianName ); doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); assertTrue( dswService.deleteLogicalModel( DOMAIN_ID_2MODELS, MODEL_NAME ) ); verify( mondrianService ).removeCatalog( eq( mondrianName ), any( IPentahoSession.class ) ); } @Test( expected = DatasourceServiceException.class ) public void testDeleteLogicalModel_DomainStorageException() throws Exception { testDeleteLogicalModel_Exception( DomainStorageException.class ); } @Test( expected = DatasourceServiceException.class ) public void testDeleteLogicalModel_MondrianCatalogServiceException() throws Exception { testDeleteLogicalModel_Exception( MondrianCatalogServiceException.class ); } @Test( expected = DatasourceServiceException.class ) public void testDeleteLogicalModel_DomainIdNullException() throws Exception { testDeleteLogicalModel_Exception( DomainIdNullException.class ); } private void testDeleteLogicalModel_Exception( Class<? extends Throwable> clazz ) throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( workspace2Models ).when( dswService ).createModelerWorkspace(); doThrow( clazz ).when( domainRepository ).removeModel( anyString(), anyString() ); dswService.deleteLogicalModel( null, MODEL_NAME ); } @Test( expected = DatasourceServiceException.class ) public void testSaveLogicalModel__DoNotSaveAnyWithoutPermissions() throws Exception { doReturn( false ).when( dswService ).hasDataAccessPermission(); assertFalse( dswService.saveLogicalModel( domain2Models, false ) ); verify( domainRepository, never() ).storeDomain( any( Domain.class ), anyBoolean() ); } @Test public void testSaveLogicalModel() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); assertTrue( dswService.saveLogicalModel( domain2Models, false ) ); verify( domainRepository ).storeDomain( any( Domain.class ), anyBoolean() ); } @Test( expected = DatasourceServiceException.class ) public void testSaveLogicalModel_DomainStorageException() throws Exception { testSaveLogicalModel_Exception( DomainStorageException.class ); } @Test( expected = DatasourceServiceException.class ) public void testSaveLogicalModel_DomainAlreadyExistsException() throws Exception { testSaveLogicalModel_Exception( DomainAlreadyExistsException.class ); } @Test( expected = DatasourceServiceException.class ) public void testSaveLogicalModel_DomainIdNullException() throws Exception { testSaveLogicalModel_Exception( DomainIdNullException.class ); } private void testSaveLogicalModel_Exception( Class<? extends Throwable> clazz ) throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doThrow( clazz ).when( domainRepository ).storeDomain( any( Domain.class ), anyBoolean() ); dswService.saveLogicalModel( domain2Models, false ); } @Test public void testTestDataSourceConnection() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); assertTrue( dswService.testDataSourceConnection( CONNECTION_NAME ) ); } @Test( expected = DatasourceServiceException.class ) public void testTestDataSourceConnection_NullNativeConnection() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( null ).when( sqlConnection ).getNativeConnection(); assertTrue( dswService.testDataSourceConnection( CONNECTION_NAME ) ); } @Test( expected = DatasourceServiceException.class ) public void testTestDataSourceConnection_CouldNotClose() throws Exception { doReturn( true ).when( dswService ).hasDataAccessPermission(); doThrow( new SQLException() ).when( nativeConnection ).close(); assertTrue( dswService.testDataSourceConnection( CONNECTION_NAME ) ); } @Test( expected = DatasourceServiceException.class ) public void testTestDataSourceConnection_DoesNotHavePermission() throws Exception { doReturn( false ).when( dswService ).hasDataAccessPermission(); dswService.testDataSourceConnection( CONNECTION_NAME ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateLogicalModel_DoesNotHavePermission() throws DatasourceServiceException { doReturn( false ).when( dswService ).hasDataAccessPermission(); dswService.generateLogicalModel( MODEL_NAME, CONNECTION_NAME, DB_TYPE, VALID_QUERY, PREVIEW_LIMIT ); } @Test public void testGenerateLogicalModel() throws DatasourceServiceException { testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, VALID_QUERY, null, null ); } @Test public void testGenerateLogicalModel_EmptyRoleList() throws DatasourceServiceException { List<String> roleList = new ArrayList<String>(); testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, VALID_QUERY, roleList, null ); } @Test public void testGenerateLogicalModel_NonEmptyRoleList() throws DatasourceServiceException { PentahoSessionHolder.setSession( mock( IPentahoSession.class ) ); List<String> roleList = Arrays.asList( "systemRole" ); testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, VALID_QUERY, roleList, null ); } @Test public void testGenerateLogicalModel_EmptyUserList() throws DatasourceServiceException { List<String> userList = new ArrayList<String>(); testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, VALID_QUERY, null, userList ); } @Test public void testGenerateLogicalModel_NonEmptyUserList_NonEmptyRoles() throws DatasourceServiceException { PentahoSessionHolder.setSession( mock( IPentahoSession.class ) ); List<String> userList = Arrays.asList( "systemUser" ); List<String> roleList = Arrays.asList( "systemRole" ); testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, VALID_QUERY, roleList, userList ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateLogicalModel_NonEmptyUserList_EmptyRoles() throws DatasourceServiceException { PentahoSessionHolder.setSession( mock( IPentahoSession.class ) ); List<String> userList = Arrays.asList( "systemUser" ); testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, VALID_QUERY, null, userList ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateLogicalModel_UNABLE_TO_GENERATE_MODEL_NULLNAME() throws DatasourceServiceException { testGenerateLogicalModel( null, CONNECTION_NAME, VALID_QUERY, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateLogicalModel_UNABLE_TO_GENERATE_MODEL_NULLConnection() throws DatasourceServiceException { testGenerateLogicalModel( MODEL_NAME, null, VALID_QUERY, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateLogicalModel_UNABLE_TO_GENERATE_MODEL_NULLQUERY() throws DatasourceServiceException { testGenerateLogicalModel( MODEL_NAME, CONNECTION_NAME, null, null, null ); } private void testGenerateLogicalModel( String modelName, String connName, String query, List<String> roleList, List<String> userList ) throws DatasourceServiceException { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( roleList ).when( dswService ).getPermittedRoleList(); doReturn( userList ).when( dswService ).getPermittedUserList(); doReturn( 1 ).when( dswService ).getDefaultAcls(); BusinessData businessData = dswService.generateLogicalModel( modelName, connName, DB_TYPE, query, PREVIEW_LIMIT ); assertNotNull( businessData ); assertNotNull( businessData.getDomain() ); assertNotNull( businessData.getData() ); } @Test public void testDoPreview() throws DatasourceServiceException { doReturn( true ).when( dswService ).hasDataAccessPermission(); SerializedResultSet result = dswService.doPreview( CONNECTION_NAME, VALID_QUERY, PREVIEW_LIMIT ); assertNotNull( result ); assertArrayEquals( columns, result.getColumns() ); assertArrayEquals( columnTypes, result.getColumnTypes() ); } @Test( expected = DatasourceServiceException.class ) public void testDoPreview_DoesNotHavePermission() throws DatasourceServiceException { doReturn( false ).when( dswService ).hasDataAccessPermission(); dswService.doPreview( CONNECTION_NAME, VALID_QUERY, PREVIEW_LIMIT ); } @Test( expected = DatasourceServiceException.class ) public void testDoPreview_NullConnection() throws DatasourceServiceException { doReturn( true ).when( dswService ).hasDataAccessPermission(); dswService.doPreview( null, VALID_QUERY, PREVIEW_LIMIT ); } @Test( expected = DatasourceServiceException.class ) public void testDoPreview_NullQuery() throws DatasourceServiceException { doReturn( true ).when( dswService ).hasDataAccessPermission(); SerializedResultSet result = dswService.doPreview( CONNECTION_NAME, null, PREVIEW_LIMIT ); assertNotNull( result ); assertArrayEquals( columns, result.getColumns() ); assertArrayEquals( columnTypes, result.getColumnTypes() ); } @Test public void testGenerateQueryDomain() throws DatasourceServiceException { testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateQueryDomain_EmptyModelName() throws DatasourceServiceException { testGenerateQueryDomain( "", VALID_QUERY, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateQueryDomain_UnableToSerializeCommonCause() throws Exception { doThrow( new Exception() ).when( modelerService ).serializeModels( any( Domain.class ), anyString() ); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateQueryDomain_UnableToSerialize() throws Exception { when( modelerService.serializeModels( any( Domain.class ), anyString() ) ).thenThrow( new ModelerException() ); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateQueryDomain_SQLException() throws Exception { testGenerateQueryDomain( MODEL_NAME, QUERY_COLUMN_ALREADY_EXIST, null, null ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateQueryDomain_NullQuery() throws DatasourceServiceException { testGenerateQueryDomain( MODEL_NAME, null, null, null ); } @Test public void testGenerateQueryDomain_EmptyRoleList() throws DatasourceServiceException { List<String> roleList = new ArrayList<String>(); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, roleList, null ); } @Test public void testGenerateQueryDomain_NonEmptyRoleList() throws DatasourceServiceException { List<String> roleList = Arrays.asList( "systemRole" ); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, roleList, null ); } @Test public void testGenerateQueryDomain_EmptyUserList() throws DatasourceServiceException { List<String> userList = new ArrayList<String>(); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, null, userList ); } @Test( expected = DatasourceServiceException.class ) public void testGenerateQueryDomain_NonEmptyUserList_EmptyRoles() throws DatasourceServiceException { List<String> userList = Arrays.asList( "systemUser" ); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, null, userList ); } @Test public void testGenerateQueryDomain_NonEmptyUserList_NonEmptyRoles() throws DatasourceServiceException { List<String> userList = Arrays.asList( "systemUser" ); List<String> roleList = Arrays.asList( "systemRole" ); testGenerateQueryDomain( MODEL_NAME, VALID_QUERY, roleList, userList ); } private void testGenerateQueryDomain( String modelName, String query, List<String> roleList, List<String> userList ) throws DatasourceServiceException { ModelInfo modelInfo = mock( ModelInfo.class ); when( modelInfo.getFileInfo() ).thenReturn( mock( CsvFileInfo.class ) ); DatasourceDTO datasourceDTO = new DatasourceDTO(); datasourceDTO.setConnectionName( CONNECTION_NAME ); datasourceDTO.setDatasourceName( CONNECTION_NAME ); datasourceDTO.setCsvModelInfo( modelInfo ); DatabaseConnection connection = new DatabaseConnection(); connection.setName( CONNECTION_NAME ); connection.setDatabaseType( mock( IDatabaseType.class ) ); doReturn( modelerService ).when( dswService ).createModelerService(); doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( roleList ).when( dswService ).getPermittedRoleList(); doReturn( userList ).when( dswService ).getPermittedUserList(); doReturn( null ).when( dswService ).getGeoContext(); doReturn( 1 ).when( dswService ).getDefaultAcls(); QueryDatasourceSummary summary = dswService.generateQueryDomain( modelName, query, connection, datasourceDTO ); assertNotNull( summary ); assertNotNull( summary.getDomain() ); assertEquals( CONNECTION_NAME, summary.getDomain().getId() ); } @Test( expected = DatasourceServiceException.class ) public void testGetLogicalModels_DoesNotHavePermissionViewPermission() throws DatasourceServiceException { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( false ).when( dswService ).hasDataAccessViewPermission(); dswService.getLogicalModels( LOGICAL_MODEL_CONTEXTNAME ); } @Test public void testGetLogicalModels_visibleToContext() throws DatasourceServiceException { testGetLogicalModels_NullContext( LOGICAL_MODEL_CONTEXTNAME ); } @Test public void testGetLogicalModels_NonVisibleToContext() throws DatasourceServiceException { testGetLogicalModels_NullContext( "anotherContext" ); } @Test public void testGetLogicalModels_NullContext() throws DatasourceServiceException { testGetLogicalModels_NullContext( null ); } @Test public void testGetLogicalModels_EmptyContext() throws DatasourceServiceException { testGetLogicalModels_NullContext( "" ); } private void testGetLogicalModels_NullContext( String context ) throws DatasourceServiceException { doReturn( true ).when( dswService ).hasDataAccessPermission(); doReturn( true ).when( dswService ).hasDataAccessViewPermission(); List<LogicalModelSummary> models = dswService.getLogicalModels( context ); assertNotNull( models ); for ( LogicalModelSummary logicalModelSummary : models ) { assertEquals( domain2Models.getId(), logicalModelSummary.getDomainId() ); } } @Test public void testListDatasourceNames() throws Exception { IPentahoSession session = mock( IPentahoSession.class ); when( session.getId() ).thenReturn( "SessionId" ); when( session.getActionName() ).thenReturn( "ActionNAme" ); when( session.getProcessId() ).thenReturn( "ProcessId" ); PentahoSessionHolder.setSession( session ); List<String> datasources = dswService.listDatasourceNames(); assertNotNull( datasources ); assertFalse( datasources.isEmpty() ); assertTrue( datasources.contains( LOGICAL_MODEL_ID_REPORTING ) ); } @Test public void testLoadBusinessData() throws DatasourceServiceException { BusinessData businessData = dswService.loadBusinessData( DOMAIN_ID_2MODELS, MODEL_NAME ); assertNotNull( businessData ); //should load the domain with expected id assertEquals( DOMAIN_ID_2MODELS, businessData.getDomain().getId() ); } @Test public void testHasPermission_nullSession() { PentahoSessionHolder.setSession( null ); assertFalse( dswService.hasPermission() ); } //should create new modeler service without exception @Test public void testCreateModelerService() { ModelerService service = dswService.createModelerService(); assertNotNull( service ); } //should create new workspace without exception @Test public void testCreateModelerWorkspace() { ModelerWorkspace workspace = dswService.createModelerWorkspace(); assertNotNull( workspace ); } @Test( expected = SqlQueriesNotSupportedException.class ) public void testSqlQueries_AreNotSupported_PentahoDataServices() throws Exception { String connNameDataService = "connToDataService"; String dbTypeIdDataService = "Pentaho Data Services"; DatabaseType dbtype = new DatabaseType( dbTypeIdDataService, STRING_DEFAULT, null, 0, STRING_DEFAULT ); IDatabaseConnection connDataService = new DatabaseConnection(); connDataService.setDatabaseType( dbtype ); ConnectionServiceImpl connService = mock( ConnectionServiceImpl.class ); doReturn( connDataService ).when( connService ).getConnectionByName( eq( connNameDataService ) ); DSWDatasourceServiceImpl service = new DSWDatasourceServiceImpl( connService ); service.checkSqlQueriesSupported( connNameDataService ); } @Test public void testSqlQueries_Supported_PostgresDb() throws Exception { String connNamePostgres = "connToPostgresDb"; String dbTypeIdPostgres = "PostgresDb"; IDatabaseConnection connDataService = new DatabaseConnection(); connDataService.setDatabaseType( new DatabaseType( dbTypeIdPostgres, STRING_DEFAULT, null, 0, STRING_DEFAULT ) ); ConnectionServiceImpl connService = mock( ConnectionServiceImpl.class ); doReturn( connDataService ).when( connService ).getConnectionByName( eq( connNamePostgres ) ); DSWDatasourceServiceImpl service = new DSWDatasourceServiceImpl( connService ); service.checkSqlQueriesSupported( connNamePostgres ); } @Test public void testDeSerializeModelStateValidString() throws Exception { PentahoSystem.registerObjectFactory( new TestObjectFactory() ); DatasourceModel datasourceModel = new DatasourceModel(); datasourceModel.setDatasourceName( "testDatasource" ); datasourceModel.setDatasourceType( DatasourceType.CSV ); DatasourceDTO dto = DatasourceDTO.generateDTO( datasourceModel ); assertNotNull( dto ); String serializedDTO = dswService.serializeModelState( dto ); dswService.deSerializeModelState( serializedDTO ); } @Test( expected = DatasourceServiceException.class ) public void testDeSerializeModelStateInvalidString() throws Exception { String notSafeString = "<com.malicious.DatasourceDTO>\n" + " <datasourceName>testDatasource</datasourceName>\n" + " <datasourceType>CSV</datasourceType>\n" + " <csvModelInfo>\n" + " <fileInfo>\n" + " <delimiter>,</delimiter>\n" + " <enclosure>"</enclosure>\n" + " <headerRows>1</headerRows>\n" + " <currencySymbol></currencySymbol>\n" + " <decimalSymbol>.</decimalSymbol>\n" + " <groupSymbol>,</groupSymbol>\n" + " <ifNull>---</ifNull>\n" + " <nullStr></nullStr>\n" + " </fileInfo>\n" + " <stageTableName>testdatasource</stageTableName>\n" + " <validated>false</validated>\n" + " <csvInputErrors/>\n" + " <tableOutputErrors/>\n" + " </csvModelInfo>\n" + " <connectionName>SampleData</connectionName>\n" + " <version>2.0</version>\n" + "</com.malicious.DatasourceDTO>"; dswService.deSerializeModelState( notSafeString ); } private Class<?> anyClass() { return argThat( new AnyClassMatcher() ); } private class AnyClassMatcher extends ArgumentMatcher<Class<?>> { @Override public boolean matches( final Object arg ) { return true; } } }