Skip to content

Commit

Permalink
Support fetching queries to be verified using a Presto query
Browse files Browse the repository at this point in the history
Currently, we support fetch source queries (pairs for queries to be
verified) from an MySQL table by a given suite. This is insufficient
in some cases, as it requires MySQL and is also bound by the limitation
of MySQL.

Add support to fetch source queries by running a Presto query. The
fetching query will be run on the helper cluster.
  • Loading branch information
caithagoras0 authored and mbasmanova committed Sep 10, 2020
1 parent 6a763b2 commit 2e179d3
Show file tree
Hide file tree
Showing 9 changed files with 435 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import static com.facebook.presto.verifier.framework.QueryConfigurationOverrides.SessionPropertiesOverrideStrategy.OVERRIDE;
import static com.facebook.presto.verifier.framework.QueryConfigurationOverrides.SessionPropertiesOverrideStrategy.SUBSTITUTE;
import static com.google.common.base.MoreObjects.toStringHelper;
import static java.util.Objects.requireNonNull;

public class QueryConfiguration
Expand Down Expand Up @@ -118,4 +119,16 @@ public int hashCode()
{
return Objects.hash(catalog, schema, username, password, sessionProperties);
}

@Override
public String toString()
{
return toStringHelper(this)
.add("catalog", catalog)
.add("schema", schema)
.add("username", username)
.add("password", password)
.add("sessionProperties", sessionProperties)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ public enum QueryStage
DESCRIBE(CONTROL),
DETERMINISM_ANALYSIS_SETUP(CONTROL),
DETERMINISM_ANALYSIS_MAIN(CONTROL),
DETERMINISM_ANALYSIS_CHECKSUM(CONTROL);
DETERMINISM_ANALYSIS_CHECKSUM(CONTROL),

// Running Presto query to fetch the source queries to be verified
SOURCE(CONTROL);

private final ClusterType targetCluster;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import org.jdbi.v3.core.mapper.reflect.ColumnName;
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;

import java.util.Objects;

import static com.google.common.base.MoreObjects.toStringHelper;
import static java.util.Objects.requireNonNull;

public class SourceQuery
Expand Down Expand Up @@ -85,4 +88,41 @@ private static String clean(String sql)
}
return sql;
}

@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
SourceQuery o = (SourceQuery) obj;
return Objects.equals(suite, o.suite) &&
Objects.equals(name, o.name) &&
Objects.equals(controlQuery, o.controlQuery) &&
Objects.equals(testQuery, o.testQuery) &&
Objects.equals(controlConfiguration, o.controlConfiguration) &&
Objects.equals(testConfiguration, o.testConfiguration);
}

@Override
public int hashCode()
{
return Objects.hash(suite, name, controlQuery, testQuery, controlConfiguration, testConfiguration);
}

