/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.database.execution;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import de.rcenvironment.components.database.common.DatabaseComponentConstants;
import de.rcenvironment.components.database.common.jdbc.JDBCDriverInformation;
import de.rcenvironment.components.database.common.jdbc.JDBCDriverService;
import de.rcenvironment.core.component.api.ComponentException;
import de.rcenvironment.core.component.execution.api.Component;
import de.rcenvironment.core.component.testutils.ComponentContextMock;
import de.rcenvironment.core.component.testutils.ComponentTestWrapper;
import de.rcenvironment.core.datamodel.api.DataType;
import de.rcenvironment.core.datamodel.api.TypedDatumFactory;
import de.rcenvironment.core.datamodel.api.TypedDatumService;
/**
* Component tests for {@link DatabaseComponent}..
*
* @author Oliver Seebach
*/
public class DatabaseComponentTest {
private static final String ESCAPED_SLASH = "\"";
private static final String CONNECTOR_NAME = "ConnectorName";
private static final String ANY_URL = "AnyURL";
private static final String SELECT_SOMETHING = "SELECT something";
private static final String DEF_OUTPUT_NAME = "out";
private static final String DEF_STATEMENT_NAME = "some name";
/**
* Expected fails.
*/
@Rule
public ExpectedException thrown = ExpectedException.none();
private ComponentTestWrapper component;
private ComponentContextMock context;
private TypedDatumFactory typedDatumFactory;
private Set<JDBCDriverInformation> createJDBCDriverInformationSetMock() {
// JDBC INFORMATION
JDBCDriverInformation driverInfoMock = EasyMock.createNiceMock(JDBCDriverInformation.class);
EasyMock.expect(driverInfoMock.getDisplayName()).andReturn(CONNECTOR_NAME).anyTimes();
EasyMock.expect(driverInfoMock.getUrlScheme()).andReturn(ANY_URL).anyTimes();
EasyMock.replay(driverInfoMock);
Set<JDBCDriverInformation> jdbcInformationsSet = new HashSet<JDBCDriverInformation>();
jdbcInformationsSet.add(driverInfoMock);
return jdbcInformationsSet;
}
private Set<JDBCDriverInformation> createEmptyJDBCDriverInformationSetMock() {
// JDBC INFORMATION
JDBCDriverInformation driverInfoMock = EasyMock.createNiceMock(JDBCDriverInformation.class);
EasyMock.expect(driverInfoMock.getDisplayName()).andReturn(CONNECTOR_NAME).anyTimes();
EasyMock.expect(driverInfoMock.getUrlScheme()).andReturn(ANY_URL).anyTimes();
EasyMock.replay(driverInfoMock);
Set<JDBCDriverInformation> jdbcInformationsSet = new HashSet<JDBCDriverInformation>();
return jdbcInformationsSet;
}
private PreparedStatement createPreparedStatementMock(ResultSet resultSetMock) throws SQLException {
PreparedStatement preparedStatementMock = EasyMock.createStrictMock(PreparedStatement.class);
EasyMock.expect(preparedStatementMock.executeQuery()).andStubReturn(resultSetMock);
EasyMock.expect(preparedStatementMock.isClosed()).andReturn(false);
preparedStatementMock.close();
EasyMock.expectLastCall();
EasyMock.replay(preparedStatementMock);
return preparedStatementMock;
}
private Statement createStatementMock(ResultSet resultSetMock) throws SQLException {
Statement statementMock = EasyMock.createStrictMock(Statement.class);
EasyMock.expect(statementMock.getResultSet()).andStubReturn(resultSetMock);
EasyMock.replay(statementMock);
return statementMock;
}
private Connection createConnectionFailsToCreateStatementMock(Statement statementMock, PreparedStatement preparedStatementMock)
throws SQLException {
Connection connectionMock = EasyMock.createStrictMock(Connection.class);
EasyMock.expect(connectionMock.prepareStatement(EasyMock.anyObject(String.class))).andStubThrow(
EasyMock.createNiceMock(SQLException.class));
return connectionMock;
}
private Connection createConnectionMock(Statement statementMock, PreparedStatement preparedStatementMock) throws SQLException {
Connection connectionMock = EasyMock.createStrictMock(Connection.class);
EasyMock.expect(connectionMock.createStatement()).andStubReturn(statementMock);
EasyMock.expect(connectionMock.prepareStatement(EasyMock.anyObject(String.class))).andStubReturn(preparedStatementMock);
EasyMock.expect(connectionMock.getAutoCommit()).andStubReturn(false);
EasyMock.expect(connectionMock.isClosed()).andStubReturn(false);
connectionMock.setAutoCommit(EasyMock.anyBoolean());
EasyMock.expectLastCall().anyTimes();
EasyMock.expect(connectionMock.isClosed()).andReturn(false).anyTimes();
connectionMock.close();
EasyMock.expectLastCall().anyTimes();
EasyMock.expect(connectionMock.setSavepoint(EasyMock.anyObject(String.class))).andStubReturn(
EasyMock.createNiceMock(Savepoint.class));
connectionMock.commit();
EasyMock.expectLastCall().anyTimes();
EasyMock.expect(connectionMock.isClosed()).andReturn(true).anyTimes();
connectionMock.releaseSavepoint(EasyMock.anyObject(Savepoint.class));
EasyMock.expectLastCall().anyTimes();
connectionMock.setAutoCommit(EasyMock.anyBoolean());
EasyMock.expectLastCall();
connectionMock.close();
EasyMock.expectLastCall();
EasyMock.expect(connectionMock.isClosed()).andReturn(true).anyTimes();
EasyMock.replay(connectionMock);
return connectionMock;
}
private ResultSet createResultSetMock(int rows, int cols) throws SQLException {
ResultSetMetaData resultSetMetaDataMock = EasyMock.createStrictMock(ResultSetMetaData.class);
EasyMock.expect(resultSetMetaDataMock.getColumnCount()).andReturn(cols);
EasyMock.replay(resultSetMetaDataMock);
ResultSet resultSetMock = EasyMock.createStrictMock(ResultSet.class);
// ------------
// CHECK IF RESULT SET IS EMPTY
EasyMock.expect(resultSetMock.isBeforeFirst()).andReturn(true);
EasyMock.expect(resultSetMock.next()).andReturn(true).once();
resultSetMock.beforeFirst();
EasyMock.expectLastCall();
// ------------
// GET SIZE OF RESULT SET
EasyMock.expect(resultSetMock.getMetaData()).andStubReturn(resultSetMetaDataMock);
EasyMock.expect(resultSetMock.next()).andReturn(true).times(rows);
EasyMock.expect(resultSetMock.next()).andReturn(false).once();
resultSetMock.beforeFirst();
EasyMock.expectLastCall().anyTimes();
// ------------
// HANDLE ACTUAL RESULT SET
EasyMock.expect(resultSetMock.getObject(EasyMock.anyInt())).andStubReturn(true);
EasyMock.expect(resultSetMock.getRow()).andStubReturn(3);
EasyMock.expect(resultSetMock.getBoolean(EasyMock.anyInt())).andStubReturn(true);
EasyMock.expect(resultSetMock.next()).andReturn(true).times(5);
EasyMock.expect(resultSetMock.next()).andReturn(false).once();
// ------------
// CLOSE DOWN
EasyMock.expect(resultSetMock.isClosed()).andReturn(false).anyTimes();
resultSetMock.close();
EasyMock.expectLastCall().anyTimes();
EasyMock.replay(resultSetMock);
return resultSetMock;
}
private void setArbitraryConnectionConfigurations() {
context.setConfigurationValue(DatabaseComponentConstants.DATABASE_CONNECTOR, CONNECTOR_NAME);
context.setConfigurationValue(DatabaseComponentConstants.CONFIG_KEY_AUTH_PHRASE, "SomePassword");
context.setConfigurationValue(DatabaseComponentConstants.CONFIG_KEY_AUTH_USER, "SomeUser");
}
private JDBCDriverService createJDBCDriverServiceMock(Connection connectionMock, Set<JDBCDriverInformation> jdbcInformationsSet)
throws SQLException {
JDBCDriverService jdbcDriverServiceMock = EasyMock.createStrictMock(JDBCDriverService.class);
EasyMock.expect(
jdbcDriverServiceMock.getConnectionWithCredentials(EasyMock.anyObject(String.class), EasyMock.anyObject(String.class),
EasyMock.anyObject(String.class))).andStubReturn(connectionMock);
EasyMock.expect(jdbcDriverServiceMock.getRegisteredJDBCDrivers()).andReturn(jdbcInformationsSet).anyTimes();
EasyMock.replay(jdbcDriverServiceMock);
return jdbcDriverServiceMock;
}
/**
* Common setup.
*
* @throws IOException e
* @throws SQLException se
*/
@Before
public void setUp() throws IOException, SQLException {
context = new ComponentContextMock();
component = new ComponentTestWrapper(new DatabaseComponent(), context);
typedDatumFactory = context.getService(TypedDatumService.class).getFactory();
}
/**
* Common cleanup.
*/
@After
public void tearDown() {
component.tearDown(Component.FinalComponentState.FINISHED);
component.dispose();
}
private String convertParametersToKey(int index, String name, String statement, boolean willWriteToOutput, String outputToWriteTo) {
String key = "";
if (name != null) {
name = ESCAPED_SLASH + name + ESCAPED_SLASH;
}
if (statement != null) {
statement = ESCAPED_SLASH + statement + ESCAPED_SLASH;
}
if (outputToWriteTo != null) {
outputToWriteTo = ESCAPED_SLASH + outputToWriteTo + ESCAPED_SLASH;
}
key =
"[{\"index\": " + String.valueOf(index) + " ,\"name\":" + name + ",\"statement\":" + statement
+ ",\"willWriteToOutput\":" + willWriteToOutput + ",\"outputToWriteTo\":" + outputToWriteTo + "}]";
return key;
}
private void setUpValidContext() throws SQLException {
context.addSimulatedOutput("Success", "Success", DataType.Boolean, false, new HashMap<String, String>());
// Add Service to context
context
.addService(
JDBCDriverService.class,
createJDBCDriverServiceMock(
createConnectionMock(createStatementMock(createResultSetMock(5, 5)),
createPreparedStatementMock(createResultSetMock(5, 5))), createJDBCDriverInformationSetMock()));
setArbitraryConnectionConfigurations();
}
/**
* A simple test that runs through with an arbitrary valid setup.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testRunThroughSimple() throws SQLException, ComponentException {
setUpValidContext();
context.addSimulatedOutput(DEF_OUTPUT_NAME, DEF_OUTPUT_NAME, DataType.SmallTable, true, null);
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, "SELECT * FROM myTable;", true, DEF_OUTPUT_NAME);
context.setConfigurationValue((DatabaseComponentConstants.DB_STATEMENTS_KEY), key);
component.start();
}
/**
* A test that checks if null statements are handled correctly.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testValidationOfNullStatement() throws ComponentException {
context.setConfigurationValue(DatabaseComponentConstants.DB_STATEMENTS_KEY, null);
thrown.expect(ComponentException.class);
thrown.expectMessage("error occured while loading statements");
component.start();
}
/**
* A test that checks if invalid statements are handled correctly.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testValidationOfInvalidStatement() throws ComponentException {
context.setConfigurationValue(DatabaseComponentConstants.DB_STATEMENTS_KEY, "rubbish");
thrown.expect(ComponentException.class);
thrown.expectMessage("Failed to parse SQL statement");
component.start();
}
/**
* A test that checks if invalid writing to output settings are handled correctly.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testWriteToOutputButNullDefined() throws ComponentException {
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, SELECT_SOMETHING, true, null);
context.setConfigurationValue(DatabaseComponentConstants.DB_STATEMENTS_KEY, key);
thrown.expect(ComponentException.class);
thrown.expectMessage("is configured to write to an output but no output is selected");
component.start();
}
/**
* A test that checks if invalid writing to output settings are handled correctly.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testWriteToOutputButEmptyDefined() throws ComponentException {
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, SELECT_SOMETHING, true, "");
context.setConfigurationValue(DatabaseComponentConstants.DB_STATEMENTS_KEY, key);
thrown.expect(ComponentException.class);
thrown.expectMessage("is configured to write to an output but no output is selected");
component.start();
}
/**
* A test that checks how missing jdbc drivers are handled.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testNoJDBCDriverRegistered() throws ComponentException, SQLException {
context
.addService(
JDBCDriverService.class,
createJDBCDriverServiceMock(
createConnectionFailsToCreateStatementMock(createStatementMock(createResultSetMock(5, 5)),
createPreparedStatementMock(createResultSetMock(5, 5))), createEmptyJDBCDriverInformationSetMock()));
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, SELECT_SOMETHING, false, null);
context.setConfigurationValue(DatabaseComponentConstants.DB_STATEMENTS_KEY, key);
thrown.expect(ComponentException.class);
thrown.expectMessage("Failed to establish");
component.start();
}
/**
* A simple test that uses invalid statement type.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testInvalidStatementBehavior() throws SQLException, ComponentException {
setUpValidContext();
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, "CREATE TABLE test ()", false, "");
context.setConfigurationValue((DatabaseComponentConstants.DB_STATEMENTS_KEY), key);
thrown.expect(ComponentException.class);
thrown.expectMessage("allowed query types");
component.start();
}
/**
* A simple test where statement creation fails.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testConnectionFailureBehavior() throws SQLException, ComponentException {
context
.addService(
JDBCDriverService.class,
createJDBCDriverServiceMock(
createConnectionFailsToCreateStatementMock(createStatementMock(createResultSetMock(5, 5)),
createPreparedStatementMock(createResultSetMock(5, 5))), createJDBCDriverInformationSetMock()));
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, "SELECT * FROM table WHERE something", false, "");
context.setConfigurationValue((DatabaseComponentConstants.DB_STATEMENTS_KEY), key);
thrown.expect(ComponentException.class);
thrown.expectMessage("Failed to establish database connection");
component.start();
}
/**
* A simple test that has writing to an output selected but not output activated.
*
* @throws SQLException an exception more on database site.
* @throws ComponentException an exception by the component.
*/
@Test
public void testWriteToOutputButNoOutputSelectedBehavior() throws SQLException, ComponentException {
setUpValidContext();
String key = convertParametersToKey(0, DEF_STATEMENT_NAME, "SELECT * FROM myTable;", true, "");
context.setConfigurationValue((DatabaseComponentConstants.DB_STATEMENTS_KEY), key);
thrown.expect(ComponentException.class);
thrown.expectMessage("but no output is selected");
component.start();
}
// /**
// * ................................
// *
// * @throws SQLException
// */
// @Test
// public void simpleStatementTest() throws ComponentException, SQLException {
// // JDBC INFORMATION
// JDBCDriverInformation driverInfoMock = EasyMock.createNiceMock(JDBCDriverInformation.class);
// EasyMock.expect(driverInfoMock.getDisplayName()).andReturn("ConnectorName").anyTimes();
// EasyMock.expect(driverInfoMock.getUrlScheme()).andReturn("AnyURL").anyTimes();
// EasyMock.replay(driverInfoMock);
// HashSet<JDBCDriverInformation> jdbcInformationsSet = new HashSet<JDBCDriverInformation>();
// jdbcInformationsSet.add(driverInfoMock);
//
// int COL_COUNT = 5;
// int ROW_COUNT = 5;
// ResultSetMetaData resultSetMetaDataMock = EasyMock.createStrictMock(ResultSetMetaData.class);
// EasyMock.expect(resultSetMetaDataMock.getColumnCount()).andReturn(COL_COUNT);
// EasyMock.replay(resultSetMetaDataMock);
//
// ResultSet resultSetMock = EasyMock.createStrictMock(ResultSet.class);
// // ------------
// // CHECK IF RESULT SET IS EMPTY
// EasyMock.expect(resultSetMock.isBeforeFirst()).andReturn(true);
// EasyMock.expect(resultSetMock.next()).andReturn(true).once();
// resultSetMock.beforeFirst();
// EasyMock.expectLastCall();
//
// // ------------
// // GET SIZE OF RESULT SET
// EasyMock.expect(resultSetMock.getMetaData()).andStubReturn(resultSetMetaDataMock);
// EasyMock.expect(resultSetMock.next()).andReturn(true).times(ROW_COUNT);
// EasyMock.expect(resultSetMock.next()).andReturn(false).once();
// resultSetMock.beforeFirst();
// EasyMock.expectLastCall().anyTimes();
//
// // ------------
// // HANDLE ACTUAL RESULT SET
// EasyMock.expect(resultSetMock.getObject(EasyMock.anyInt())).andStubReturn(new Boolean(true));
// EasyMock.expect(resultSetMock.getRow()).andStubReturn(3);
// EasyMock.expect(resultSetMock.getBoolean(EasyMock.anyInt())).andStubReturn(true);
//
// EasyMock.expect(resultSetMock.next()).andReturn(true).times(5);
// EasyMock.expect(resultSetMock.next()).andReturn(false).once();
//
// // ------------
// // CLOSE DOWN
// EasyMock.expect(resultSetMock.isClosed()).andReturn(false).anyTimes();
// resultSetMock.close();
// EasyMock.expectLastCall().anyTimes();
//
// EasyMock.replay(resultSetMock);
//
// Statement statementMock = EasyMock.createStrictMock(Statement.class);
// EasyMock.expect(statementMock.getResultSet()).andStubReturn(resultSetMock);
// EasyMock.replay(statementMock);
//
// PreparedStatement preparedStatementMock = EasyMock.createStrictMock(PreparedStatement.class);
// EasyMock.expect(preparedStatementMock.executeQuery()).andStubReturn(resultSetMock);
// EasyMock.expect(preparedStatementMock.isClosed()).andReturn(false);
// preparedStatementMock.close();
// EasyMock.expectLastCall();
// EasyMock.replay(preparedStatementMock);
//
// Connection connectionMock = EasyMock.createStrictMock(Connection.class);
// EasyMock.expect(connectionMock.createStatement()).andStubReturn(statementMock);
// EasyMock.expect(connectionMock.prepareStatement(EasyMock.anyObject(String.class))).andStubReturn(preparedStatementMock);
// EasyMock.expect(connectionMock.getAutoCommit()).andStubReturn(false);
// EasyMock.expect(connectionMock.isClosed()).andStubReturn(false);
// connectionMock.setAutoCommit(EasyMock.anyBoolean());
// EasyMock.expectLastCall().anyTimes();
// EasyMock.expect(connectionMock.isClosed()).andReturn(false).anyTimes();
// connectionMock.close();
// EasyMock.expectLastCall().anyTimes();
// EasyMock.expect(connectionMock.setSavepoint(EasyMock.anyObject(String.class))).andStubReturn(
// EasyMock.createNiceMock(Savepoint.class));
// connectionMock.commit();
// EasyMock.expectLastCall().anyTimes();
// EasyMock.expect(connectionMock.isClosed()).andReturn(true).anyTimes();
// connectionMock.releaseSavepoint(EasyMock.anyObject(Savepoint.class));
// EasyMock.expectLastCall().anyTimes();
// connectionMock.setAutoCommit(EasyMock.anyBoolean());
// EasyMock.expectLastCall();
// connectionMock.close();
// EasyMock.expectLastCall();
// EasyMock.expect(connectionMock.isClosed()).andReturn(true).anyTimes();
// EasyMock.replay(connectionMock);
//
// // Service that returns Connection
// JDBCDriverService jdbcDriverServiceMock = EasyMock.createStrictMock(JDBCDriverService.class);
// EasyMock.expect(
// jdbcDriverServiceMock.getConnectionWithCredentials(EasyMock.anyObject(String.class), EasyMock.anyObject(String.class),
// EasyMock.anyObject(String.class))).andStubReturn(connectionMock);
// EasyMock.expect(jdbcDriverServiceMock.getRegisteredJDBCDrivers()).andReturn(jdbcInformationsSet).anyTimes();
// EasyMock.replay(jdbcDriverServiceMock);
//
// // Add Service to context
// context.addService(JDBCDriverService.class, jdbcDriverServiceMock);
// context.setConfigurationValue(DatabaseComponentConstants.DATABASE_CONNECTOR, "ConnectorName");
// context.setConfigurationValue(DatabaseComponentConstants.CONFIG_KEY_AUTH_PHRASE, "SomePassword");
// context.setConfigurationValue(DatabaseComponentConstants.CONFIG_KEY_AUTH_USER, "SomeUser");
//
// context.addSimulatedOutput("out", "out", DataType.SmallTable, true, null);
// context.addSimulatedOutput("Success", "Success", DataType.Boolean, false, null);
// String key = convertParametersToKey(0, "some name", "SELECT * FROM myTable;", true, "out");
// context.setConfigurationValue((DatabaseComponentConstants.DB_STATEMENTS_KEY), key);
//
// component.start();
//
// assertEquals(true, context.getCapturedOutput("out").toString().contains("true"));
// }
}