blob: f3ebc8a1d4dc823a5f1ae4e8b62ccb6cb4c93094 [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.calcite.avatica.jdbc;
import org.apache.calcite.avatica.AvaticaPreparedStatement;
import org.apache.calcite.avatica.Meta.ConnectionHandle;
import org.apache.calcite.avatica.Meta.Signature;
import org.apache.calcite.avatica.Meta.StatementHandle;
import com.google.common.cache.Cache;
import org.junit.Test;
import org.mockito.Mockito;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link JdbcMeta}.
*/
public class JdbcMetaTest {
@Test public void testExceptionPropagation() throws SQLException {
JdbcMeta meta = new JdbcMeta("url");
final Throwable e = new Exception();
final RuntimeException rte;
try {
meta.propagate(e);
fail("Expected an exception to be thrown");
} catch (RuntimeException caughtException) {
rte = caughtException;
assertThat(rte.getCause(), is(e));
}
}
@Test public void testPrepareSetsMaxRows() throws Exception {
final String id = UUID.randomUUID().toString();
final String sql = "SELECT * FROM FOO";
final int maxRows = 500;
final ConnectionHandle ch = new ConnectionHandle(id);
final AtomicInteger statementIdGenerator = new AtomicInteger(0);
JdbcMeta meta = Mockito.mock(JdbcMeta.class);
Connection connection = Mockito.mock(Connection.class);
PreparedStatement statement = Mockito.mock(PreparedStatement.class);
ResultSetMetaData resultSetMetaData = Mockito.mock(ResultSetMetaData.class);
ParameterMetaData parameterMetaData = Mockito.mock(ParameterMetaData.class);
@SuppressWarnings("unchecked")
Cache<Integer, StatementInfo> statementCache =
(Cache<Integer, StatementInfo>) Mockito.mock(Cache.class);
Mockito.when(meta.getStatementIdGenerator()).thenReturn(statementIdGenerator);
Mockito.when(meta.getStatementCache()).thenReturn(statementCache);
Mockito.when(meta.getConnection(id)).thenReturn(connection);
Mockito.when(connection.prepareStatement(sql)).thenReturn(statement);
Mockito.when(statement.isWrapperFor(AvaticaPreparedStatement.class)).thenReturn(false);
Mockito.when(statement.getMetaData()).thenReturn(resultSetMetaData);
Mockito.when(statement.getParameterMetaData()).thenReturn(parameterMetaData);
// Call the real methods
Mockito.doCallRealMethod().when(meta).setMaxRows(statement, maxRows);
Mockito.doCallRealMethod().when(meta).prepare(ch, sql, maxRows);
meta.prepare(ch, sql, maxRows);
Mockito.verify(statement).setMaxRows(maxRows);
}
@Test public void testPrepareAndExecuteSetsMaxRows() throws Exception {
final String id = UUID.randomUUID().toString();
final int statementId = 12345;
final String sql = "SELECT * FROM FOO";
final int maxRows = 500;
JdbcMeta meta = Mockito.mock(JdbcMeta.class);
PreparedStatement statement = Mockito.mock(PreparedStatement.class);
@SuppressWarnings("unchecked")
Cache<Integer, StatementInfo> statementCache =
(Cache<Integer, StatementInfo>) Mockito.mock(Cache.class);
Signature signature = Mockito.mock(Signature.class);
final StatementInfo statementInfo = new StatementInfo(statement);
final StatementHandle statementHandle = new StatementHandle(id, statementId, signature);
Mockito.when(meta.getStatementCache()).thenReturn(statementCache);
Mockito.when(statementCache.getIfPresent(statementId)).thenReturn(statementInfo);
Mockito.when(statement.getResultSet()).thenReturn(null);
// The real methods
Mockito.when(meta.prepareAndExecute(statementHandle, sql, maxRows, 50, null)).
thenCallRealMethod();
Mockito.doCallRealMethod().when(meta).setMaxRows(statement, maxRows);
// Call our method
meta.prepareAndExecute(statementHandle, sql, maxRows, 50, null);
// Verify we called setMaxRows with the right value
Mockito.verify(statement).setMaxRows(maxRows);
}
@Test public void testConcurrentConnectionOpening() throws Exception {
final Map<String, String> properties = Collections.emptyMap();
final Connection conn = Mockito.mock(Connection.class);
// Override JdbcMeta to shim in a fake Connection object. Irrelevant for the test
JdbcMeta meta = new JdbcMeta("jdbc:url") {
@Override protected Connection createConnection(String url, Properties info) {
return conn;
}
};
ConnectionHandle ch1 = new ConnectionHandle("id1");
meta.openConnection(ch1, properties);
assertEquals(conn, meta.getConnectionCache().getIfPresent(ch1.id));
try {
meta.openConnection(ch1, properties);
fail("Should not be allowed to open two connections with the same ID");
} catch (RuntimeException e) {
// pass
}
// Cached object should not change
assertEquals(conn, meta.getConnectionCache().getIfPresent(ch1.id));
}
@Test public void testRacingConnectionOpens() throws Exception {
final Map<String, String> properties = Collections.emptyMap();
final Connection conn1 = Mockito.mock(Connection.class);
final Connection conn2 = Mockito.mock(Connection.class);
final ConnectionHandle ch1 = new ConnectionHandle("id1");
// Override JdbcMeta to shim in a fake Connection object. Irrelevant for the test
JdbcMeta meta = new JdbcMeta("jdbc:url") {
@Override protected Connection createConnection(String url, Properties info) {
// Hack to mimic the race condition of a connection being cached by another thread.
getConnectionCache().put(ch1.id, conn1);
// Return our "newly created" connectino
return conn2;
}
};
try {
meta.openConnection(ch1, properties);
fail("Should see an exception when the cache already contained our connection after"
+ " creating it");
} catch (RuntimeException e) {
// pass
}
// Our opened connection should get closed when this race condition happens
Mockito.verify(conn2).close();
}
}
// End JdbcMetaTest.java