@Override
public String toString()
{
return toStringHelper(this)
.add("suite", suite)
.add("name", name)
.add("controlQuery", controlQuery)
.add("testQuery", testQuery)
.add("controlConfiguration", controlConfiguration)
.add("testConfiguration", testConfiguration)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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 com.facebook.presto.verifier.source;

import com.facebook.airlift.configuration.Config;

import javax.validation.constraints.NotNull;

import java.util.Optional;

public class PrestoQuerySourceQueryConfig
{
private String query;
private String catalog;
private String schema;
private Optional<String> username = Optional.empty();
private Optional<String> password = Optional.empty();

@NotNull
public String getQuery()
{
return query;
}

@Config("query")
public PrestoQuerySourceQueryConfig setQuery(String query)
{
this.query = query;
return this;
}

@NotNull
public String getCatalog()
{
return catalog;
}

@Config("catalog")
public PrestoQuerySourceQueryConfig setCatalog(String catalog)
{
this.catalog = catalog;
return this;
}

@NotNull
public String getSchema()
{
return schema;
}

@Config("schema")
public PrestoQuerySourceQueryConfig setSchema(String schema)
{
this.schema = schema;
return this;
}

@NotNull
public Optional<String> getUsername()
{
return username;
}

@Config("username")
public PrestoQuerySourceQueryConfig setUsername(String username)
{
this.username = Optional.ofNullable(username);
return this;
}

@NotNull
public Optional<String> getPassword()
{
return password;
}

@Config("password")
public PrestoQuerySourceQueryConfig setPassword(String password)
{
this.password = Optional.ofNullable(password);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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 com.facebook.presto.verifier.source;

import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.verifier.annotation.ForHelper;
import com.facebook.presto.verifier.framework.QueryConfiguration;
import com.facebook.presto.verifier.framework.SourceQuery;
import com.facebook.presto.verifier.framework.VerificationContext;
import com.facebook.presto.verifier.prestoaction.PrestoAction;
import com.facebook.presto.verifier.prestoaction.PrestoAction.ResultSetConverter;
import com.facebook.presto.verifier.prestoaction.PrestoActionFactory;

import javax.inject.Inject;

import java.util.List;
import java.util.Optional;

import static com.facebook.presto.verifier.framework.QueryStage.SOURCE;
import static com.facebook.presto.verifier.framework.VerifierUtil.PARSING_OPTIONS;
import static java.util.Objects.requireNonNull;

public class PrestoQuerySourceQuerySupplier
implements SourceQuerySupplier
{
public static final String PRESTO_QUERY_SOURCE_QUERY_SUPPLIER = "presto-query";
private static final ResultSetConverter<SourceQuery> SOURCE_QUERY_CONVERTER = resultSet ->
Optional.of(new SourceQuery(
resultSet.getString("suite"),
resultSet.getString("name"),
resultSet.getString("control_query"),
resultSet.getString("test_query"),
new QueryConfiguration(
resultSet.getString("control_catalog"),
resultSet.getString("control_schema"),
Optional.ofNullable(resultSet.getString("control_username")),
Optional.ofNullable(resultSet.getString("control_password")),
Optional.ofNullable(resultSet.getString("control_session_properties"))
.map(StringToStringMapColumnMapper.CODEC::fromJson)),
new QueryConfiguration(
resultSet.getString("test_catalog"),
resultSet.getString("test_schema"),
Optional.ofNullable(resultSet.getString("test_username")),
Optional.ofNullable(resultSet.getString("test_password")),
Optional.ofNullable(resultSet.getString("test_session_properties"))
.map(StringToStringMapColumnMapper.CODEC::fromJson))));

private final PrestoAction helperAction;
private final SqlParser sqlParser;
private final String query;

@Inject
public PrestoQuerySourceQuerySupplier(
@ForHelper PrestoActionFactory helperActionFactory,
SqlParser sqlParser,
PrestoQuerySourceQueryConfig config)
{
this.helperAction = helperActionFactory.create(
new QueryConfiguration(config.getCatalog(), config.getSchema(), config.getUsername(), config.getPassword(), Optional.empty()),
VerificationContext.create("", ""));
this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
this.query = requireNonNull(config.getQuery(), "query is null");
}

@Override
public List<SourceQuery> get()
{
return helperAction.execute(sqlParser.createStatement(query, PARSING_OPTIONS), SOURCE, SOURCE_QUERY_CONVERTER).getResults();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@

import static com.facebook.airlift.configuration.ConfigBinder.configBinder;
import static com.facebook.presto.verifier.source.MySqlSourceQuerySupplier.MYSQL_SOURCE_QUERY_SUPPLIER;
import static com.facebook.presto.verifier.source.PrestoQuerySourceQuerySupplier.PRESTO_QUERY_SOURCE_QUERY_SUPPLIER;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.inject.Scopes.SINGLETON;

public class SourceQueryModule
extends AbstractConfigurationAwareModule
{
private static final String SOURCE_QUERY_CONFIG_PREFIX = "source-query";
private final Set<String> supportedSourceQuerySupplierTypes;

public SourceQueryModule(Set<String> customSourceQuerySupplierTypes)
{
this.supportedSourceQuerySupplierTypes = ImmutableSet.<String>builder()
.add(MYSQL_SOURCE_QUERY_SUPPLIER)
.add(PRESTO_QUERY_SOURCE_QUERY_SUPPLIER)
.addAll(customSourceQuerySupplierTypes)
.build();
}
Expand All @@ -45,8 +48,13 @@ protected void setup(Binder binder)
checkArgument(supportedSourceQuerySupplierTypes.contains(sourceQuerySupplierType), "Unsupported SourceQuerySupplier: %s", sourceQuerySupplierType);

if (MYSQL_SOURCE_QUERY_SUPPLIER.equals(sourceQuerySupplierType)) {
configBinder(binder).bindConfig(MySqlSourceQueryConfig.class, "source-query");
configBinder(binder).bindConfig(MySqlSourceQueryConfig.class, SOURCE_QUERY_CONFIG_PREFIX);
binder.bind(SourceQuerySupplier.class).to(MySqlSourceQuerySupplier.class).in(SINGLETON);
}

if (PRESTO_QUERY_SOURCE_QUERY_SUPPLIER.equals(sourceQuerySupplierType)) {
configBinder(binder).bindConfig(PrestoQuerySourceQueryConfig.class, SOURCE_QUERY_CONFIG_PREFIX);
binder.bind(SourceQuerySupplier.class).to(PrestoQuerySourceQuerySupplier.class).in(SINGLETON);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
public class StringToStringMapColumnMapper
implements ColumnMapper<Map<String, String>>
{
private static final JsonCodec<Map<String, String>> CODEC = mapJsonCodec(String.class, String.class);
public static final JsonCodec<Map<String, String>> CODEC = mapJsonCodec(String.class, String.class);

@Override
public Map<String, String> map(ResultSet resultSet, int columnNumber, StatementContext ctx)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 com.facebook.presto.verifier.source;

import com.google.common.collect.ImmutableMap;
import org.testng.annotations.Test;

import java.util.Map;

import static com.facebook.airlift.configuration.testing.ConfigAssertions.assertFullMapping;
import static com.facebook.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults;
import static com.facebook.airlift.configuration.testing.ConfigAssertions.recordDefaults;

public class TestPrestoQuerySourceQueryConfig
{
@Test
public void testDefault()
{
assertRecordedDefaults(recordDefaults(PrestoQuerySourceQueryConfig.class)
.setQuery(null)
.setCatalog(null)
.setSchema(null)
.setUsername(null)
.setPassword(null));
}

@Test
public void testExplicitPropertyMappings()
{
Map<String, String> properties = new ImmutableMap.Builder<String, String>()
.put("query", "SELECT query")
.put("catalog", "test_catalog")
.put("schema", "test_schema")
.put("username", "test_user")
.put("password", "test_password")
.build();
PrestoQuerySourceQueryConfig expected = new PrestoQuerySourceQueryConfig()
.setQuery("SELECT query")
.setCatalog("test_catalog")
.setSchema("test_schema")
.setUsername("test_user")
.setPassword("test_password");

assertFullMapping(properties, expected);
}
}
Loading

0 comments on commit 2e179d3

Please sign in to comment.