/*
* 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.server;
import com.facebook.presto.client.QueryError;
import com.facebook.presto.client.QueryResults;
import com.facebook.presto.execution.QueryInfo;
import com.facebook.presto.server.testing.TestingPrestoServer;
import com.facebook.presto.spi.QueryId;
import com.facebook.presto.spi.type.TimeZoneNotSupportedException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.http.client.FullJsonResponseHandler.JsonResponse;
import io.airlift.http.client.HttpClient;
import io.airlift.http.client.HttpUriBuilder;
import io.airlift.http.client.Request;
import io.airlift.http.client.StatusResponseHandler;
import io.airlift.http.client.jetty.JettyHttpClient;
import io.airlift.testing.Closeables;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.net.URI;
import java.util.List;
import static com.facebook.presto.SystemSessionProperties.DISTRIBUTED_JOIN;
import static com.facebook.presto.SystemSessionProperties.HASH_PARTITION_COUNT;
import static com.facebook.presto.SystemSessionProperties.QUERY_MAX_MEMORY;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_CATALOG;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_CLIENT_INFO;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_PREPARED_STATEMENT;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SCHEMA;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SESSION;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_SOURCE;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_STARTED_TRANSACTION_ID;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_TIME_ZONE;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_TRANSACTION_ID;
import static com.facebook.presto.client.PrestoHeaders.PRESTO_USER;
import static com.facebook.presto.spi.StandardErrorCode.INCOMPATIBLE_CLIENT;
import static io.airlift.http.client.FullJsonResponseHandler.createFullJsonResponseHandler;
import static io.airlift.http.client.JsonResponseHandler.createJsonResponseHandler;
import static io.airlift.http.client.Request.Builder.prepareGet;
import static io.airlift.http.client.Request.Builder.preparePost;
import static io.airlift.http.client.StaticBodyGenerator.createStaticBodyGenerator;
import static io.airlift.http.client.StatusResponseHandler.createStatusResponseHandler;
import static io.airlift.json.JsonCodec.jsonCodec;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.ws.rs.core.Response.Status.OK;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
@Test(singleThreaded = true)
public class TestServer
{
private TestingPrestoServer server;
private HttpClient client;
@BeforeMethod
public void setup()
throws Exception
{
server = new TestingPrestoServer();
client = new JettyHttpClient();
}
@SuppressWarnings("deprecation")
@AfterMethod
public void teardown()
{
Closeables.closeQuietly(server);
Closeables.closeQuietly(client);
}
@Test
public void testInvalidSessionError()
throws Exception
{
String invalidTimeZone = "this_is_an_invalid_time_zone";
Request request = preparePost().setHeader(PRESTO_USER, "user")
.setUri(uriFor("/v1/statement"))
.setBodyGenerator(createStaticBodyGenerator("show catalogs", UTF_8))
.setHeader(PRESTO_SOURCE, "source")
.setHeader(PRESTO_CATALOG, "catalog")
.setHeader(PRESTO_SCHEMA, "schema")
.setHeader(PRESTO_TIME_ZONE, invalidTimeZone)
.build();
QueryResults queryResults = client.execute(request, createJsonResponseHandler(jsonCodec(QueryResults.class)));
QueryError queryError = queryResults.getError();
assertNotNull(queryError);
TimeZoneNotSupportedException expected = new TimeZoneNotSupportedException(invalidTimeZone);
assertEquals(queryError.getErrorCode(), expected.getErrorCode().getCode());
assertEquals(queryError.getErrorName(), expected.getErrorCode().getName());
assertEquals(queryError.getErrorType(), expected.getErrorCode().getType().name());
assertEquals(queryError.getMessage(), expected.getMessage());
}
@Test
public void testServerStarts()
throws Exception
{
StatusResponseHandler.StatusResponse response = client.execute(
prepareGet().setUri(server.resolve("/v1/query")).build(),
createStatusResponseHandler());
assertEquals(response.getStatusCode(), OK.getStatusCode());
}
@Test
public void testQuery()
throws Exception
{
// start query
Request request = preparePost()
.setUri(uriFor("/v1/statement"))
.setBodyGenerator(createStaticBodyGenerator("show catalogs", UTF_8))
.setHeader(PRESTO_USER, "user")
.setHeader(PRESTO_SOURCE, "source")
.setHeader(PRESTO_CATALOG, "catalog")
.setHeader(PRESTO_SCHEMA, "schema")
.setHeader(PRESTO_CLIENT_INFO, "{\"clientVersion\":\"testVersion\"}")
.addHeader(PRESTO_SESSION, QUERY_MAX_MEMORY + "=1GB")
.addHeader(PRESTO_SESSION, DISTRIBUTED_JOIN + "=true," + HASH_PARTITION_COUNT + " = 43")
.addHeader(PRESTO_PREPARED_STATEMENT, "foo=select * from bar")
.build();
QueryResults queryResults = client.execute(request, createJsonResponseHandler(jsonCodec(QueryResults.class)));
// get the query info
QueryInfo queryInfo = server.getQueryManager().getQueryInfo(new QueryId(queryResults.getId()));
// verify session properties
assertEquals(queryInfo.getSession().getSystemProperties(), ImmutableMap.builder()
.put(QUERY_MAX_MEMORY, "1GB")
.put(DISTRIBUTED_JOIN, "true")
.put(HASH_PARTITION_COUNT, "43")
.build());
// verify client info in session
assertEquals(queryInfo.getSession().getClientInfo().get(), "{\"clientVersion\":\"testVersion\"}");
// verify prepared statements
assertEquals(queryInfo.getSession().getPreparedStatements(), ImmutableMap.builder()
.put("foo", "select * from bar")
.build());
ImmutableList.Builder<List<Object>> data = ImmutableList.builder();
if (queryResults.getData() != null) {
data.addAll(queryResults.getData());
}
while (queryResults.getNextUri() != null) {
queryResults = client.execute(prepareGet().setUri(queryResults.getNextUri()).build(), createJsonResponseHandler(jsonCodec(QueryResults.class)));
if (queryResults.getData() != null) {
data.addAll(queryResults.getData());
}
}
assertNull(queryResults.getError());
// only the system catalog exists by default
List<List<Object>> rows = data.build();
assertEquals(rows, ImmutableList.of(ImmutableList.of("system")));
}
@Test
public void testTransactionSupport()
throws Exception
{
Request request = preparePost()
.setUri(uriFor("/v1/statement"))
.setBodyGenerator(createStaticBodyGenerator("start transaction", UTF_8))
.setHeader(PRESTO_USER, "user")
.setHeader(PRESTO_SOURCE, "source")
.setHeader(PRESTO_TRANSACTION_ID, "none")
.build();
JsonResponse<QueryResults> queryResults = client.execute(request, createFullJsonResponseHandler(jsonCodec(QueryResults.class)));
ImmutableList.Builder<List<Object>> data = ImmutableList.builder();
while (true) {
if (queryResults.getValue().getData() != null) {
data.addAll(queryResults.getValue().getData());
}
if (queryResults.getValue().getNextUri() == null) {
break;
}
queryResults = client.execute(prepareGet().setUri(queryResults.getValue().getNextUri()).build(), createFullJsonResponseHandler(jsonCodec(QueryResults.class)));
}
assertNull(queryResults.getValue().getError());
assertNotNull(queryResults.getHeader(PRESTO_STARTED_TRANSACTION_ID));
}
@Test
public void testNoTransactionSupport()
throws Exception
{
Request request = preparePost()
.setUri(uriFor("/v1/statement"))
.setBodyGenerator(createStaticBodyGenerator("start transaction", UTF_8))
.setHeader(PRESTO_USER, "user")
.setHeader(PRESTO_SOURCE, "source")
.build();
QueryResults queryResults = client.execute(request, createJsonResponseHandler(jsonCodec(QueryResults.class)));
while (queryResults.getNextUri() != null) {
queryResults = client.execute(prepareGet().setUri(queryResults.getNextUri()).build(), createJsonResponseHandler(jsonCodec(QueryResults.class)));
}
assertNotNull(queryResults.getError());
assertEquals(queryResults.getError().getErrorCode(), INCOMPATIBLE_CLIENT.toErrorCode().getCode());
}
public URI uriFor(String path)
{
return HttpUriBuilder.uriBuilderFrom(server.getBaseUrl()).replacePath(path).build();
}
}