/* * 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) 2000 - 2016 Pentaho Corporation, Simba Management Limited and Contributors... All rights reserved. */ package org.pentaho.reporting.engine.classic.core.modules.misc.datafactory.sql; import org.junit.Before; import org.junit.Test; import org.pentaho.reporting.engine.classic.core.DataFactory; import org.pentaho.reporting.engine.classic.core.DataFactoryContext; import org.pentaho.reporting.engine.classic.core.DataRow; import org.pentaho.reporting.engine.classic.core.ReportDataFactoryException; import org.pentaho.reporting.engine.classic.core.ResourceBundleFactory; import org.pentaho.reporting.libraries.base.config.Configuration; import javax.swing.table.TableModel; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Date; import java.util.List; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.Matchers.arrayContainingInAnyOrder; import static org.hamcrest.Matchers.emptyArray; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.*; public class SimpleSQLReportDataFactoryTest { private static final String QUERY = "test_query"; private SimpleSQLReportDataFactory factory; private Connection connection; @Before public void setUp() throws ReportDataFactoryException, SQLException { connection = mock( Connection.class ); factory = spy( new SimpleSQLReportDataFactory( connection ) ); DataFactoryContext dataFactoryContext = mock( DataFactoryContext.class ); Configuration conf = mock( Configuration.class ); ResourceBundleFactory resourceBundleFactory = mock( ResourceBundleFactory.class ); doReturn( conf ).when( dataFactoryContext ).getConfiguration(); doReturn( resourceBundleFactory ).when( dataFactoryContext ).getResourceBundleFactory(); doReturn( "simple" ).when( conf ).getConfigProperty( ResultSetTableModelFactory.RESULTSET_FACTORY_MODE ); factory.initialize( dataFactoryContext ); } @Test( expected = NullPointerException.class ) public void testCreateFactoryWithNullProvider() { ConnectionProvider connectionProvider = null; new SimpleSQLReportDataFactory( connectionProvider ); } @Test( expected = SQLException.class ) public void testGetNullConnection() throws SQLException { factory = new SimpleSQLReportDataFactory( mock( JndiConnectionProvider.class ) ); DataRow dataRow = mock( DataRow.class ); factory.getConnection( dataRow ); } @Test public void testGetConnection() throws SQLException { DataRow dataRow = mock( DataRow.class ); Connection con = factory.getConnection( dataRow ); assertThat( con, is( equalTo( connection ) ) ); } @Test public void testGetConnectionWithoutCredentials() throws SQLException { DataRow dataRow = mock( DataRow.class ); factory.setUserField( "userField" ); factory.setPasswordField( "passwordField" ); Connection con = factory.getConnection( dataRow ); assertThat( con, is( equalTo( connection ) ) ); } @Test public void testGetConnectionWithCredentials() throws SQLException { DataRow dataRow = mock( DataRow.class ); factory.setUserField( "userField" ); factory.setPasswordField( "passwordField" ); doReturn( "user" ).when( dataRow ).get( "userField" ); doReturn( "password" ).when( dataRow ).get( "passwordField" ); Connection con = factory.getConnection( dataRow ); assertThat( con, is( equalTo( connection ) ) ); } @Test( expected = ReportDataFactoryException.class ) public void testQueryDataWithSqlException() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); String[] preparedParameterNames = new String[] {}; doThrow( SQLException.class ).when( factory ).parametrizeAndQuery( parameters, QUERY, preparedParameterNames ); factory.queryData( QUERY, parameters ); } @Test public void testQueryData() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); TableModel model = mock( TableModel.class ); String[] preparedParameterNames = new String[] {}; doReturn( model ).when( factory ).parametrizeAndQuery( parameters, QUERY, preparedParameterNames ); TableModel result = factory.queryData( QUERY, parameters ); assertThat( result, is( equalTo( model ) ) ); } @Test( expected = ReportDataFactoryException.class ) public void testGetReferencedFieldsComputedQueryException() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); doThrow( ReportDataFactoryException.class ).when( factory ).computedQuery( QUERY + "${param}", parameters ); factory.getReferencedFields( QUERY + "${param}", parameters ); } @Test( expected = ReportDataFactoryException.class ) public void testGetReferencedFieldsSqlException() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); doThrow( SQLException.class ).when( factory ).getConnection( parameters ); factory.getReferencedFields( QUERY + "${param}", parameters ); } @Test public void testGetReferencedFields() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); String[] result = factory.getReferencedFields( QUERY + "${param}", parameters ); assertThat( result, arrayContainingInAnyOrder( "param", DataFactory.QUERY_LIMIT ) ); factory.setUserField( "user_field" ); factory.setPasswordField( "password_field" ); result = factory.getReferencedFields( QUERY + "${param}", parameters ); assertThat( result, arrayContainingInAnyOrder( "param", "user_field", "password_field", DataFactory.QUERY_LIMIT ) ); } @Test public void testTranslateQuery() { assertThat( factory.translateQuery( QUERY ), is( equalTo( QUERY ) ) ); } @Test public void testComputedQuery() throws ReportDataFactoryException { DataRow parameters = mock( DataRow.class ); assertThat( factory.computedQuery( QUERY, parameters ), is( equalTo( QUERY ) ) ); } @Test public void testIsExpandArrayParameterNeeded() { assertThat( SimpleSQLReportDataFactory.isExpandArrayParameterNeeded( QUERY ), is( equalTo( true ) ) ); assertThat( SimpleSQLReportDataFactory.isExpandArrayParameterNeeded( "{call}" ), is( equalTo( false ) ) ); assertThat( SimpleSQLReportDataFactory.isExpandArrayParameterNeeded( "{?=call}" ), is( equalTo( false ) ) ); } @Test public void testParametrizeAndQuery() throws SQLException { DataRow parameters = mock( DataRow.class ); String[] preparedParameterNames = new String[] {}; Connection con = mock( Connection.class ); PreparedStatement statement = mock( PreparedStatement.class ); ResultSet res = mock( ResultSet.class ); ResultSetMetaData rsmd = mock( ResultSetMetaData.class ); doReturn( 10 ).when( parameters ).get( DataFactory.QUERY_LIMIT ); doReturn( 20 ).when( parameters ).get( DataFactory.QUERY_TIMEOUT ); doReturn( con ).when( factory ).getConnection( parameters ); doReturn( statement ).when( con ).createStatement( anyInt(), anyInt() ); doReturn( res ).when( statement ).executeQuery( QUERY ); doReturn( res ).when( statement ).executeQuery(); doReturn( rsmd ).when( res ).getMetaData(); doReturn( 1 ).when( rsmd ).getColumnCount(); doReturn( "test_column_label" ).when( rsmd ).getColumnLabel( 1 ); doReturn( "test_column_name" ).when( rsmd ).getColumnName( 1 ); doReturn( true ).doReturn( false ).when( res ).next(); doReturn( "test_val" ).when( res ).getObject( 1 ); TableModel result = factory.parametrizeAndQuery( parameters, QUERY, preparedParameterNames ); verify( con ).createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); verify( statement ).setMaxRows( 10 ); verify( statement ).setQueryTimeout( 20 ); verify( statement ).executeQuery( QUERY ); assertThat( result, is( notNullValue() ) ); assertThat( result.getRowCount(), is( equalTo( 1 ) ) ); assertThat( result.getColumnCount(), is( equalTo( 1 ) ) ); assertThat( result.getColumnName( 0 ), is( equalTo( "test_column_label" ) ) ); assertThat( (String) result.getValueAt( 0, 0 ), is( equalTo( "test_val" ) ) ); } @Test public void testParametrizeAndQueryWithCallableStatement() throws SQLException { String query = "{?=call}"; DataRow parameters = mock( DataRow.class ); String[] preparedParameterNames = new String[] { "param_0", "param_1", "param_2", "param_3" }; Connection con = mock( Connection.class ); CallableStatement statement = mock( CallableStatement.class ); ResultSet res = mock( ResultSet.class ); ResultSetMetaData rsmd = mock( ResultSetMetaData.class ); Date currentDate = new Date(); java.sql.Date sqlDate = new java.sql.Date( currentDate.getTime() ); doReturn( null ).when( parameters ).get( "param_0" ); doReturn( sqlDate ).when( parameters ).get( "param_1" ); doReturn( currentDate ).when( parameters ).get( "param_2" ); doReturn( "val_3" ).when( parameters ).get( "param_3" ); doReturn( con ).when( factory ).getConnection( parameters ); doReturn( statement ).when( con ).prepareCall( anyString(), anyInt(), anyInt() ); doReturn( statement ).when( con ).prepareStatement( anyString(), anyInt(), anyInt() ); doReturn( res ).when( statement ).executeQuery(); doReturn( rsmd ).when( res ).getMetaData(); doReturn( 1 ).when( rsmd ).getColumnCount(); doReturn( "test_column_label" ).when( rsmd ).getColumnLabel( 1 ); doReturn( "test_column_name" ).when( rsmd ).getColumnName( 1 ); doReturn( true ).doReturn( false ).when( res ).next(); doReturn( "test_val" ).when( res ).getObject( 1 ); TableModel result = factory.parametrizeAndQuery( parameters, query, preparedParameterNames ); verify( con, never() ).createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); verify( statement, never() ).setMaxRows( 10 ); verify( statement, never() ).setQueryTimeout( 20 ); verify( statement, never() ).executeQuery( query ); verify( statement ).clearParameters(); verify( statement ).setObject( 2, null ); verify( statement ).setObject( 3, sqlDate ); verify( statement ).setObject( 4, currentDate ); verify( statement ).setObject( 5, "val_3" ); verify( statement ).executeQuery(); assertThat( result, is( notNullValue() ) ); assertThat( result.getRowCount(), is( equalTo( 1 ) ) ); assertThat( result.getColumnCount(), is( equalTo( 1 ) ) ); assertThat( result.getColumnName( 0 ), is( equalTo( "test_column_label" ) ) ); assertThat( (String) result.getValueAt( 0, 0 ), is( equalTo( "test_val" ) ) ); } @Test public void testParametrizeAndQueryWithArrays() throws SQLException { String query = "{ca}"; DataRow parameters = mock( DataRow.class ); String[] preparedParameterNames = new String[] { "param_0", "param_1", "param_2", "param_3" }; Connection con = mock( Connection.class ); CallableStatement statement = mock( CallableStatement.class ); ResultSet res = mock( ResultSet.class ); ResultSetMetaData rsmd = mock( ResultSetMetaData.class ); Date currentDate = new Date(); java.sql.Date sqlDate = new java.sql.Date( currentDate.getTime() ); doReturn( new Object[] {} ).when( parameters ).get( "param_0" ); doReturn( new Object[] { sqlDate, currentDate, "val_3" } ).when( parameters ).get( "param_1" ); doReturn( con ).when( factory ).getConnection( parameters ); doReturn( statement ).when( con ).prepareStatement( anyString(), anyInt(), anyInt() ); doReturn( res ).when( statement ).executeQuery(); doReturn( rsmd ).when( res ).getMetaData(); doReturn( 1 ).when( rsmd ).getColumnCount(); doReturn( "test_column_label" ).when( rsmd ).getColumnLabel( 1 ); doReturn( "test_column_name" ).when( rsmd ).getColumnName( 1 ); doReturn( true ).doReturn( false ).when( res ).next(); doReturn( "test_val" ).when( res ).getObject( 1 ); TableModel result = factory.parametrizeAndQuery( parameters, query, preparedParameterNames ); verify( con, never() ).createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); verify( statement, never() ).setMaxRows( 10 ); verify( statement, never() ).setQueryTimeout( 20 ); verify( statement, never() ).executeQuery( query ); verify( statement ).clearParameters(); verify( statement ).setObject( 1, null ); verify( statement ).setObject( 2, sqlDate ); verify( statement ).setObject( 3, currentDate ); verify( statement ).setObject( 4, "val_3" ); verify( statement ).executeQuery(); assertThat( result, is( notNullValue() ) ); assertThat( result.getRowCount(), is( equalTo( 1 ) ) ); assertThat( result.getColumnCount(), is( equalTo( 1 ) ) ); assertThat( result.getColumnName( 0 ), is( equalTo( "test_column_label" ) ) ); assertThat( (String) result.getValueAt( 0, 0 ), is( equalTo( "test_val" ) ) ); } @Test public void testIsExpandArrays() { assertThat( factory.isExpandArrays(), is( equalTo( true ) ) ); } @Test public void testClose() throws SQLException { factory.close(); verify( connection, never() ).close(); factory.getConnection( mock( DataRow.class ) ); factory.close(); verify( connection ).close(); } @Test public void testClone() { SimpleSQLReportDataFactory result = factory.clone(); assertThat( result, is( not( sameInstance( factory ) ) ) ); assertThat( result.getConnectionProvider(), is( equalTo( factory.getConnectionProvider() ) ) ); } @Test( expected = NullPointerException.class ) public void testSetConnectionProviderWithoutProvider() { ConnectionProvider connectionProvider = null; factory.setConnectionProvider( connectionProvider ); } @Test( expected = IllegalStateException.class ) public void testSetConnectionProviderWithConnection() throws SQLException { factory.getConnection( mock( DataRow.class ) ); ConnectionProvider connectionProvider = mock( ConnectionProvider.class ); factory.setConnectionProvider( connectionProvider ); } @Test public void testSetConnectionProvide() { ConnectionProvider connectionProvider = mock( ConnectionProvider.class ); factory.setConnectionProvider( connectionProvider ); assertThat( factory.getConnectionProvider(), is( equalTo( connectionProvider ) ) ); } @Test public void testIsQueryExecutable() { assertThat( factory.isQueryExecutable( QUERY, null ), is( equalTo( true ) ) ); } @Test public void testGetQueryNames() { assertThat( factory.getQueryNames(), is( emptyArray() ) ); } @SuppressWarnings( "unchecked" ) @Test public void testGetConnectionHash() { StaticConnectionProvider provider = mock( StaticConnectionProvider.class ); doReturn( "test_hash" ).when( provider ).getConnectionHash(); doReturn( provider ).when( factory ).getConnectionProvider(); Object result = factory.getQueryHash( QUERY, null ); assertThat( result, is( instanceOf( List.class ) ) ); List<Object> list = (List<Object>) result; assertThat( list.size(), is( equalTo( 3 ) ) ); assertThat( (String) list.get( 0 ), is( equalTo( factory.getClass().getName() ) ) ); assertThat( (String) list.get( 1 ), is( equalTo( QUERY ) ) ); assertThat( (String) list.get( 2 ), is( equalTo( "test_hash" ) ) ); } @Test public void testGetReferencedFieldsCloseItsConnection() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); this.connection = null; String[] result = factory.getReferencedFields( QUERY + "${param}", parameters ); verify(factory, times(1)).close(); } @Test public void testGetReferencedFieldsDoNotCloseExistConnection() throws ReportDataFactoryException, SQLException { DataRow parameters = mock( DataRow.class ); this.connection = factory.getConnection( parameters ); String[] result = factory.getReferencedFields( QUERY + "${param}", parameters ); verify(factory, times(0)).close(); } }