/*
* 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.drill.jdbc;
import static org.junit.Assert.fail;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import com.google.common.base.Strings;
import org.apache.drill.exec.ExecTest;
import org.apache.drill.jdbc.test.JdbcAssert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
// TODO: Document this, especially what writers of unit tests need to know
// (e.g., the reusing of connections, the automatic interception of test
// failures and resetting of connections, etc.).
public class JdbcTestBase extends ExecTest {
@SuppressWarnings("unused")
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JdbcTestBase.class);
@Rule
public final TestRule watcher = new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
reset();
}
};
private static CachingConnectionFactory factory;
@BeforeClass
public static void setUpTestCase() {
factory = new SingleConnectionCachingFactory(new ConnectionFactory() {
@Override
public Connection getConnection(ConnectionInfo info) throws SQLException {
return DriverManager.getConnection(info.getUrl(), info.getParamsAsProperties());
}
});
JdbcAssert.setFactory(factory);
}
/**
* Creates a {@link java.sql.Connection connection} using default parameters.
* @param url connection URL
* @throws Exception if connection fails
*/
protected static Connection connect(String url) throws SQLException {
return connect(url, JdbcAssert.getDefaultProperties());
}
/**
* Creates a {@link java.sql.Connection connection} using the given parameters.
* @param url connection URL
* @param info connection info
* @throws Exception if connection fails
*/
protected static Connection connect(String url, Properties info) throws SQLException {
final Connection conn = factory.getConnection(new ConnectionInfo(url, info));
changeSchemaIfSupplied(conn, info);
return conn;
}
/**
* Changes schema of the given connection if the field "schema" is present in {@link java.util.Properties info}.
* Does nothing otherwise.
*/
protected static void changeSchemaIfSupplied(Connection conn, Properties info) {
final String schema = info.getProperty("schema", null);
if (!Strings.isNullOrEmpty(schema)) {
changeSchema(conn, schema);
}
}
// TODO: Purge nextUntilEnd(...) and calls when remaining fragment race
// conditions are fixed (not just DRILL-2245 fixes).
///**
// * Calls {@link ResultSet#next} on given {@code ResultSet} until it returns
// * false. (For TEMPORARY workaround for query cancelation race condition.)
// */
//private static void nextUntilEnd(final ResultSet resultSet) throws SQLException {
// while (resultSet.next()) {
// }
//}
protected static void changeSchema(Connection conn, String schema) {
final String query = String.format("use %s", schema);
try (Statement s = conn.createStatement()) {
@SuppressWarnings("unused")
ResultSet r = s.executeQuery(query);
// TODO: Purge nextUntilEnd(...) and calls when remaining fragment
// race conditions are fixed (not just DRILL-2245 fixes).
// nextUntilEnd(r);
} catch (SQLException e) {
throw new RuntimeException("unable to change schema", e);
}
}
/**
* Resets the factory closing all of the active connections.
*/
protected static void reset() {
try {
factory.closeConnections();
} catch (SQLException e) {
throw new RuntimeException("error while closing connection factory", e);
}
}
@AfterClass
public static void tearDownTestCase() throws Exception {
factory.closeConnections();
}
/**
* Test of whether tests that get connection from JdbcTest.connect(...)
* work with resetting of connections. If enabling this (failing) test method
* causes other test methods to fail, something needs to be fixed.
* (Note: Not a guaranteed test--depends on order in which test methods are
* run.)
*/
@Ignore("Usually disabled; enable temporarily to check tests")
@Test
public void testJdbcTestConnectionResettingCompatibility() {
fail("Intentional failure--did other test methods still run?");
}
}