Skip to content

Commit

Permalink
Add Presto container
Browse files Browse the repository at this point in the history
  • Loading branch information
findepi committed Jan 5, 2020
1 parent 3d79c03 commit 9575f62
Show file tree
Hide file tree
Showing 10 changed files with 345 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/modules/databases/index.md
Expand Up @@ -69,6 +69,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database
`jdbc:tc:postgis:9.6:///databasename`
### Using Presto
`jdbc:tc:presto:327://localhost/memory/default`
## Using a classpath init script
Testcontainers can run an init script after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows:
Expand Down
85 changes: 85 additions & 0 deletions docs/modules/databases/presto.md
@@ -0,0 +1,85 @@
# Presto Module

See [Database containers](./index.md) for documentation and usage that is common to all database container types.

## Usage example

Running Presto as a stand-in for in a test:

```java
public class SomeTest {

@Rule
public PrestoContainer presto = new PrestoContainer();

@Test
public void someTestMethod() {
String url = presto.getJdbcUrl();

... create a connection and run test as normal
```

Presto comes with several catalogs preconfigured. Most useful ones for testing are

* `tpch` catalog using the [Presto TPCH Connector](https://prestosql.io/docs/current/connector/tpch.html).
This is a read-only catalog that defines standard TPCH schema, so is available for querying without a need
to create any tables.
* `memory` catalog using the [Presto Memory Connector](https://prestosql.io/docs/current/connector/memory.html).
This catalog can be used for creating schemas and tables and does not require any storage, as everything
is stored fully in-memory.

Example test using the `tpch` and `memory` catalogs:

```java
public class SomeTest {

@Rule
public PrestoContainer presto = new PrestoContainer();

@Test
public void queryMemoryAndTpchConnectors() throws SQLException {
try (Connection connection = presto.createConnection();
Statement statement = connection.createStatement()) {
// Prepare data
statement.execute("CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[4, 2, 42] my_array");

// Query Presto using newly created table and a builtin connector
try (ResultSet resultSet = statement.executeQuery("" +
"SELECT nationkey, element " +
"FROM tpch.tiny.nation " +
"JOIN memory.default.table_with_array twa ON nationkey = twa.id " +
"LEFT JOIN UNNEST(my_array) a(element) ON true ")) {
Set<Integer> actualElements = new HashSet<>();
while (resultSet.next()) {
actualElements.add(resultSet.getInt("element"));
}
Assert.assertEquals(ImmutableSet.of(4, 2, 42), actualElements);
}
}
}
}
```

## Adding this module to your project dependencies

Add the following dependency to your `pom.xml`/`build.gradle` file:

```groovy tab='Gradle'
testCompile "org.testcontainers:presto:{{latest_version}}"
```

```xml tab='Maven'
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>presto</artifactId>
<version>{{latest_version}}</version>
<scope>test</scope>
</dependency>
```

!!! hint
Adding this Testcontainers library JAR will not automatically add the Presto JDBC driver JAR to your project.
You should ensure that your project has the Presto JDBC driver as a dependency, if you plan on using it.
Refer to [Presto project download page](https://prestosql.io/download.html) for instructions.


2 changes: 2 additions & 0 deletions modules/jdbc-test/build.gradle
Expand Up @@ -7,6 +7,7 @@ repositories {
dependencies {
compile project(':mysql')
compile project(':postgresql')
compile project(':presto')
compile project(':cockroachdb')
compile project(':mariadb')
compile project(':oracle-xe')
Expand All @@ -16,6 +17,7 @@ dependencies {

testCompile 'com.google.guava:guava:18.0'
testCompile 'org.postgresql:postgresql:42.0.0'
testCompile 'io.prestosql:presto-jdbc:327'
testCompile 'mysql:mysql-connector-java:8.0.14'
testCompile 'org.mariadb.jdbc:mariadb-java-client:1.4.6'
testCompile 'com.oracle:ojdbc6:12.1.0.1-atlassian-hosted'
Expand Down
Expand Up @@ -53,6 +53,7 @@ public static Iterable<Object[]> data() {
{"jdbc:tc:postgresql:9.6.8://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)},
{"jdbc:tc:postgis://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)},
{"jdbc:tc:postgis:9.6://hostname/databasename?user=someuser&password=somepwd", EnumSet.of(Options.JDBCParams)},
{"jdbc:tc:presto:327://hostname/", EnumSet.of(Options.PmdKnownBroken)},
{"jdbc:tc:mysql:5.6://hostname/databasename?TC_MY_CNF=somepath/mysql_conf_override", EnumSet.of(Options.CustomIniFile)},
{"jdbc:tc:mariadb://hostname/databasename", EnumSet.noneOf(Options.class)},
{"jdbc:tc:mariadb://hostname/databasename?user=someuser&TC_INITSCRIPT=somepath/init_mariadb.sql", EnumSet.of(Options.ScriptedSchema, Options.JDBCParams)},
Expand Down
8 changes: 8 additions & 0 deletions modules/presto/build.gradle
@@ -0,0 +1,8 @@
description = "Testcontainers :: JDBC :: Presto"

dependencies {
compile project(':jdbc')

testCompile 'io.prestosql:presto-jdbc:327'
testCompile 'commons-dbutils:commons-dbutils:1.7'
}
@@ -0,0 +1,104 @@
package org.testcontainers.containers;

import org.jetbrains.annotations.NotNull;
import org.testcontainers.containers.wait.LogMessageWaitStrategy;

import java.sql.Connection;
import java.sql.SQLException;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;

import static com.google.common.base.Strings.nullToEmpty;
import static java.lang.String.format;
import static java.time.temporal.ChronoUnit.SECONDS;

public class PrestoContainer<SELF extends PrestoContainer<SELF>> extends JdbcDatabaseContainer<SELF> {
public static final String NAME = "presto";
public static final String IMAGE = "prestosql/presto";
public static final String DEFAULT_TAG = "327";

public static final Integer PRESTO_PORT = 8080;

private String username = "test";
private String catalog = null;

public PrestoContainer() {
this(IMAGE + ":" + DEFAULT_TAG);
}

public PrestoContainer(final String dockerImageName) {
super(dockerImageName);
this.waitStrategy = new LogMessageWaitStrategy()
.withRegEx(".*io.prestosql.server.PrestoServer\\s+======== SERVER STARTED ========.*")
.withStartupTimeout(Duration.of(60, SECONDS));
}

@NotNull
@Override
protected Set<Integer> getLivenessCheckPorts() {
return new HashSet<>(getMappedPort(PRESTO_PORT));
}

@Override
protected void configure() {
addExposedPort(PRESTO_PORT);
}

@Override
public String getDriverClassName() {
return "io.prestosql.jdbc.PrestoDriver";
}

@Override
public String getJdbcUrl() {
return format("jdbc:presto://%s:%s/%s", getContainerIpAddress(), getMappedPort(PRESTO_PORT), nullToEmpty(catalog));
}

@Override
public String getUsername() {
return username;
}

@Override
public String getPassword() {
return "";
}

@Override
public String getDatabaseName() {
return catalog;
}

@Override
public String getTestQueryString() {
return "SELECT count(*) FROM tpch.tiny.nation";
}

@Override
public SELF withUsername(final String username) {
this.username = username;
return self();
}

/**
* @deprecated This operation is not supported.
*/
@Override
@Deprecated
public SELF withPassword(final String password) {
// ignored, Presto does not support password authentication without TLS
// TODO: make JDBCDriverTest not pass a password unconditionally and remove this method
return self();
}

@Override
public SELF withDatabaseName(String dbName) {
this.catalog = dbName;
return self();
}

public Connection createConnection() throws SQLException, NoDriverFoundException {
return createConnection("");
}
}
@@ -0,0 +1,35 @@
package org.testcontainers.containers;

import org.testcontainers.jdbc.ConnectionUrl;

import java.util.Objects;

/**
* Factory for Presto containers.
*/
public class PrestoContainerProvider extends JdbcDatabaseContainerProvider {

public static final String USER_PARAM = "user";
public static final String PASSWORD_PARAM = "password";

@Override
public boolean supports(String databaseType) {
return databaseType.equals(PrestoContainer.NAME);
}

@Override
public JdbcDatabaseContainer newInstance() {
return newInstance(PrestoContainer.DEFAULT_TAG);
}

@Override
public JdbcDatabaseContainer newInstance(String tag) {
return new PrestoContainer(PrestoContainer.IMAGE + ":" + tag);
}

@Override
public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) {
return newInstanceFromConnectionUrl(connectionUrl, USER_PARAM, PASSWORD_PARAM);
}

}
@@ -0,0 +1 @@
org.testcontainers.containers.PrestoContainerProvider
@@ -0,0 +1,103 @@
/*
* Licensed 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.testcontainers.containers;

import com.google.common.collect.ImmutableSet;
import org.junit.Assert;
import org.junit.Test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

/**
* @author findepi
*/
public class PrestoContainerTest {
@Test
public void testSimple() throws Exception {
try (PrestoContainer<?> container = new PrestoContainer<>()) {
container.start();
try (Connection connection = container.createConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) {
assertTrue("No result", resultSet.next());
assertEquals("Presto version", PrestoContainer.DEFAULT_TAG, resultSet.getString("node_version"));
}
}
}

@Test
public void testSpecificVersion() throws Exception {
String prestoVersion = "325";
assertNotEquals(prestoVersion, PrestoContainer.DEFAULT_TAG);
try (PrestoContainer<?> container = new PrestoContainer<>("prestosql/presto:" + prestoVersion)) {
container.start();
try (Connection connection = container.createConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT DISTINCT node_version FROM system.runtime.nodes")) {
assertTrue("No result", resultSet.next());
assertEquals("Presto version", "325", resultSet.getString("node_version"));
}
}
}

@Test
public void testQueryMemoryAndTpch() throws SQLException {
try (PrestoContainer<?> container = new PrestoContainer<>()) {
container.start();
try (Connection connection = container.createConnection();
Statement statement = connection.createStatement()) {
// Prepare data
statement.execute("CREATE TABLE memory.default.table_with_array AS SELECT 1 id, ARRAY[4, 2, 42] my_array");

// Query Presto using newly created table and a builtin connector
try (ResultSet resultSet = statement.executeQuery("" +
"SELECT nationkey, element " +
"FROM tpch.tiny.nation " +
"JOIN memory.default.table_with_array twa ON nationkey = twa.id " +
"LEFT JOIN UNNEST(my_array) a(element) ON true ")) {
Set<Integer> actualElements = new HashSet<>();
while (resultSet.next()) {
actualElements.add(resultSet.getInt("element"));
}
Assert.assertEquals(ImmutableSet.of(4, 2, 42), actualElements);
}
}
}
}

@Test
public void testInitScript() throws Exception {
try (PrestoContainer<?> container = new PrestoContainer<>()) {
container.withInitScript("initial.sql");
container.start();
try (Connection connection = container.createConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT a FROM memory.default.test_table")) {
assertTrue("No result", resultSet.next());
assertEquals("Value", 12345678909324L, resultSet.getObject("a"));
assertFalse("Too many result", resultSet.next());
}
}
}
}
2 changes: 2 additions & 0 deletions modules/presto/src/test/resources/initial.sql
@@ -0,0 +1,2 @@
CREATE TABLE memory.default.test_table(a bigint);
INSERT INTO memory.default.test_table(a) VALUES (12345678909324);

0 comments on commit 9575f62

Please sign in to comment.