blob: 34e182f4c304332c074bdadc527e4b5df617c2bb [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.sqoop.manager.oracle;
import static org.junit.Assert.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.junit.Assert;
import org.junit.Test;
import org.apache.sqoop.manager.oracle.util.OracleUtils;
/**
* Test OracleConnectionFactory class including initialization statements.
*/
public class OracleConnectionFactoryTest extends OraOopTestCase {
/**
* This is just to expose methods in OracleConnectionFactory.
*/
public class Exposer extends OracleConnectionFactory {
}
@Test
public void testSetJdbcFetchSize() {
setAndCheckJdbcFetchSize(45);
setAndCheckJdbcFetchSize(2000);
}
private void setAndCheckJdbcFetchSize(int jdbcFetchSize) {
try {
Connection conn = getConnection();
String uniqueJunk =
(new SimpleDateFormat("yyyyMMddHHmmsszzz")).format(new Date())
+ jdbcFetchSize;
org.apache.hadoop.conf.Configuration conf = new Configuration();
conf.setInt(OraOopConstants.ORACLE_ROW_FETCH_SIZE, jdbcFetchSize);
// Prevent setJdbcFetchSize() from logging information about the
// fetch-size
// changing. Otherwise, the junit output will be polluted with messages
// about
// things that aren't actually a problem...
boolean logIsBeingCached =
OracleConnectionFactory.LOG.getCacheLogEntries();
OracleConnectionFactory.LOG.setCacheLogEntries(true);
OraOopOracleQueries.setJdbcFetchSize(conn, conf);
OracleConnectionFactory.LOG.setCacheLogEntries(logIsBeingCached);
String uniqueSql =
String.format("select /*%s*/ * from dba_objects", uniqueJunk);
// Usually dba_objects will have a lot of rows
ResultSet resultSet1 = conn.createStatement().executeQuery(uniqueSql);
while (resultSet1.next()) {
// Nothing to do
continue;
}
ResultSet resultSet2 =
conn.createStatement().executeQuery(OraOopTestConstants.SQL_TABLE);
boolean sqlFound = false;
double rowsPerFetch = 0;
while (resultSet2.next()) {
String sqlText = resultSet2.getString("SQL_TEXT");
if (sqlText.contains(uniqueJunk)) {
sqlFound = true;
rowsPerFetch = resultSet2.getDouble("ROWS_PER_FETCH");
break;
}
}
if (!sqlFound) {
Assert
.fail("Unable to find the performance metrics for the SQL "
+ "statement being used to check the JDBC fetch size.");
}
if (rowsPerFetch < jdbcFetchSize * 0.95
|| rowsPerFetch > jdbcFetchSize * 1.05) {
Assert
.fail(String
.format(
"The measured JDBC fetch size is not within 5%% of what we "
+ "expected. Expected=%s rows/fetch, actual=%s rows/fetch",
jdbcFetchSize, rowsPerFetch));
}
} catch (SQLException ex) {
Assert.fail(ex.getMessage());
}
}
@Test
public void testCreateOracleJdbcConnectionBadUserName() {
try {
// Prevent createOracleJdbcConnection() from logging a problem with the
// bad username we're about to use. Otherwise, the junit output will be
// polluted with messages about things that aren't actually a problem...
boolean logIsBeingCached =
OracleConnectionFactory.LOG.getCacheLogEntries();
OracleConnectionFactory.LOG.setCacheLogEntries(true);
OracleConnectionFactory.createOracleJdbcConnection(
OraOopConstants.ORACLE_JDBC_DRIVER_CLASS, OracleUtils.CONNECT_STRING,
OracleUtils.ORACLE_INVALID_USER_NAME, OracleUtils.ORACLE_USER_PASS);
OracleConnectionFactory.LOG.setCacheLogEntries(logIsBeingCached);
Assert
.fail("OracleConnectionFactory should have thrown an exception in "
+ "response to a rubbish user name.");
} catch (SQLException ex) {
assertEquals(ex.getErrorCode(), 1017); // <- ORA-01017 invalid
// username/password; logon denied.
}
}
@Test
public void testCreateOracleJdbcConnectionBadPassword() {
try {
// Prevent createOracleJdbcConnection() from logging a problem with the
// bad username we're about to use. Otherwise, the junit output will be
// polluted with messages about things that aren't actually a problem...
boolean logIsBeingCached =
OracleConnectionFactory.LOG.getCacheLogEntries();
OracleConnectionFactory.LOG.setCacheLogEntries(true);
OracleConnectionFactory.createOracleJdbcConnection(
OraOopConstants.ORACLE_JDBC_DRIVER_CLASS, OracleUtils.CONNECT_STRING,
OracleUtils.ORACLE_USER_NAME, "a" + OracleUtils.ORACLE_USER_PASS);
OracleConnectionFactory.LOG.setCacheLogEntries(logIsBeingCached);
Assert
.fail("OracleConnectionFactory should have thrown an exception in "
+ "response to a rubbish password.");
} catch (SQLException ex) {
assertEquals(ex.getErrorCode(), 1017); // <- ORA-01017 invalid
// username/password; logon denied.
}
}
@Test
public void testCreateOracleJdbcConnectionOk() {
try {
Connection conn = getConnection();
assertEquals(
"The connection to the Oracle database does not appear to be valid.",
true, conn.isValid(15));
ResultSet resultSet =
conn.createStatement().executeQuery(
"select instance_name from v$instance");
if (!resultSet.next() || resultSet.getString(1).isEmpty()) {
Assert.fail("Got blank instance name from v$instance");
}
} catch (SQLException ex) {
Assert.fail(ex.getMessage());
}
}
@Test
public void testExecuteOraOopSessionInitializationStatements() {
// Exposer.LOG = null;
// protected static final Log LOG =
// LogFactory.getLog(OracleConnectionFactory.class.getName());
OraOopLogFactory.OraOopLog2 oraoopLog = Exposer.LOG;
oraoopLog.setCacheLogEntries(true);
// Check that the default session-initialization statements are reflected in
// the log...
oraoopLog.clearCache();
checkExecuteOraOopSessionInitializationStatements(null);
checkLogContainsText(oraoopLog,
"Initializing Oracle session with SQL : alter session disable "
+ "parallel query");
checkLogContainsText(
oraoopLog,
"Initializing Oracle session with SQL : alter session set "
+ "\"_serial_direct_read\"=true");
// Check that the absence of session-initialization statements is reflected
// in the log...
oraoopLog.clearCache();
checkExecuteOraOopSessionInitializationStatements("");
checkLogContainsText(oraoopLog,
"No Oracle 'session initialization' statements were found to execute");
// This should do nothing (i.e. not throw an exception)...
checkExecuteOraOopSessionInitializationStatements(";");
// This should throw an exception, as Oracle won't know what to do with
// this...
oraoopLog.clearCache();
checkExecuteOraOopSessionInitializationStatements("loremipsum");
checkLogContainsText(oraoopLog, "loremipsum");
checkLogContainsText(oraoopLog, "ORA-00900: invalid SQL statement");
Connection conn = getConnection();
try {
// Try a session-initialization statement that creates a table...
dropTable(conn, OracleUtils.SYSTEMTEST_TABLE_NAME);
checkExecuteOraOopSessionInitializationStatements("create table "
+ OracleUtils.SYSTEMTEST_TABLE_NAME + " (col1 varchar2(1))");
if (!doesTableExist(conn, OracleUtils.SYSTEMTEST_TABLE_NAME)) {
Assert.fail("The session-initialization statement to create the table "
+ OracleUtils.SYSTEMTEST_TABLE_NAME + " did not work.");
}
// Try a sequence of a few statements...
dropTable(conn, OracleUtils.SYSTEMTEST_TABLE_NAME);
checkExecuteOraOopSessionInitializationStatements("create table "
+ OracleUtils.SYSTEMTEST_TABLE_NAME + " (col1 number);insert into "
+ OracleUtils.SYSTEMTEST_TABLE_NAME + " values (1) ; --update "
+ OracleUtils.SYSTEMTEST_TABLE_NAME + " set col1 = col1 + 1; update "
+ OracleUtils.SYSTEMTEST_TABLE_NAME
+ " set col1 = col1 + 1; commit ;;");
ResultSet resultSet =
conn.createStatement().executeQuery(
"select col1 from " + OracleUtils.SYSTEMTEST_TABLE_NAME);
resultSet.next();
int actualValue = resultSet.getInt("col1");
if (actualValue != 2) {
Assert.fail("The table " + OracleUtils.SYSTEMTEST_TABLE_NAME
+ " does not contain the data we expected.");
}
dropTable(conn, OracleUtils.SYSTEMTEST_TABLE_NAME);
} catch (Exception ex) {
Assert.fail(ex.getMessage());
}
}
@Test
public void testParseOraOopSessionInitializationStatements() {
List<String> statements = null;
try {
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(null);
Assert.fail("An IllegalArgumentException should have been thrown.");
} catch (IllegalArgumentException ex) {
// This is what we wanted.
}
org.apache.hadoop.conf.Configuration conf = new Configuration();
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertTrue(statements.size() > 0);
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS, "");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(0, statements.size());
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS, ";");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(0, statements.size());
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS,
";--;\t--");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(0, statements.size());
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS
, "\ta");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(1, statements.size());
if (!statements.get(0).equalsIgnoreCase("a")) {
Assert.fail("Expected a session initialization statement of \"a\"");
}
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS,
"a;b;--c;d;");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(3, statements.size());
if (!statements.get(0).equalsIgnoreCase("a")) {
Assert.fail("Expected a session initialization statement of \"a\"");
}
if (!statements.get(1).equalsIgnoreCase("b")) {
Assert.fail("Expected a session initialization statement of \"b\"");
}
if (!statements.get(2).equalsIgnoreCase("d")) {
Assert.fail("Expected a session initialization statement of \"d\"");
}
// Expressions without default values...
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS,
"set a={expr1};b={expr2}/{expr3};");
conf.set("expr1", "1");
conf.set("expr2", "2");
conf.set("expr3", "3");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(2, statements.size());
String actual = statements.get(0);
String expected = "set a=1";
if (!actual.equalsIgnoreCase(expected)) {
Assert.fail(String.format(
"Expected a session initialization statement of \"%s\", but got \"%s\"."
, expected, actual));
}
actual = statements.get(1);
expected = "b=2/3";
if (!actual.equalsIgnoreCase(expected)) {
Assert.fail(String.format(
"Expected a session initialization statement of \"%s\", but got \"%s\"."
, expected, actual));
}
// Expressions with default values...
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS,
"set c={expr3|66};d={expr4|15}/{expr5|90};");
conf.set("expr3", "20");
// conf.set("expr4", "21");
// conf.set("expr5", "23");
statements =
OracleConnectionFactory
.parseOraOopSessionInitializationStatements(conf);
Assert.assertEquals(2, statements.size());
actual = statements.get(0);
expected = "set c=20";
if (!actual.equalsIgnoreCase(expected)) {
Assert.fail(String.format(
"Expected a session initialization statement of \"%s\", but got \"%s\"."
, expected, actual));
}
actual = statements.get(1);
expected = "d=15/90";
if (!actual.equalsIgnoreCase(expected)) {
Assert.fail(String.format(
"Expected a session initialization statement of \"%s\", but got \"%s\"."
, expected, actual));
}
}
private void dropTable(Connection conn, String tableName) {
try {
conn.createStatement().executeQuery("drop table " + tableName);
if (doesTableExist(conn, tableName)) {
Assert.fail("Unable to drop the table " + tableName);
}
} catch (SQLException ex) {
if (ex.getErrorCode() != 942) { // <- Table or view does not exist
Assert.fail(ex.getMessage());
}
}
}
private boolean doesTableExist(Connection conn, String tableName) {
boolean result = false;
try {
List<OracleTable> tables = OraOopOracleQueries.getTables(conn);
for (int idx = 0; idx < tables.size(); idx++) {
if (tables.get(idx).getName().equalsIgnoreCase(tableName)) {
result = true;
break;
}
}
} catch (SQLException ex) {
Assert.fail(ex.getMessage());
}
return result;
}
private void checkLogContainsText(OraOopLogFactory.OraOopLog2 oraoopLog,
String text) {
if (!oraoopLog.getLogEntries().toLowerCase().contains(text.toLowerCase())) {
Assert.fail(
"The LOG does not contain the following text (when it should):\n\t"
+ text);
}
}
private void checkExecuteOraOopSessionInitializationStatements(
String statements) {
Connection conn = getConnection();
org.apache.hadoop.conf.Configuration conf = new Configuration();
if (statements != null) {
conf.set(OraOopConstants.ORAOOP_SESSION_INITIALIZATION_STATEMENTS,
statements);
}
Exposer.executeOraOopSessionInitializationStatements(conn, conf);
}
@Test
public void testSetSessionClientInfo() {
Connection conn = getConnection();
org.apache.hadoop.conf.Configuration conf = new Configuration();
String moduleName = OraOopConstants.ORACLE_SESSION_MODULE_NAME;
String actionName =
(new SimpleDateFormat("yyyyMMddHHmmsszzz")).format(new Date());
conf.set(OraOopConstants.ORACLE_SESSION_ACTION_NAME, actionName);
try {
PreparedStatement statement =
conn.prepareStatement("select process, module, action "
+ "from v$session " + "where module = ? and action = ?");
statement.setString(1, moduleName);
statement.setString(2, actionName);
// Check no session have this action name - because we haven't applied to
// our session yet...
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
Assert
.fail("There should be no Oracle sessions with an action name of "
+ actionName);
}
// Apply this action name to our session...
OracleConnectionFactory.setSessionClientInfo(conn, conf);
// Now check there is a session with our action name...
int sessionFoundCount = 0;
resultSet = statement.executeQuery();
while (resultSet.next()) {
sessionFoundCount++;
}
if (sessionFoundCount < 1) {
Assert
.fail("Unable to locate an Oracle session with the expected module "
+ "and action.");
}
if (sessionFoundCount > 1) {
Assert
.fail("Multiple sessions were found with the expected module and "
+ "action - we only expected to find one.");
}
} catch (SQLException ex) {
Assert.fail(ex.getMessage());
}
}
private Connection getConnection() {
try {
return OracleConnectionFactory.createOracleJdbcConnection(
OraOopConstants.ORACLE_JDBC_DRIVER_CLASS, OracleUtils.CONNECT_STRING,
OracleUtils.ORACLE_USER_NAME, OracleUtils.ORACLE_USER_PASS);
} catch (SQLException ex) {
Assert.fail(ex.getMessage());
}
return null;
}
}