blob: 452309c2cfd1ce6469d1dae156b5dbc93502a5f5 [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.remote;
import org.apache.calcite.avatica.AvaticaConnection;
import org.apache.calcite.avatica.AvaticaSpecificDatabaseMetaData;
import org.apache.calcite.avatica.AvaticaSqlException;
import org.apache.calcite.avatica.AvaticaStatement;
import org.apache.calcite.avatica.AvaticaUtils;
import org.apache.calcite.avatica.ConnectionPropertiesImpl;
import org.apache.calcite.avatica.ConnectionSpec;
import org.apache.calcite.avatica.Meta;
import org.apache.calcite.avatica.Meta.DatabaseProperty;
import org.apache.calcite.avatica.jdbc.JdbcMeta;
import org.apache.calcite.avatica.remote.AvaticaServersForTest.FullyRemoteJdbcMetaFactory;
import org.apache.calcite.avatica.remote.Service.ErrorResponse;
import org.apache.calcite.avatica.remote.Service.Response;
import org.apache.calcite.avatica.server.HttpServer;
import org.apache.calcite.avatica.util.ArrayImpl;
import org.apache.calcite.avatica.util.FilteredConstants;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import org.junit.AfterClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.Array;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.UUID;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/** Tests covering {@link RemoteMeta}. */
@RunWith(Parameterized.class)
public class RemoteMetaTest {
private static final AvaticaServersForTest SERVERS = new AvaticaServersForTest();
private static final Random RANDOM = new Random();
private final HttpServer server;
private final String url;
private final int port;
private final Driver.Serialization serialization;
@Parameters(name = "{0}")
public static List<Object[]> parameters() throws Exception {
SERVERS.startServers();
return SERVERS.getJUnitParameters();
}
public RemoteMetaTest(Driver.Serialization serialization, HttpServer server) {
this.server = server;
this.port = this.server.getPort();
this.serialization = serialization;
this.url = SERVERS.getJdbcUrl(port, serialization);
}
@AfterClass public static void afterClass() throws Exception {
if (null != SERVERS) {
SERVERS.stopServers();
}
}
private static Meta getMeta(AvaticaConnection conn) throws Exception {
Field f = AvaticaConnection.class.getDeclaredField("meta");
f.setAccessible(true);
return (Meta) f.get(conn);
}
private static Meta.ExecuteResult prepareAndExecuteInternal(AvaticaConnection conn,
final AvaticaStatement statement, String sql, int maxRowCount) throws Exception {
Method m =
AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal",
AvaticaStatement.class, String.class, long.class);
m.setAccessible(true);
return (Meta.ExecuteResult) m.invoke(conn, statement, sql, maxRowCount);
}
private static Connection getConnection(JdbcMeta m, String id) throws Exception {
Field f = JdbcMeta.class.getDeclaredField("connectionCache");
f.setAccessible(true);
//noinspection unchecked
Cache<String, Connection> connectionCache = (Cache<String, Connection>) f.get(m);
return connectionCache.getIfPresent(id);
}
@Test public void testRemoteExecuteMaxRowCount() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
final AvaticaStatement statement = conn.createStatement();
prepareAndExecuteInternal(conn, statement,
"select * from (values ('a', 1), ('b', 2))", 0);
ResultSet rs = statement.getResultSet();
int count = 0;
while (rs.next()) {
count++;
}
assertEquals("Check maxRowCount=0 and ResultSets is 0 row", count, 0);
assertEquals("Check result set meta is still there",
rs.getMetaData().getColumnCount(), 2);
rs.close();
statement.close();
conn.close();
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-1301">[CALCITE-1301]
* Add cancel flag to AvaticaStatement</a>. */
@Test public void testCancel() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
final AvaticaStatement statement = conn.createStatement();
final String sql = "select * from (values ('a', 1), ('b', 2))";
final ResultSet rs = statement.executeQuery(sql);
int count = 0;
loop:
for (;;) {
switch (count++) {
case 0:
assertThat(rs.next(), is(true));
break;
case 1:
rs.getStatement().cancel();
try {
boolean x = rs.next();
fail("expected exception, got " + x);
} catch (SQLException e) {
assertThat(e.getMessage(), is("Statement canceled"));
}
break loop;
default:
fail("count: " + count);
}
}
assertThat(count, is(2));
assertThat(statement.isClosed(), is(false));
rs.close();
assertThat(statement.isClosed(), is(false));
statement.close();
assertThat(statement.isClosed(), is(true));
statement.close();
assertThat(statement.isClosed(), is(true));
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-780">[CALCITE-780]
* HTTP error 413 when sending a long string to the Avatica server</a>. */
@Test public void testRemoteExecuteVeryLargeQuery() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try {
// Before the bug was fixed, a value over 7998 caused an HTTP 413.
// 16K bytes, I guess.
checkLargeQuery(8);
checkLargeQuery(240);
checkLargeQuery(8000);
checkLargeQuery(240000);
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
private void checkLargeQuery(int n) throws Exception {
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
final AvaticaStatement statement = conn.createStatement();
final String frenchDisko = "It said human existence is pointless\n"
+ "As acts of rebellious solidarity\n"
+ "Can bring sense in this world\n"
+ "La resistance!\n";
final String sql = "select '"
+ longString(frenchDisko, n)
+ "' as s from (values 'x')";
prepareAndExecuteInternal(conn, statement, sql, -1);
ResultSet rs = statement.getResultSet();
int count = 0;
while (rs.next()) {
count++;
}
assertThat(count, is(1));
rs.close();
statement.close();
conn.close();
}
}
/** Creates a string of exactly {@code length} characters by concatenating
* {@code fragment}. */
private static String longString(String fragment, int length) {
assert fragment.length() > 0;
final StringBuilder buf = new StringBuilder();
while (buf.length() < length) {
buf.append(fragment);
}
buf.setLength(length);
return buf.toString();
}
@Test public void testRemoteConnectionProperties() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
String id = conn.id;
final Map<String, ConnectionPropertiesImpl> m = ((RemoteMeta) getMeta(conn)).propsMap;
assertFalse("remote connection map should start ignorant", m.containsKey(id));
// force creating a connection object on the remote side.
try (final Statement stmt = conn.createStatement()) {
assertTrue("creating a statement starts a local object.", m.containsKey(id));
assertTrue(stmt.execute("select count(1) from EMP"));
}
Connection remoteConn = getConnection(FullyRemoteJdbcMetaFactory.getInstance(), id);
final boolean defaultRO = remoteConn.isReadOnly();
final boolean defaultAutoCommit = remoteConn.getAutoCommit();
final String defaultCatalog = remoteConn.getCatalog();
final String defaultSchema = remoteConn.getSchema();
conn.setReadOnly(!defaultRO);
assertTrue("local changes dirty local state", m.get(id).isDirty());
assertEquals("remote connection has not been touched", defaultRO, remoteConn.isReadOnly());
conn.setAutoCommit(!defaultAutoCommit);
assertEquals("remote connection has not been touched",
defaultAutoCommit, remoteConn.getAutoCommit());
// further interaction with the connection will force a sync
try (final Statement stmt = conn.createStatement()) {
assertEquals(!defaultAutoCommit, remoteConn.getAutoCommit());
assertFalse("local values should be clean", m.get(id).isDirty());
}
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testRemoteStatementInsert() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try {
final String t = AvaticaUtils.unique("TEST_TABLE2");
AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
Statement statement = conn.createStatement();
final String create =
String.format(Locale.ROOT, "create table if not exists %s ("
+ " id int not null, msg varchar(255) not null)", t);
int status = statement.executeUpdate(create);
assertEquals(status, 0);
statement = conn.createStatement();
final String update =
String.format(Locale.ROOT, "insert into %s values ('%d', '%s')",
t, RANDOM.nextInt(Integer.MAX_VALUE), UUID.randomUUID());
status = statement.executeUpdate(update);
assertEquals(status, 1);
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testBigints() throws Exception {
final String table = "TESTBIGINTS";
ConnectionSpec.getDatabaseLock().lock();
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
Statement stmt = conn.createStatement()) {
assertFalse(stmt.execute("DROP TABLE IF EXISTS " + table));
assertFalse(stmt.execute("CREATE TABLE " + table + " (id BIGINT)"));
assertFalse(stmt.execute("INSERT INTO " + table + " values(10)"));
ResultSet results = conn.getMetaData().getColumns(null, null, table, null);
assertTrue(results.next());
assertEquals(table, results.getString(3));
// ordinal position
assertEquals(1L, results.getLong(17));
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testOpenConnectionWithProperties() throws Exception {
// This tests that username and password are used for creating a connection on the
// server. If this was not the case, it would succeed.
try {
DriverManager.getConnection(url, "john", "doe");
fail("expected exception");
} catch (RuntimeException e) {
assertEquals("Remote driver error: "
+ "SQLInvalidAuthorizationSpecException: invalid authorization specification - "
+ "not found: john"
+ " -> HsqlException: invalid authorization specification - not found: john",
e.getMessage());
}
}
@Test public void testRemoteConnectionsAreDifferent() throws SQLException {
ConnectionSpec.getDatabaseLock().lock();
try {
Connection conn1 = DriverManager.getConnection(url);
Statement stmt = conn1.createStatement();
stmt.execute("DECLARE LOCAL TEMPORARY TABLE"
+ " buffer (id INTEGER PRIMARY KEY, textdata VARCHAR(100))");
stmt.execute("insert into buffer(id, textdata) values(1, 'abc')");
stmt.executeQuery("select * from buffer");
// The local temporary table is local to the connection above, and should
// not be visible on another connection
Connection conn2 = DriverManager.getConnection(url);
Statement stmt2 = conn2.createStatement();
try {
stmt2.executeQuery("select * from buffer");
fail("expected exception");
} catch (Exception e) {
assertEquals("Error -1 (00000) : Error while executing SQL \"select * from buffer\". "
+ "Remote driver error: "
+ "SQLSyntaxErrorException: user lacks privilege or object not found: BUFFER -> "
+ "HsqlException: user lacks privilege or object not found: BUFFER",
e.getMessage());
}
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Ignore("[CALCITE-942] AvaticaConnection should fail-fast when closed.")
@Test public void testRemoteConnectionClosing() throws Exception {
AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
// Verify connection is usable
conn.createStatement();
conn.close();
// After closing the connection, it should not be usable anymore
try {
conn.createStatement();
fail("expected exception");
} catch (SQLException e) {
assertThat(e.getMessage(),
containsString("Connection is closed"));
}
}
@Test public void testExceptionPropagation() throws Exception {
final String sql = "SELECT * from EMP LIMIT FOOBARBAZ";
ConnectionSpec.getDatabaseLock().lock();
try (final AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
final Statement stmt = conn.createStatement()) {
try {
// invalid SQL
stmt.execute(sql);
fail("Expected an AvaticaSqlException");
} catch (AvaticaSqlException e) {
assertEquals(ErrorResponse.UNKNOWN_ERROR_CODE, e.getErrorCode());
assertEquals(ErrorResponse.UNKNOWN_SQL_STATE, e.getSQLState());
assertTrue("Message should contain original SQL, was '" + e.getMessage() + "'",
e.getMessage().contains(sql));
assertEquals(1, e.getStackTraces().size());
final String stacktrace = e.getStackTraces().get(0);
final String substring = "unexpected token: FOOBARBAZ";
assertTrue("Message should contain '" + substring + "', was '" + e.getMessage() + ",",
stacktrace.contains(substring));
}
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testRemoteColumnsMeta() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try {
// Verify all columns are retrieved, thus that frame-based fetching works correctly
// for columns
int rowCount = 0;
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
ResultSet rs = conn.getMetaData().getColumns(null, null, null, null);
Statement stmt = rs.getStatement();
while (rs.next()) {
rowCount++;
}
rs.close();
// The implicitly created statement should have been closed
assertTrue(stmt.isClosed());
}
// default fetch size is 100, we are well beyond it
assertTrue(rowCount > 900);
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testArrays() throws SQLException {
ConnectionSpec.getDatabaseLock().lock();
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
Statement stmt = conn.createStatement()) {
ResultSet resultSet =
stmt.executeQuery("select * from (values ('a', array['b', 'c']));");
assertTrue(resultSet.next());
assertEquals("a", resultSet.getString(1));
Array arr = resultSet.getArray(2);
assertTrue(arr instanceof ArrayImpl);
Object[] values = (Object[]) ((ArrayImpl) arr).getArray();
assertArrayEquals(new String[]{"b", "c"}, values);
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testBinaryAndStrings() throws Exception {
final String tableName = "testbinaryandstrs";
final byte[] data = "asdf".getBytes(StandardCharsets.UTF_8);
ConnectionSpec.getDatabaseLock().lock();
try (final Connection conn = DriverManager.getConnection(url);
final Statement stmt = conn.createStatement()) {
assertFalse(stmt.execute("DROP TABLE IF EXISTS " + tableName));
assertFalse(stmt.execute("CREATE TABLE " + tableName + "(id int, bin BINARY(4))"));
try (final PreparedStatement prepStmt = conn.prepareStatement(
"INSERT INTO " + tableName + " values(1, ?)")) {
prepStmt.setBytes(1, data);
assertFalse(prepStmt.execute());
}
try (ResultSet results = stmt.executeQuery("SELECT id, bin from " + tableName)) {
assertTrue(results.next());
assertEquals(1, results.getInt(1));
// byte comparison should work
assertArrayEquals("Bytes were " + Arrays.toString(results.getBytes(2)),
data, results.getBytes(2));
// as should string
assertEquals(new String(data, StandardCharsets.UTF_8), results.getString(2));
assertFalse(results.next());
}
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testLocalStackTraceHasServerStackTrace() {
ConnectionSpec.getDatabaseLock().lock();
try {
Statement statement = DriverManager.getConnection(url).createStatement();
statement.executeQuery("SELECT * FROM BOGUS_TABLE_DEF_DOESNT_EXIST");
} catch (SQLException e) {
// Verify that we got the expected exception
assertThat(e, instanceOf(AvaticaSqlException.class));
// Attempt to verify that we got a "server-side" class in the stack.
assertThat(Throwables.getStackTraceAsString(e),
containsString(JdbcMeta.class.getName()));
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testServerAddressInResponse() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try {
URL url = new URL("http://localhost:" + this.port);
AvaticaHttpClient httpClient = new AvaticaHttpClientImpl(url);
byte[] request;
Service.OpenConnectionRequest jsonReq = new Service.OpenConnectionRequest(
UUID.randomUUID().toString(), Collections.<String, String>emptyMap());
switch (this.serialization) {
case JSON:
request = JsonService.MAPPER.writeValueAsBytes(jsonReq);
break;
case PROTOBUF:
ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
request = pbTranslation.serializeRequest(jsonReq);
break;
default:
throw new IllegalStateException("Should not reach here");
}
byte[] response = httpClient.send(request);
Service.OpenConnectionResponse openCnxnResp;
switch (this.serialization) {
case JSON:
openCnxnResp = JsonService.MAPPER.readValue(response,
Service.OpenConnectionResponse.class);
break;
case PROTOBUF:
ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
Response genericResp = pbTranslation.parseResponse(response);
assertTrue("Expected an OpenConnnectionResponse, but got " + genericResp.getClass(),
genericResp instanceof Service.OpenConnectionResponse);
openCnxnResp = (Service.OpenConnectionResponse) genericResp;
break;
default:
throw new IllegalStateException("Should not reach here");
}
String hostname = InetAddress.getLocalHost().getHostName();
assertNotNull(openCnxnResp.rpcMetadata);
assertEquals(hostname + ":" + this.port, openCnxnResp.rpcMetadata.serverAddress);
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testCommitRollback() throws Exception {
final String productTable = "commitrollback_products";
final String salesTable = "commitrollback_sales";
ConnectionSpec.getDatabaseLock().lock();
try (final Connection conn = DriverManager.getConnection(url);
final Statement stmt = conn.createStatement()) {
assertFalse(stmt.execute("DROP TABLE IF EXISTS " + productTable));
assertFalse(
stmt.execute(
String.format(Locale.ROOT,
"CREATE TABLE %s(id integer, stock integer)",
productTable)));
assertFalse(stmt.execute("DROP TABLE IF EXISTS " + salesTable));
assertFalse(
stmt.execute(
String.format(Locale.ROOT,
"CREATE TABLE %s(id integer, units_sold integer)",
salesTable)));
final int productId = 1;
// No products and no sales
assertFalse(
stmt.execute(
String.format(Locale.ROOT, "INSERT INTO %s VALUES(%d, 0)",
productTable, productId)));
assertFalse(
stmt.execute(
String.format(Locale.ROOT, "INSERT INTO %s VALUES(%d, 0)",
salesTable, productId)));
conn.setAutoCommit(false);
PreparedStatement productStmt = conn.prepareStatement(
String.format(Locale.ROOT,
"UPDATE %s SET stock = stock + ? WHERE id = ?", productTable));
PreparedStatement salesStmt = conn.prepareStatement(
String.format(Locale.ROOT,
"UPDATE %s SET units_sold = units_sold + ? WHERE id = ?",
salesTable));
// No stock
assertEquals(0, getInventory(conn, productTable, productId));
// Set a stock of 10 for product 1
productStmt.setInt(1, 10);
productStmt.setInt(2, productId);
productStmt.executeUpdate();
conn.commit();
assertEquals(10, getInventory(conn, productTable, productId));
// Sold 5 items (5 in stock, 5 sold)
productStmt.setInt(1, -5);
productStmt.setInt(2, productId);
productStmt.executeUpdate();
salesStmt.setInt(1, 5);
salesStmt.setInt(2, productId);
salesStmt.executeUpdate();
conn.commit();
// We will definitely see the updated values
assertEquals(5, getInventory(conn, productTable, productId));
assertEquals(5, getSales(conn, salesTable, productId));
// Update some "bad" values
productStmt.setInt(1, -10);
productStmt.setInt(2, productId);
productStmt.executeUpdate();
salesStmt.setInt(1, 10);
salesStmt.setInt(2, productId);
salesStmt.executeUpdate();
// We just went negative, nonsense. Better rollback.
conn.rollback();
// Should still have 5 and 5
assertEquals(5, getInventory(conn, productTable, productId));
assertEquals(5, getSales(conn, salesTable, productId));
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
private int getInventory(Connection conn, String productTable, int productId) throws Exception {
try (Statement stmt = conn.createStatement()) {
ResultSet results = stmt.executeQuery(
String.format(Locale.ROOT, "SELECT stock FROM %s WHERE id = %d",
productTable, productId));
assertTrue(results.next());
return results.getInt(1);
}
}
private int getSales(Connection conn, String salesTable, int productId) throws Exception {
try (Statement stmt = conn.createStatement()) {
ResultSet results = stmt.executeQuery(
String.format(Locale.ROOT, "SELECT units_sold FROM %s WHERE id = %d",
salesTable, productId));
assertTrue(results.next());
return results.getInt(1);
}
}
@Test public void getAvaticaVersion() throws Exception {
ConnectionSpec.getDatabaseLock().lock();
try (final Connection conn = DriverManager.getConnection(url)) {
DatabaseMetaData metadata = conn.getMetaData();
assertTrue("DatabaseMetaData is not an instance of AvaticaDatabaseMetaData",
metadata instanceof AvaticaSpecificDatabaseMetaData);
AvaticaSpecificDatabaseMetaData avaticaMetadata = (AvaticaSpecificDatabaseMetaData) metadata;
// We should get the same version back from the server
assertEquals(FilteredConstants.VERSION, avaticaMetadata.getAvaticaServerVersion());
Properties avaticaProps = avaticaMetadata.unwrap(Properties.class);
assertNotNull(avaticaProps);
assertEquals(FilteredConstants.VERSION,
avaticaProps.get(DatabaseProperty.AVATICA_VERSION.name()));
} finally {
ConnectionSpec.getDatabaseLock().unlock();
}
}
@Test public void testMalformedRequest() throws Exception {
URL url = new URL("http://localhost:" + this.port);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
// Write some garbage data
wr.write(new byte[] {0, 1, 2, 3, 4, 5, 6, 7});
wr.flush();
wr.close();
}
final int responseCode = conn.getResponseCode();
assertEquals(500, responseCode);
final InputStream inputStream = conn.getErrorStream();
byte[] responseBytes = AvaticaUtils.readFullyToBytes(inputStream);
ErrorResponse response;
switch (this.serialization) {
case JSON:
response = JsonService.MAPPER.readValue(responseBytes, ErrorResponse.class);
assertTrue("Unexpected error message: " + response.errorMessage,
response.errorMessage.contains("Illegal character"));
break;
case PROTOBUF:
ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
Response genericResp = pbTranslation.parseResponse(responseBytes);
assertTrue("Response was not an ErrorResponse, but was " + genericResp.getClass(),
genericResp instanceof ErrorResponse);
response = (ErrorResponse) genericResp;
assertTrue("Unexpected error message: " + response.errorMessage,
response.errorMessage.contains("contained an invalid tag"));
break;
default:
fail("Unhandled serialization " + this.serialization);
throw new RuntimeException();
}
}
@Test public void testDriverProperties() throws Exception {
final Properties props = new Properties();
props.setProperty("foo", "bar");
final Properties originalProps = (Properties) props.clone();
try (final Connection conn = DriverManager.getConnection(url, props)) {
// The contents of the two properties objects should not have changed after connecting.
assertEquals(props, originalProps);
}
}
}
// End RemoteMetaTest.java