This is an automated email from the ASF dual-hosted git repository. kenhuuu pushed a commit to branch http-server-test-updates in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit ba25c6970a639e8112a209941a102db33517aee0 Author: Ken Hu <106191785+kenh...@users.noreply.github.com> AuthorDate: Mon May 27 16:58:58 2024 -0700 Fix and re-enable tests for server and Java driver. --- .../structure/io/graphson/GraphSONReader.java | 2 +- .../tinkerpop/gremlin/driver/Channelizer.java | 7 + .../tinkerpop/gremlin/driver/ConnectionPool.java | 11 +- .../driver/handler/GremlinResponseHandler.java | 3 +- .../driver/handler/HttpGremlinRequestEncoder.java | 4 +- .../handler/HttpGremlinResponseStreamDecoder.java | 21 +- .../gremlin/driver/handler/SslCheckHandler.java | 50 ++++ .../gremlin/driver/simple/AbstractClient.java | 2 +- .../handler/HttpBasicAuthorizationHandler.java | 27 ++- .../server/handler/HttpGremlinEndpointHandler.java | 2 +- .../driver/ClientConnectionIntegrateTest.java | 2 +- .../gremlin/server/GremlinDriverIntegrateTest.java | 126 +--------- .../server/GremlinServerAuditLogIntegrateTest.java | 259 ++++++++------------- .../server/GremlinServerAuthIntegrateTest.java | 2 +- .../server/GremlinServerAuthzIntegrateTest.java | 78 ++++--- .../gremlin/server/GremlinServerIntegrateTest.java | 212 ++++++----------- .../GremlinServerSerializationIntegrateTest.java | 3 +- .../server/GremlinServerSslIntegrateTest.java | 13 +- ...tractGremlinServerChannelizerIntegrateTest.java | 50 +--- .../src/test/resources/conf/remote-objects.yaml | 2 +- .../util/ser/GraphBinaryMessageSerializerV4.java | 3 +- 21 files changed, 327 insertions(+), 552 deletions(-) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java index 7b5c812f42..937adce201 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java @@ -177,7 +177,7 @@ public final class GraphSONReader implements GraphReader { final Direction attachEdgesOfThisDirection) throws IOException { // graphson v3 has special handling for generic Map instances, by forcing to linkedhashmap (which is probably // what it should have been anyway) stargraph format can remain unchanged across all versions - final Map<String, Object> vertexData = version == GraphSONVersion.V3_0 ? + final Map<String, Object> vertexData = ((version == GraphSONVersion.V3_0) || (version == GraphSONVersion.V4_0)) ? mapper.readValue(inputStream, linkedHashMapTypeReference) : mapper.readValue(inputStream, mapTypeReference); final StarGraph starGraph = StarGraphGraphSONDeserializer.readStarGraphVertex(vertexData); if (vertexAttachMethod != null) vertexAttachMethod.apply(starGraph.getStarVertex()); diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java index 4caa029484..d2e393f100 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java @@ -20,6 +20,8 @@ package org.apache.tinkerpop.gremlin.driver; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -29,6 +31,7 @@ import io.netty.handler.ssl.SslHandler; import org.apache.tinkerpop.gremlin.driver.handler.GremlinResponseHandler; import org.apache.tinkerpop.gremlin.driver.handler.HttpGremlinRequestEncoder; import org.apache.tinkerpop.gremlin.driver.handler.HttpGremlinResponseStreamDecoder; +import org.apache.tinkerpop.gremlin.driver.handler.SslCheckHandler; import org.apache.tinkerpop.gremlin.util.MessageSerializerV4; import java.util.Optional; @@ -92,6 +95,8 @@ public interface Channelizer extends ChannelHandler { protected static final String PIPELINE_HTTP_ENCODER = "gremlin-encoder"; protected static final String PIPELINE_HTTP_DECODER = "gremlin-decoder"; + private static final SslCheckHandler sslCheckHandler = new SslCheckHandler(); + public boolean supportsSsl() { return cluster.connectionPoolSettings().enableSsl; } @@ -135,6 +140,8 @@ public interface Channelizer extends ChannelHandler { // will instead be capped by connectionSetupTimeoutMillis. sslHandler.setHandshakeTimeoutMillis(0); pipeline.addLast(PIPELINE_SSL_HANDLER, sslHandler); + } else { + pipeline.addLast(PIPELINE_SSL_HANDLER, sslCheckHandler); } configure(pipeline); diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java index f8642300a3..759a85c0aa 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java @@ -208,17 +208,16 @@ final class ConnectionPool { return; } + // Destroy any extra connections that exceeded the maximum pool size. Idle connections will be removed + // based on their idle timeout so that isn't handled here. final int poolSize = connections.size(); - if (poolSize > minPoolSize) { + if (poolSize > maxPoolSize) { if (logger.isDebugEnabled()) logger.debug("destroy {}", connection.getConnectionInfo()); destroyConnection(connection); - } else if (maxPoolSize > 1) { - if (logger.isDebugEnabled()) - logger.debug("replace {}", connection.getConnectionInfo()); - replaceConnection(connection); - } else + } else { announceAvailableConnection(); + } } } diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java index eb1bb37df7..88e8a740e6 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java @@ -91,7 +91,8 @@ public class GremlinResponseHandler extends SimpleChannelInboundHandler<Response // there are that many failures someone would take notice and hopefully stop the client. logger.error("Could not process the response", cause); - pending.getAndSet(null).markError(cause); + final ResultQueue pendingQueue = pending.getAndSet(null); + if (pendingQueue != null) pendingQueue.markError(cause); // serialization exceptions should not close the channel - that's worth a retry if (!IteratorUtils.anyMatch(ExceptionUtils.getThrowableList(cause).iterator(), t -> t instanceof SerializationException)) diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java index 2d9c51c73e..21335f9f0d 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java @@ -22,7 +22,6 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; -import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; @@ -42,6 +41,8 @@ import org.apache.tinkerpop.gremlin.util.ser.SerializationException; import java.net.InetSocketAddress; import java.util.List; +import static org.apache.tinkerpop.gremlin.driver.handler.SslCheckHandler.REQUEST_SENT; + /** * Converts {@link RequestMessageV4} to a {@code HttpRequest}. */ @@ -85,6 +86,7 @@ public final class HttpGremlinRequestEncoder extends MessageToMessageEncoder<Req request = interceptor.apply(request); } objects.add(request); + channelHandlerContext.channel().attr(REQUEST_SENT).set(true); } catch (SerializationException ex) { throw new ResponseException(HttpResponseStatus.BAD_REQUEST, String.format( "An error occurred during serialization of this request [%s] - it could not be sent to the server - Reason: %s", diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java index 8d8f626017..d38220a4ca 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java @@ -62,6 +62,7 @@ public class HttpGremlinResponseStreamDecoder extends MessageToMessageDecoder<De final Attribute<HttpResponseStatus> responseStatus = ((AttributeMap) ctx).attr(RESPONSE_STATUS); if (msg instanceof HttpResponse) { + ctx.channel().attr(BYTES_READ).set(0); responseStatus.set(((HttpResponse) msg).status()); if (isError(((HttpResponse) msg).status())) { @@ -69,7 +70,6 @@ public class HttpGremlinResponseStreamDecoder extends MessageToMessageDecoder<De } isFirstChunk.set(true); - ctx.channel().attr(BYTES_READ).set(0); } if (msg instanceof HttpContent) { @@ -77,7 +77,14 @@ public class HttpGremlinResponseStreamDecoder extends MessageToMessageDecoder<De Attribute<Integer> bytesRead = ctx.channel().attr(BYTES_READ); bytesRead.set(bytesRead.get() + content.readableBytes()); if (bytesRead.get() > maxContentLength) { - ctx.fireExceptionCaught(new TooLongFrameException("Response exceeded " + maxContentLength + " bytes.")); + throw new TooLongFrameException("Response exceeded " + maxContentLength + " bytes."); + } + + if (msg instanceof LastHttpContent && content.readableBytes() == 0 && bytesRead.get() != 0) { + // If this last content contains no bytes and there were bytes read previously, it means that this is the + // trailing headers. Trailing headers aren't used in the driver and shouldn't be passed on. + content.release(); + return; } try { @@ -96,14 +103,6 @@ public class HttpGremlinResponseStreamDecoder extends MessageToMessageDecoder<De final ResponseMessageV4 chunk = serializer.readChunk(content, isFirstChunk.get()); - if (msg instanceof LastHttpContent) { - final HttpHeaders trailingHeaders = ((LastHttpContent) msg).trailingHeaders(); - - if (!Objects.equals(trailingHeaders.get("code"), "200")) { - throw new Exception(trailingHeaders.get("message")); - } - } - isFirstChunk.set(false); out.add(chunk); @@ -114,6 +113,6 @@ public class HttpGremlinResponseStreamDecoder extends MessageToMessageDecoder<De } private static boolean isError(final HttpResponseStatus status) { - return status != HttpResponseStatus.OK && status != HttpResponseStatus.NO_CONTENT; + return status != HttpResponseStatus.OK; } } diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/SslCheckHandler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/SslCheckHandler.java new file mode 100644 index 0000000000..dc58186d2c --- /dev/null +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/SslCheckHandler.java @@ -0,0 +1,50 @@ +/* + * 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.tinkerpop.gremlin.driver.handler; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.AttributeKey; + +/** + * Handler used to detect if the server requires TLS when the client is sending plain HTTP. + */ +@ChannelHandler.Sharable +public class SslCheckHandler extends ChannelInboundHandlerAdapter { + public static final AttributeKey<Integer> BYTES_READ = AttributeKey.valueOf("bytesRead"); + public static final AttributeKey<Boolean> REQUEST_SENT = AttributeKey.valueOf("requestSent"); + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + // If the server requires SSL/TLS, then it will simply shut down the connection if it doesn't get the right + // handshake. This happens after the TCP connection has already been created. If no packets were received from + // the server and the connection closes after an HTTP request was sent, then there is a good chance that this is + // because the server expected a SSL/TLS handshake. + if ((null == ctx.channel().attr(BYTES_READ).get()) && (null != ctx.channel().attr(REQUEST_SENT).get())) { + // BYTES_READ is set by the HttpGremlinResponseStreamDecoder when any data is received. If it isn't set, + // it can be assumed that no bytes were received when the connection closed. + final String errMsg = "Connection to server closed unexpectedly. Ensure that the server is still" + + " reachable. The server may be expecting SSL to be enabled."; + ctx.fireExceptionCaught(new RuntimeException(errMsg)); + } else { + super.channelInactive(ctx); + } + } +} diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java index 0d733c85eb..a95bcbc8f5 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/simple/AbstractClient.java @@ -67,7 +67,7 @@ public abstract class AbstractClient implements SimpleClient { final CompletableFuture<List<ResponseMessageV4>> f = new CompletableFuture<>(); callbackResponseHandler.callback = response -> { // message with trailers - if (f.isDone() && response.getStatus().getCode() != HttpResponseStatus.NO_CONTENT) + if (f.isDone()) throw new RuntimeException("A terminating message was already encountered - no more messages should have been received"); results.add(response); diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java index a3b3d35050..018f9ba563 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthorizationHandler.java @@ -22,14 +22,19 @@ import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.ReferenceCountUtil; +import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.server.GremlinServer; import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser; import org.apache.tinkerpop.gremlin.server.authz.AuthorizationException; import org.apache.tinkerpop.gremlin.server.authz.Authorizer; +import org.apache.tinkerpop.gremlin.util.TokensV4; import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; + import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR; import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; @@ -61,17 +66,29 @@ public class HttpBasicAuthorizationHandler extends ChannelInboundHandlerAdapter if (null == user) { // This is expected when using the AllowAllAuthenticator user = AuthenticatedUser.ANONYMOUS_USER; } - - authorizer.authorize(user, requestMessage); - ctx.fireChannelRead(msg); + switch (requestMessage.getGremlinType()) { + case TokensV4.OPS_BYTECODE: + final Bytecode bytecode = (Bytecode) requestMessage.getGremlin(); + final Map<String, String> aliases = new HashMap<>(); + aliases.put(TokensV4.ARGS_G, requestMessage.getField(TokensV4.ARGS_G)); + final Bytecode restrictedBytecode = authorizer.authorize(user, bytecode, aliases); + final RequestMessageV4 restrictedMsg = RequestMessageV4.from(requestMessage, restrictedBytecode).create(); + ctx.fireChannelRead(restrictedMsg); + break; + case TokensV4.OPS_EVAL: + authorizer.authorize(user, requestMessage); + ctx.fireChannelRead(requestMessage); + break; + default: + throw new AuthorizationException("This AuthorizationHandler only handles requests with OPS_BYTECODE or OPS_EVAL."); + } } catch (AuthorizationException ex) { // Expected: users can alternate between allowed and disallowed requests String address = ctx.channel().remoteAddress().toString(); if (address.startsWith("/") && address.length() > 1) address = address.substring(1); final String script = requestMessage.getGremlin().toString(); auditLogger.info("User {} with address {} attempted an unauthorized http request: {}", user.getName(), address, script); - final String message = String.format("No authorization for script [%s] - check permissions.", script); - HttpHandlerUtil.sendError(ctx, UNAUTHORIZED, message); + HttpHandlerUtil.sendError(ctx, UNAUTHORIZED, "Failed to authorize: " + ex.getMessage()); ReferenceCountUtil.release(msg); } catch (Exception ex) { final String message = String.format( diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java index 669c3d0570..3a808aed05 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java @@ -191,7 +191,7 @@ public class HttpGremlinEndpointHandler extends SimpleChannelInboundHandler<Requ String address = ctx.channel().remoteAddress().toString(); if (address.startsWith("/") && address.length() > 1) address = address.substring(1); auditLogger.info("User {} with address {} requested: {}", user.getName(), address, - requestMessage.getFieldOrDefault(TokensV4.ARGS_GREMLIN, "")); + requestMessage.getGremlin()); } // Send back the 200 OK response header here since the response is always chunk transfer encoded. Any diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java index ef93ff19b5..523c9e6dd4 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/ClientConnectionIntegrateTest.java @@ -237,7 +237,7 @@ public class ClientConnectionIntegrateTest extends AbstractGremlinServerIntegrat */ @Test public void shouldSucceedWithJitteryConnection() throws Exception { - final Cluster cluster = TestClientFactory.build().minConnectionPoolSize(1).maxConnectionPoolSize(4). + final Cluster cluster = TestClientFactory.build().minConnectionPoolSize(1).maxConnectionPoolSize(128). reconnectInterval(1000). maxWaitForConnection(4000).validationRequest("g.inject()").create(); final Client.ClusteredClient client = cluster.connect(); diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java index d380061ef7..edf5275d20 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java @@ -135,7 +135,6 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration settings.channelizer = HttpChannelizer.class.getName(); break; case "shouldAliasTraversalSourceVariables": - case "shouldAliasTraversalSourceVariablesInSession": try { final String p = Storage.toPath(TestHelper.generateTempFileFromResource( GremlinDriverIntegrateTest.class, @@ -301,7 +300,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration fail("Request should have failed because it exceeded the max content length allowed"); } catch (Exception ex) { final Throwable root = ExceptionHelper.getRootCause(ex); - assertThat(root.getMessage(), containsString("Max frame length of 64 has been exceeded.")); + assertThat(root.getMessage(), containsString("Response exceeded 64 bytes.")); } assertEquals(2, client.submit("1+1").all().join().get(0).getInt()); @@ -473,7 +472,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration assertThat(inner.getMessage(), endsWith("Division by zero")); final ResponseException rex = (ResponseException) inner; - assertEquals("java.lang.ArithmeticException", rex.getRemoteException()); + assertEquals("ServerErrorException", rex.getRemoteException()); } // should not die completely just because we had a bad serialization error. that kind of stuff happens @@ -754,43 +753,6 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration } } - @Test - public void shouldWorkWithGraphSONV4Serialization() throws Exception { - final Cluster cluster = TestClientFactory.build().serializer(SerializersV4.GRAPHSON_V4).create(); - final Client client = cluster.connect(); - - try { - final List<Result> r = client.submit("TinkerFactory.createModern().traversal().V(1)").all().join(); - assertEquals(1, r.size()); - - final Vertex v = r.get(0).get(DetachedVertex.class); - assertEquals(1, v.id()); - assertEquals("person", v.label()); - - assertEquals(2, IteratorUtils.count(v.properties())); - assertEquals("marko", v.value("name")); - assertEquals(29, Integer.parseInt(v.value("age").toString())); - } finally { - cluster.close(); - } - } - - @Test - public void shouldWorkWithGraphSONExtendedV4Serialization() throws Exception { - final Cluster cluster = TestClientFactory.build().serializer(SerializersV4.GRAPHSON_V4).create(); - final Client client = cluster.connect(); - - try { - final List<Result> r = client.submit("java.time.Instant.EPOCH").all().join(); - assertEquals(1, r.size()); - - final Instant then = r.get(0).get(Instant.class); - assertEquals(Instant.EPOCH, then); - } finally { - cluster.close(); - } - } - @Test public void shouldWorkWithGraphBinaryV4Serialization() throws Exception { final Cluster cluster = TestClientFactory.build().serializer(SerializersV4.GRAPHBINARY_V4).create(); @@ -819,7 +781,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration fail("Should throw an exception."); } catch (Exception re) { final Throwable root = ExceptionHelper.getRootCause(re); - assertTrue(root.getMessage().equals("Max frame length of 1 has been exceeded.")); + assertTrue(root.getMessage().equals("Response exceeded 1 bytes.")); } finally { cluster.close(); } @@ -888,6 +850,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration } } + @Ignore("Server doesn't currently support transactions.") @Test public void shouldExecuteSessionlessScriptOnTransactionalGraph() throws Exception { @@ -937,32 +900,6 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration cluster.close(); } - @Test - public void shouldExecuteScriptsInMultipleSession() throws Exception { - final Cluster cluster = TestClientFactory.open(); - try { - final Client client1 = cluster.connect(name.getMethodName() + "1"); - final Client client2 = cluster.connect(name.getMethodName() + "2"); - final Client client3 = cluster.connect(name.getMethodName() + "3"); - - final ResultSet results11 = client1.submit("x = 1"); - final ResultSet results21 = client2.submit("x = 2"); - final ResultSet results31 = client3.submit("x = 3"); - assertEquals(1, results11.all().get().get(0).getInt()); - assertEquals(2, results21.all().get().get(0).getInt()); - assertEquals(3, results31.all().get().get(0).getInt()); - - final ResultSet results12 = client1.submit("x + 100"); - final ResultSet results22 = client2.submit("x * 2"); - final ResultSet results32 = client3.submit("x * 10"); - assertEquals(101, results12.all().get().get(0).getInt()); - assertEquals(4, results22.all().get().get(0).getInt()); - assertEquals(30, results32.all().get().get(0).getInt()); - } finally { - cluster.close(); - } - } - @Test public void shouldNotHaveKnowledgeOfBindingsBetweenRequestsWhenSessionless() throws Exception { final Cluster cluster = TestClientFactory.open(); @@ -1059,6 +996,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration } } + @Ignore("strict transactions not currently supported") @Test public void shouldAliasGraphVariablesInStrictTransactionMode() throws Exception { @@ -1127,55 +1065,6 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration } } - @Test - public void shouldAliasGraphVariablesInSession() throws Exception { - final Cluster cluster = TestClientFactory.build().serializer(SerializersV4.GRAPHBINARY_V4).create(); - final Client client = cluster.connect(name.getMethodName()); - - try { - client.submit("g.addVertex('name','stephen');").all().get().get(0).getVertex(); - fail("Should have tossed an exception because \"g\" does not have the addVertex method under default config"); - } catch (Exception ex) { - final Throwable root = ExceptionHelper.getRootCause(ex); - assertThat(root, instanceOf(ResponseException.class)); - final ResponseException re = (ResponseException) root; - assertEquals(HttpResponseStatus.INTERNAL_SERVER_ERROR, re.getResponseStatusCode()); - client.close(); - } - - try { - final Client aliased = cluster.connect(name.getMethodName()).alias("graph"); - assertEquals("jason", aliased.submit("n='jason'").all().get().get(0).getString()); - final String name = aliased.submit("g.addVertex('name',n).values('name')").all().get().get(0).getString(); - assertEquals("jason", name); - } finally { - cluster.close(); - } - } - - @Test - public void shouldAliasTraversalSourceVariablesInSession() throws Exception { - final Cluster cluster = TestClientFactory.build().serializer(SerializersV4.GRAPHBINARY_V4).create(); - final Client client = cluster.connect(name.getMethodName()); - - try { - client.submit("g.addV().property('name','stephen')").all().get().get(0).getVertex(); - fail("Should have tossed an exception because \"g\" is readonly in this context"); - } catch (Exception ex) { - final Throwable root = ExceptionHelper.getRootCause(ex); - assertThat(root, instanceOf(ResponseException.class)); - final ResponseException re = (ResponseException) root; - assertEquals(HttpResponseStatus.INTERNAL_SERVER_ERROR, re.getResponseStatusCode()); - } - - final Client clientAliased = client.alias("g1"); - assertEquals("jason", clientAliased.submit("n='jason'").all().get().get(0).getString()); - final String name = clientAliased.submit("g.addV().property('name',n).values('name')").all().get().get(0).getString(); - assertEquals("jason", name); - - cluster.close(); - } - @Ignore("used sessions") @Test public void shouldCloseAllClientsOnCloseOfCluster() throws Exception { @@ -1347,9 +1236,4 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration public void shouldFailOnInitiallyDeadHostForClusterClient() throws Exception { testShouldFailOnInitiallyDeadHost(true); } - - @Test - public void shouldFailOnInitiallyDeadHostForSessionClient() throws Exception { - testShouldFailOnInitiallyDeadHost(false); - } } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java index ce2d4116a6..2d91e9e9db 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java @@ -19,8 +19,10 @@ package org.apache.tinkerpop.gremlin.server; import nl.altindag.log.LogCaptor; +import org.apache.http.Consts; import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; @@ -48,6 +50,7 @@ import java.util.Base64; import java.util.HashMap; import java.util.Map; +import static org.apache.tinkerpop.gremlin.driver.auth.Auth.basic; import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -181,104 +184,81 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt "User %s with address .+? requested: 1\\+3", AuthenticatedUser.ANONYMOUS_USERNAME)))); } -// @Test -// public void shouldAuditLogWithSimpleAuthenticator() throws Exception { -// final String username = "stephen"; -// final String password = "password"; -// -// final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).credentials(username, password).create(); -// final Client client = cluster.connect(); -// -// try { -// assertEquals(2, client.submit("1+1").all().get().get(0).getInt()); -// assertEquals(3, client.submit("1+2").all().get().get(0).getInt()); -// assertEquals(4, client.submit("1+3").all().get().get(0).getInt()); -// assertEquals(5, client.submit("1+4").all().get().get(0).getInt()); -// } finally { -// cluster.close(); -// } -// -// // wait for logger to flush - (don't think there is a way to detect this) -// stopServer(); -// Thread.sleep(1000); -// -// final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName(); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User stephen with address .+? requested: 1\\+1"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User stephen with address .+? requested: 1\\+2"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User stephen with address .+? requested: 1\\+3"))); -// } -// -// @Test -// public void shouldAuditLogWithKrb5Authenticator() throws Exception { -// final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).protocol(kdcServer.serverPrincipalName).create(); -// final Client client = cluster.connect(); -// try { -// assertEquals(2, client.submit("1+1").all().get().get(0).getInt()); -// assertEquals(3, client.submit("1+2").all().get().get(0).getInt()); -// assertEquals(4, client.submit("1+3").all().get().get(0).getInt()); -// } finally { -// cluster.close(); -// } -// -// // wait for logger to flush - (don't think there is a way to detect this) -// stopServer(); -// Thread.sleep(1000); -// -// final String authenticatorName = Krb5Authenticator.class.getSimpleName(); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName)))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User drankye with address .+? requested: 1\\+1"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User drankye with address .+? requested: 1\\+2"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User drankye with address .+? requested: 1\\+3"))); -// } -// -// @Test -// public void shouldNotAuditLogWhenDisabled() throws Exception { -// final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE).protocol(kdcServer.serverPrincipalName).create(); -// final Client client = cluster.connect(); -// try { -// assertEquals(2, client.submit("1+1").all().get().get(0).getInt()); -// assertEquals(3, client.submit("1+2").all().get().get(0).getInt()); -// assertEquals(4, client.submit("1+3").all().get().get(0).getInt()); -// } finally { -// cluster.close(); -// } -// -// // wait for logger to flush - (don't think there is a way to detect this) -// stopServer(); -// Thread.sleep(1000); -// -// final String authenticatorName = Krb5Authenticator.class.getSimpleName(); -// assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName)))); -// assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User drankye with address .+? requested: 1\\+1"))); -// assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User drankye with address .+? requested: 1\\+2"))); -// assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User drankye with address .+? requested: 1\\+3"))); -// } + @Test + public void shouldAuditLogWithSimpleAuthenticator() throws Exception { + final String username = "stephen"; + final String password = "password"; + + final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).auth(basic(username, password)).create(); + final Client client = cluster.connect(); + + try { + assertEquals(2, client.submit("1+1").all().get().get(0).getInt()); + assertEquals(3, client.submit("1+2").all().get().get(0).getInt()); + assertEquals(4, client.submit("1+3").all().get().get(0).getInt()); + assertEquals(5, client.submit("1+4").all().get().get(0).getInt()); + } finally { + cluster.close(); + } + + // wait for logger to flush - (don't think there is a way to detect this) + stopServer(); + Thread.sleep(1000); + + final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName(); + assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)))); + assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? requested: 1\\+1"))); + assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? requested: 1\\+2"))); + assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? requested: 1\\+3"))); + } + + @Test + public void shouldNotAuditLogWhenDisabled() throws Exception { + final String username = "stephen"; + final String password = "password"; + + final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).auth(basic(username, password)).create(); + final Client client = cluster.connect(); + try { + assertEquals(2, client.submit("1+1").all().get().get(0).getInt()); + assertEquals(3, client.submit("1+2").all().get().get(0).getInt()); + assertEquals(4, client.submit("1+3").all().get().get(0).getInt()); + } finally { + cluster.close(); + } + + // wait for logger to flush - (don't think there is a way to detect this) + stopServer(); + Thread.sleep(1000); + + final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName(); + assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + String.format("User %s with address .+? authenticated by %s", username, simpleAuthenticatorName)))); + assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? requested: 1\\+1"))); + assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? requested: 1\\+2"))); + assertFalse(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? requested: 1\\+3"))); + } @Test public void shouldAuditLogWithHttpTransport() throws Exception { final CloseableHttpClient httpclient = HttpClients.createDefault(); - final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=2-1")); - httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes())); + final HttpPost httpPost = new HttpPost(TestClientFactory.createURLString()); + httpPost.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes())); + httpPost.setEntity(new StringEntity("{\"gremlin\":\"2-1\"}", Consts.UTF_8)); - try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + try (final CloseableHttpResponse response = httpclient.execute(httpPost)) { assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("application/json", response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); final JsonNode node = mapper.readTree(json); - assertEquals(1, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); + assertEquals(1, node.get("result").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); } // wait for logger to flush - (don't think there is a way to detect this) @@ -292,78 +272,29 @@ public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerInt "User stephen with address .+? requested: 2-1"))); } -// @Test -// public void shouldAuditLogWithTraversalOp() throws Exception { -// final String username = "stephen"; -// final String password = "password"; -// -// final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).credentials(username, password).create(); -// final GraphTraversalSource g = AnonymousTraversalSource.traversal(). -// withRemote(DriverRemoteConnection.using(cluster, "gmodern")); -// -// try { -// assertEquals(6, g.V().count().next().intValue()); -// } finally { -// cluster.close(); -// } -// -// // wait for logger to flush - (don't think there is a way to detect this) -// stopServer(); -// Thread.sleep(1000); -// -// final String authenticatorName = SimpleAuthenticator.class.getSimpleName(); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// String.format("User %s with address .+? authenticated by %s", username, authenticatorName)))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User .+? with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]"))); -// } - -// @Test -// public void shouldAuditLogTwoClientsWithKrb5Authenticator() throws Exception { -// // calling init to make sure the clusters get their connections primed in low resource environments like travis -// final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE). -// protocol(kdcServer.serverPrincipalName).create(); -// final Client client = cluster.connect(); -// client.init(); -// -// final Cluster cluster2 = TestClientFactory.build(kdcServer.gremlinHostname).jaasEntry(TESTCONSOLE2). -// protocol(kdcServer.serverPrincipalName).create(); -// final Client client2 = cluster2.connect(); -// client2.init(); -// -// try { -// assertEquals(2, client.submit("1+1").all().get().get(0).getInt()); -// assertEquals(22, client2.submit("11+11").all().get().get(0).getInt()); -// assertEquals(3, client.submit("1+2").all().get().get(0).getInt()); -// assertEquals(23, client2.submit("11+12").all().get().get(0).getInt()); -// assertEquals(24, client2.submit("11+13").all().get().get(0).getInt()); -// assertEquals(4, client.submit("1+3").all().get().get(0).getInt()); -// } finally { -// cluster.close(); -// cluster2.close(); -// } -// -// // wait for logger to flush - (don't think there is a way to detect this) -// stopServer(); -// Thread.sleep(1000); -// -// final String authenticatorName = Krb5Authenticator.class.getSimpleName(); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName, authenticatorName)))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User drankye with address .+? requested: 1\\+1"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User drankye with address .+? requested: 1\\+2"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User drankye with address .+? requested: 1\\+3"))); -// -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// String.format("User %s with address .+? authenticated by %s", kdcServer.clientPrincipalName2, authenticatorName)))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User drankye2 with address .+? requested: 11\\+11"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User drankye2 with address .+? requested: 11\\+12"))); -// assertTrue(logCaptor.getLogs().stream().anyMatch(m -> -// m.matches("User drankye2 with address .+? requested: 11\\+13"))); -// } + @Test + public void shouldAuditLogWithTraversalOp() throws Exception { + final String username = "stephen"; + final String password = "password"; + + final Cluster cluster = TestClientFactory.build(kdcServer.gremlinHostname).auth(basic(username, password)).create(); + final GraphTraversalSource g = AnonymousTraversalSource.traversal(). + withRemote(DriverRemoteConnection.using(cluster, "gmodern")); + + try { + assertEquals(6, g.V().count().next().intValue()); + } finally { + cluster.close(); + } + + // wait for logger to flush - (don't think there is a way to detect this) + stopServer(); + Thread.sleep(1000); + + final String authenticatorName = SimpleAuthenticator.class.getSimpleName(); + assertTrue(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + String.format("User %s with address .+? authenticated by %s", username, authenticatorName)))); + assertTrue(logCaptor.getLogs().stream().anyMatch(m -> + m.matches("User .+? with address .+? requested: \\[\\[], \\[V\\(\\), count\\(\\)]]"))); + } } \ No newline at end of file diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java index 4c3ad5d18b..832d1ef6bf 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java @@ -124,7 +124,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra } catch (Exception ex) { assertThat(ex, instanceOf(ExecutionException.class)); final Throwable root = ExceptionHelper.getRootCause(ex); - assertThat(root, instanceOf(IllegalStateException.class)); + assertThat(root.getMessage(), containsString("The server may be expecting SSL to be enabled")); } finally { cluster.close(); } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java index 08eb912d5f..62c08ae54b 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java @@ -20,8 +20,10 @@ package org.apache.tinkerpop.gremlin.server; import io.netty.handler.codec.http.HttpResponseStatus; import nl.altindag.log.LogCaptor; +import org.apache.http.Consts; import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; @@ -50,6 +52,8 @@ import java.util.HashMap; import java.util.Objects; import static org.apache.tinkerpop.gremlin.driver.auth.Auth.basic; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -128,7 +132,6 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr return settings; } - @Ignore("todo: looks at server side AllowListAuthorizer") @Test public void shouldAuthorizeBytecodeRequest() { final Cluster cluster = TestClientFactory.build().auth(basic("stephen", "password")).create(); @@ -167,21 +170,20 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr } catch (Exception ex) { final ResponseException re = (ResponseException) ex.getCause(); assertEquals(HttpResponseStatus.UNAUTHORIZED, re.getResponseStatusCode()); - // assertEquals("Failed to authorize: User not authorized for bytecode requests on [gmodern] using lambdas.", re.getMessage()); + assertEquals("Failed to authorize: User not authorized for bytecode requests on [gmodern] using lambdas.", re.getMessage()); // wait for logger to flush - (don't think there is a way to detect this) stopServer(); Thread.sleep(1000); -// assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User stephen with address .+? attempted an unauthorized request for bytecode operation: " + -// "\\[\\[], \\[V\\(\\), map\\(lambda\\[it.get\\(\\).value\\('name'\\)]\\), count\\(\\)]]")), is(true)); + assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? attempted an unauthorized http request: " + + "\\[\\[], \\[V\\(\\), map\\(lambda\\[it.get\\(\\).value\\('name'\\)]\\), count\\(\\)]]")), is(true)); } finally { cluster.close(); } } - @Ignore("todo: looks at server side AllowListAuthorizer") @Test public void shouldKeepAuthorizingBytecodeRequests() { final Cluster cluster = TestClientFactory.build().auth(basic("stephen", "password")).create(); @@ -229,14 +231,14 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr } catch (Exception ex) { final ResponseException re = (ResponseException) ex.getCause(); assertEquals(HttpResponseStatus.UNAUTHORIZED, re.getResponseStatusCode()); - // assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage()); + assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage()); // wait for logger to flush - (don't think there is a way to detect this) stopServer(); Thread.sleep(1000); -// assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User stephen with address .+? attempted an unauthorized request for eval operation: 1\\+1")), is(true)); + assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? attempted an unauthorized http request: 1\\+1")), is(true)); } finally { cluster.close(); } @@ -253,7 +255,7 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr } catch (Exception ex) { final ResponseException re = (ResponseException) ex.getCause(); assertEquals(HttpResponseStatus.UNAUTHORIZED, re.getResponseStatusCode()); - // assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage()); + assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage()); } finally { cluster.close(); } @@ -270,7 +272,7 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr } catch (Exception ex) { final ResponseException re = (ResponseException) ex.getCause(); assertEquals(HttpResponseStatus.UNAUTHORIZED, re.getResponseStatusCode()); - // assertEquals("Failed to authorize: User not authorized for bytecode requests on [gclassic].", re.getMessage()); + assertEquals("Failed to authorize: User not authorized for bytecode requests on [gclassic].", re.getMessage()); } finally { cluster.close(); } @@ -287,76 +289,78 @@ public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegr } catch (Exception ex) { final ResponseException re = (ResponseException) ex.getCause(); assertEquals(HttpResponseStatus.UNAUTHORIZED, re.getResponseStatusCode()); - // assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage()); + assertEquals("Failed to authorize: User not authorized for string-based requests.", re.getMessage()); } finally { cluster.close(); } } - @Ignore("HttpGet is not supported") @Test public void shouldAuthorizeWithHttpTransport() throws Exception { final CloseableHttpClient httpclient = HttpClients.createDefault(); - final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=2-1")); - httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes())); + final HttpPost httpPost = new HttpPost(TestClientFactory.createURLString()); + httpPost.setEntity(new StringEntity("{\"gremlin\":\"2-1\"}", Consts.UTF_8)); + httpPost.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes())); - try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + try (final CloseableHttpResponse response = httpclient.execute(httpPost)) { assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("application/json", response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); final JsonNode node = mapper.readTree(json); - assertEquals(1, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); + assertEquals(1, node.get("result").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); } } - @Ignore("HttpGet is not supported") @Test public void shouldFailAuthorizeWithHttpTransport() throws Exception { final CloseableHttpClient httpclient = HttpClients.createDefault(); - final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=3-1")); - httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes())); + final HttpPost httpPost = new HttpPost(TestClientFactory.createURLString()); + httpPost.setEntity(new StringEntity("{\"gremlin\":\"3-1\"}", Consts.UTF_8)); + httpPost.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes())); - try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + try (final CloseableHttpResponse response = httpclient.execute(httpPost)) { assertEquals(401, response.getStatusLine().getStatusCode()); } // wait for logger to flush - (don't think there is a way to detect this) stopServer(); Thread.sleep(1000); -// assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches( -// "User stephen with address .+? attempted an unauthorized http request: 3-1")), is(true)); + assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches( + "User stephen with address .+? attempted an unauthorized http request: 3-1")), is(true)); } - @Ignore("HttpGet is not supported") @Test public void shouldKeepAuthorizingWithHttpTransport() throws Exception { - HttpGet httpget; + HttpPost httpPost; final CloseableHttpClient httpclient = HttpClients.createDefault(); - httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=4-1")); - httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes())); - try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + httpPost = new HttpPost(TestClientFactory.createURLString()); + httpPost.setEntity(new StringEntity("{\"gremlin\":\"4-1\"}", Consts.UTF_8)); + httpPost.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes())); + try (final CloseableHttpResponse response = httpclient.execute(httpPost)) { assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("application/json", response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); final JsonNode node = mapper.readTree(json); - assertEquals(3, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); + assertEquals(3, node.get("result").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); } - httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=5-1")); - httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes())); - try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + httpPost = new HttpPost(TestClientFactory.createURLString()); + httpPost.setEntity(new StringEntity("{\"gremlin\":\"5-1\"}", Consts.UTF_8)); + httpPost.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes())); + try (final CloseableHttpResponse response = httpclient.execute(httpPost)) { assertEquals(401, response.getStatusLine().getStatusCode()); } - httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=6-1")); - httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes())); - try (final CloseableHttpResponse response = httpclient.execute(httpget)) { + httpPost = new HttpPost(TestClientFactory.createURLString()); + httpPost.setEntity(new StringEntity("{\"gremlin\":\"6-1\"}", Consts.UTF_8)); + httpPost.addHeader("Authorization", "Basic " + encoder.encodeToString("marko:rainbow-dash".getBytes())); + try (final CloseableHttpResponse response = httpclient.execute(httpPost)) { assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("application/json", response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); final JsonNode node = mapper.readTree(json); - assertEquals(5, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); + assertEquals(5, node.get("result").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue()); } } } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java index 7bfe79d1b4..75dcf666c7 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java @@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.TestHelper; import org.apache.tinkerpop.gremlin.driver.Client; import org.apache.tinkerpop.gremlin.driver.Cluster; import org.apache.tinkerpop.gremlin.driver.Result; +import org.apache.tinkerpop.gremlin.driver.ResultSet; import org.apache.tinkerpop.gremlin.driver.UserAgent; import org.apache.tinkerpop.gremlin.driver.exception.ResponseException; import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; @@ -45,6 +46,7 @@ import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.RemoteGraph; import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.util.ExceptionHelper; import org.apache.tinkerpop.gremlin.util.function.Lambda; import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4; import org.apache.tinkerpop.gremlin.util.message.ResponseMessageV4; @@ -56,6 +58,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -154,9 +157,6 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration // remove the script because it isn't used in the test but also because it's not CompileStatic ready settings.scriptEngines.get("gremlin-groovy").plugins.remove(ScriptFileGremlinPlugin.class.getName()); break; - case "shouldUseInterpreterMode": - settings.scriptEngines.get("gremlin-groovy").plugins.put(GroovyCompilerGremlinPlugin.class.getName(), getScriptEngineConfForInterpreterMode()); - break; case "shouldReceiveFailureTimeOutOnScriptEvalOfOutOfControlLoop": settings.scriptEngines.get("gremlin-groovy").plugins.put(GroovyCompilerGremlinPlugin.class.getName(), getScriptEngineConfForTimedInterrupt()); break; @@ -299,7 +299,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration @Test public void shouldScriptEvaluationErrorForRemoteTraversal() throws Exception { - final GraphTraversalSource g = traversal().with(conf); + final GraphTraversalSource g = traversal().withRemote(conf); try { // tests bad lambda @@ -329,7 +329,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration @Test public void shouldTimeOutRemoteTraversal() throws Exception { - final GraphTraversalSource g = traversal().with(conf); + final GraphTraversalSource g = traversal().withRemote(conf); try { // tests sleeping thread @@ -359,7 +359,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration @Test public void shouldTimeOutRemoteTraversalWithPerRequestOption() throws Exception { - final GraphTraversalSource g = traversal().with(conf); + final GraphTraversalSource g = traversal().withRemote(conf); try { // tests sleeping thread @@ -390,7 +390,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration @Test public void shouldProduceProperExceptionOnTimeout() throws Exception { final Cluster cluster = TestClientFactory.open(); - final Client client = cluster.connect(name.getMethodName()); + final Client client = cluster.connect(); boolean success = false; // Run a short test script a few times with progressively longer timeouts. @@ -431,52 +431,6 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration cluster.close(); } -// TODO: no more sessions so disable until new Transactions implemented -// @Test -// public void shouldUseInterpreterMode() throws Exception { -// final Cluster cluster = TestClientFactory.open(); -// final Client client = cluster.connect(); -// -// client.submit("def subtractAway(x,y){x-y};[]").all().get(); -// client.submit("multiplyIt = { x,y -> x * y};[]").all().get(); -// -// assertEquals(2, client.submit("x = 1 + 1").all().get().get(0).getInt()); -// assertEquals(3, client.submit("int y = x + 1").all().get().get(0).getInt()); -// assertEquals(5, client.submit("def z = x + y").all().get().get(0).getInt()); -// -// final Map<String,Object> m = new HashMap<>(); -// m.put("x", 10); -// assertEquals(-5, client.submit("z - x", m).all().get().get(0).getInt()); -// assertEquals(15, client.submit("addItUp(x,z)", m).all().get().get(0).getInt()); -// assertEquals(5, client.submit("subtractAway(x,z)", m).all().get().get(0).getInt()); -// assertEquals(50, client.submit("multiplyIt(x,z)", m).all().get().get(0).getInt()); -// -// cluster.close(); -// } - -// TODO: no more sessions so disable until new Transactions implemented -// @Test -// public void shouldNotUseInterpreterMode() throws Exception { -// final Cluster cluster = TestClientFactory.open(); -// final Client client = cluster.connect(); -// -// client.submit("def subtractAway(x,y){x-y};[]").all().get(); -// client.submit("multiplyIt = { x,y -> x * y};[]").all().get(); -// -// assertEquals(2, client.submit("x = 1 + 1").all().get().get(0).getInt()); -// assertEquals(3, client.submit("y = x + 1").all().get().get(0).getInt()); -// assertEquals(5, client.submit("z = x + y").all().get().get(0).getInt()); -// -// final Map<String,Object> m = new HashMap<>(); -// m.put("x", 10); -// assertEquals(-5, client.submit("z - x", m).all().get().get(0).getInt()); -// assertEquals(15, client.submit("addItUp(x,z)", m).all().get().get(0).getInt()); -// assertEquals(5, client.submit("subtractAway(x,z)", m).all().get().get(0).getInt()); -// assertEquals(50, client.submit("multiplyIt(x,z)", m).all().get().get(0).getInt()); -// -// cluster.close(); -// } - @Test public void shouldUseSimpleSandbox() throws Exception { final Cluster cluster = TestClientFactory.open(); @@ -651,42 +605,41 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration } } -// TODO: re-enable once there is an easier way to check for this. batchSize replaced with chunkSize so need GLV updated to test. -// @Test -// @SuppressWarnings("unchecked") -// public void shouldBatchResultsByTwos() throws Exception { -// try (SimpleClient client = TestClientFactory.createSimpleHttpClient()) { -// final RequestMessageV4 request = RequestMessageV4.build("[0,1,2,3,4,5,6,7,8,9]").create(); -// -// final List<ResponseMessage> msgs = client.submit(request); -// assertEquals(5, client.submit(request).size()); -// assertEquals(0, ((List<Integer>) msgs.get(0).getResult().getData()).get(0).intValue()); -// assertEquals(1, ((List<Integer>) msgs.get(0).getResult().getData()).get(1).intValue()); -// assertEquals(2, ((List<Integer>) msgs.get(1).getResult().getData()).get(0).intValue()); -// assertEquals(3, ((List<Integer>) msgs.get(1).getResult().getData()).get(1).intValue()); -// assertEquals(4, ((List<Integer>) msgs.get(2).getResult().getData()).get(0).intValue()); -// assertEquals(5, ((List<Integer>) msgs.get(2).getResult().getData()).get(1).intValue()); -// assertEquals(6, ((List<Integer>) msgs.get(3).getResult().getData()).get(0).intValue()); -// assertEquals(7, ((List<Integer>) msgs.get(3).getResult().getData()).get(1).intValue()); -// assertEquals(8, ((List<Integer>) msgs.get(4).getResult().getData()).get(0).intValue()); -// assertEquals(9, ((List<Integer>) msgs.get(4).getResult().getData()).get(1).intValue()); -// } -// } + @Test + @SuppressWarnings("unchecked") + public void shouldBatchResultsByTwos() throws Exception { + try (SimpleClient client = TestClientFactory.createSimpleHttpClient()) { + final RequestMessageV4 request = RequestMessageV4.build("[0,1,2,3,4,5,6,7,8,9]").create(); -// @Test -// public void shouldBatchResultsByTwosWithDriver() throws Exception { -// final Cluster cluster = TestClientFactory.build().create(); -// final Client client = cluster.connect(); -// -// try { -// final List<Result> results = client.submit("[0,1,2,3,4,5,6,7,8,9]").all().join(); -// for (int ix = 0; ix < results.size(); ix++) { -// assertEquals(ix, results.get(ix).getInt()); -// } -// } finally { -// cluster.close(); -// } -// } + final List<ResponseMessageV4> msgs = client.submit(request); + assertEquals(5, client.submit(request).size()); + assertEquals(0, (int) msgs.get(0).getResult().getData().get(0)); + assertEquals(1, (int) msgs.get(0).getResult().getData().get(1)); + assertEquals(2, (int) msgs.get(1).getResult().getData().get(0)); + assertEquals(3, (int) msgs.get(1).getResult().getData().get(1)); + assertEquals(4, (int) msgs.get(2).getResult().getData().get(0)); + assertEquals(5, (int) msgs.get(2).getResult().getData().get(1)); + assertEquals(6, (int) msgs.get(3).getResult().getData().get(0)); + assertEquals(7, (int) msgs.get(3).getResult().getData().get(1)); + assertEquals(8, (int) msgs.get(4).getResult().getData().get(0)); + assertEquals(9, (int) msgs.get(4).getResult().getData().get(1)); + } + } + + @Test + public void shouldBatchResultsByTwosWithDriver() throws Exception { + final Cluster cluster = TestClientFactory.build().create(); + final Client client = cluster.connect(); + + try { + final List<Result> results = client.submit("[0,1,2,3,4,5,6,7,8,9]").all().join(); + for (int ix = 0; ix < results.size(); ix++) { + assertEquals(ix, results.get(ix).getInt()); + } + } finally { + cluster.close(); + } + } @Test public void shouldNotThrowNoSuchElementException() throws Exception { @@ -717,7 +670,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration .addTimeoutMillis(100L) .create(); final List<ResponseMessageV4> responses = client.submit(msg); - assertThat(responses.get(0).getStatus().getMessage(), allOf(startsWith("Evaluation exceeded"), containsString("100 ms"))); + assertThat(responses.get(0).getStatus().getMessage(), containsString("A timeout occurred during traversal evaluation")); // validate that we can still send messages to the server assertEquals(2, ((Integer) (client.submit("1+1").get(0).getResult().getData()).get(0)).intValue()); @@ -768,59 +721,36 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration } } - // GraphSON does not support deserialization of streaming data + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + @Test + public void shouldBlockRequestWhenTooBig() throws Exception { + final Cluster cluster = TestClientFactory.open(); + final Client client = cluster.connect(); -// @Test -// public void shouldReceiveFailureOnBadGraphSONSerialization() throws Exception { -// final Cluster cluster = TestClientFactory.build().serializer(Serializers.GRAPHSON_V4).create(); -// final Client client = cluster.connect(); -// -// try { -// client.submit("class C { def C getC(){return this}}; new C()").all().join(); -// fail("Should throw an exception."); -// } catch (RuntimeException re) { -// final Throwable root = ExceptionHelper.getRootCause(re); -// assertThat(root.getMessage(), CoreMatchers.startsWith("Error during serialization: Direct self-reference leading to cycle (through reference chain:")); -// -// // validate that we can still send messages to the server -// assertEquals(2, client.submit("1+1").all().join().get(0).getInt()); -// } finally { -// cluster.close(); -// } -// } + try { + final String fatty = IntStream.range(0, 1024).mapToObj(String::valueOf).collect(Collectors.joining()); + final CompletableFuture<ResultSet> result = client.submitAsync("'" + fatty + "';'test'"); + final ResultSet resultSet = result.get(10000, TimeUnit.MILLISECONDS); + resultSet.all().get(10000, TimeUnit.MILLISECONDS); + fail("Should throw an exception."); + } catch (TimeoutException te) { + // the request should not have timed-out - the connection should have been reset, but it seems that + // timeout seems to occur as well on some systems (it's not clear why). however, the nature of this + // test is to ensure that the script isn't processed if it exceeds a certain size, so in this sense + // it seems ok to pass in this case. + } catch (Exception re) { + final Throwable root = ExceptionHelper.getRootCause(re); + + // went with two possible error messages here as i think that there is some either non-deterministic + // behavior around the error message or it's environmentally dependent (e.g. different jdk, versions, etc) + assertThat(root.getMessage(), Matchers.anyOf(is("Connection to server is no longer active"), is("Connection reset by peer"))); -// TODO: this test isn't valid right now since this error is thrown by netty so doesn't map properly to RequestId -// sent by the driver. Re-enable once this changes. -// @SuppressWarnings("ThrowableResultOfMethodCallIgnored") -// @Test -// public void shouldBlockRequestWhenTooBig() throws Exception { -// final Cluster cluster = TestClientFactory.open(); -// final Client client = cluster.connect(); -// -// try { -// final String fatty = IntStream.range(0, 1024).mapToObj(String::valueOf).collect(Collectors.joining()); -// final CompletableFuture<ResultSet> result = client.submitAsync("'" + fatty + "';'test'"); -// final ResultSet resultSet = result.get(10000, TimeUnit.MILLISECONDS); -// resultSet.all().get(10000, TimeUnit.MILLISECONDS); -// fail("Should throw an exception."); -// } catch (TimeoutException te) { -// // the request should not have timed-out - the connection should have been reset, but it seems that -// // timeout seems to occur as well on some systems (it's not clear why). however, the nature of this -// // test is to ensure that the script isn't processed if it exceeds a certain size, so in this sense -// // it seems ok to pass in this case. -// } catch (Exception re) { -// final Throwable root = ExceptionHelper.getRootCause(re); -// -// // went with two possible error messages here as i think that there is some either non-deterministic -// // behavior around the error message or it's environmentally dependent (e.g. different jdk, versions, etc) -// assertThat(root.getMessage(), Matchers.anyOf(is("Connection to server is no longer active"), is("Connection reset by peer"))); -// -// // validate that we can still send messages to the server -// assertEquals(2, client.submit("1+1").all().join().get(0).getInt()); -// } finally { -// cluster.close(); -// } -// } + // validate that we can still send messages to the server + assertEquals(2, client.submit("1+1").all().join().get(0).getInt()); + } finally { + cluster.close(); + } + } @Test public void shouldFailOnDeadHost() throws Exception { @@ -893,8 +823,6 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration assertNull(responses.get(0).getStatus()); // second one contains last piece of data assertEquals(HttpResponseStatus.OK, responses.get(1).getStatus().getCode()); - // last message with no data, but with trailing headers - assertEquals(HttpResponseStatus.NO_CONTENT, responses.get(2).getStatus().getCode()); } } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java index 44a9a681b5..e8538ab8e3 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSerializationIntegrateTest.java @@ -58,8 +58,7 @@ public class GremlinServerSerializationIntegrateTest extends AbstractGremlinServ @Parameterized.Parameters public static Collection serializers() { return Arrays.asList(new Object[][]{ - {new GraphBinaryMessageSerializerV4()}, - {new GraphSONMessageSerializerV4()} + {new GraphBinaryMessageSerializerV4()} }); } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java index 05d1836a48..dbf051ca77 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSslIntegrateTest.java @@ -31,6 +31,7 @@ import org.apache.tinkerpop.gremlin.driver.exception.NoHostAvailableException; import org.apache.tinkerpop.gremlin.driver.simple.SimpleClient; import org.apache.tinkerpop.gremlin.util.ExceptionHelper; import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4; +import org.junit.Ignore; import org.junit.Test; import javax.net.ssl.SSLException; @@ -43,6 +44,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsInstanceOf.instanceOf; @@ -213,9 +215,9 @@ public class GremlinServerSslIntegrateTest extends AbstractGremlinServerIntegrat client.submit("'test'").one(); fail("Should throw exception because ssl is enabled on the server but not on client"); } catch(Exception x) { - assertThat(x, instanceOf(NoHostAvailableException.class)); final Throwable root = ExceptionHelper.getRootCause(x); assertThat(root, instanceOf(RuntimeException.class)); + assertThat(root.getMessage(), containsString("The server may be expecting SSL to be enabled")); } finally { cluster.close(); } @@ -257,9 +259,9 @@ public class GremlinServerSslIntegrateTest extends AbstractGremlinServerIntegrat client.submit("'test'").one(); fail("Should throw exception because ssl client auth is enabled on the server but client does not have a cert"); } catch (Exception x) { - assertThat(x, instanceOf(NoHostAvailableException.class)); final Throwable root = ExceptionHelper.getRootCause(x); assertThat(root, instanceOf(SSLException.class)); + assertThat(root.getMessage(), containsString("bad_certificate")); } finally { cluster.close(); } @@ -275,9 +277,9 @@ public class GremlinServerSslIntegrateTest extends AbstractGremlinServerIntegrat client.submit("'test'").one(); fail("Should throw exception because ssl client auth is enabled on the server but does not trust client's cert"); } catch (Exception x) { - assertThat(x, instanceOf(NoHostAvailableException.class)); final Throwable root = ExceptionHelper.getRootCause(x); assertThat(root, instanceOf(SSLException.class)); + assertThat(root.getMessage(), containsString("bad_certificate")); } finally { cluster.close(); } @@ -293,14 +295,16 @@ public class GremlinServerSslIntegrateTest extends AbstractGremlinServerIntegrat client.submit("'test'").one(); fail("Should throw exception because ssl client requires TLSv1.2 whereas server supports only TLSv1.1"); } catch (Exception x) { - assertThat(x, instanceOf(NoHostAvailableException.class)); final Throwable root = ExceptionHelper.getRootCause(x); assertThat(root, instanceOf(SSLException.class)); + assertThat(root.getMessage(), containsString("protocol_version")); } finally { cluster.close(); } } + // TODO: Add client-side SSL checking. + @Ignore("No client side SSL checking") @Test public void shouldEnableSslAndFailIfCiphersDontMatch() { final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS) @@ -311,7 +315,6 @@ public class GremlinServerSslIntegrateTest extends AbstractGremlinServerIntegrat client.submit("'test'").one(); fail("Should throw exception because ssl client requires TLSv1.2 whereas server supports only TLSv1.1"); } catch (Exception x) { - assertThat(x, instanceOf(NoHostAvailableException.class)); final Throwable root = ExceptionHelper.getRootCause(x); assertThat(root, instanceOf(SSLException.class)); } finally { diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java index 8fde5d13c4..0852ad55b0 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java @@ -54,11 +54,7 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre private final Base64.Encoder encoder = Base64.getUrlEncoder(); protected static final String HTTP = "http"; - protected static final String WS = "ws"; protected static final String HTTPS = "https"; - protected static final String WSS = "wss"; - protected static final String WS_AND_HTTP = "wsAndHttp"; - protected static final String WSS_AND_HTTPS = "wssAndHttps"; public abstract String getProtocol(); public abstract String getSecureProtocol(); @@ -174,9 +170,6 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre public class CombinedTestClient { private CloseableHttpClient httpClient = null; - private Cluster wsCluster = null; - private Cluster.Builder wsBuilder = null; - private Client wsClient = null; private boolean secure = false; @@ -189,22 +182,6 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre httpClient = createSslHttpClient(); secure = true; break; - case WS: - this.wsBuilder = TestClientFactory.build(); - break; - case WSS: - this.wsBuilder = TestClientFactory.build(); - secure = true; - break; - case WS_AND_HTTP: - httpClient = HttpClients.createDefault(); - this.wsBuilder = TestClientFactory.build(); - break; - case WSS_AND_HTTPS: - httpClient = createSslHttpClient(); - secure = true; - this.wsBuilder = TestClientFactory.build(); - break; } } @@ -234,9 +211,6 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre if (httpClient != null) { httpClient.close(); } - if (wsCluster != null) { - wsCluster.close(); - } } public void sendAndAssertUnauthorized(final String gremlin, final String username, final String password) throws Exception { @@ -246,15 +220,6 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre assertEquals(401, response.getStatusLine().getStatusCode()); } } - if (wsBuilder != null) { - setWsClient(username, password); - try { - wsClient.submit(gremlin).all().get(); - fail("Should not authorize on incorrect auth creds"); - } catch(Exception e) { - assertEquals("Username and/or password are incorrect", e.getCause().getMessage()); - } - } } public void sendAndAssert(final String gremlin, final Object result, final String username, final String password) throws Exception { @@ -265,22 +230,9 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre assertEquals("application/json", response.getEntity().getContentType().getValue()); final String json = EntityUtils.toString(response.getEntity()); final JsonNode node = mapper.readTree(json); - assertEquals(result, node.get("result").get("data").get("@value").get(0).get("@value").intValue()); + assertEquals(result, node.get("result").get("@value").get(0).get("@value").intValue()); } } - if (wsBuilder != null) { - setWsClient(username, password); - assertEquals(result, wsClient.submit(gremlin).all().get().get(0).getInt()); - } - } - - private void setWsClient(final String username, final String password) { - if (username != null && password != null) { - wsClient = wsCluster.connect(); - } else { - wsCluster = wsBuilder.enableSsl(secure).sslSkipCertValidation(true).create(); - wsClient = wsCluster.connect(); - } } private HttpPost createPost(final String gremlin, final String username, final String password) { diff --git a/gremlin-server/src/test/resources/conf/remote-objects.yaml b/gremlin-server/src/test/resources/conf/remote-objects.yaml index f9043f0cf6..a0f3318768 100644 --- a/gremlin-server/src/test/resources/conf/remote-objects.yaml +++ b/gremlin-server/src/test/resources/conf/remote-objects.yaml @@ -29,4 +29,4 @@ hosts: [localhost] port: 45940 -serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1 } \ No newline at end of file +serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV4 } \ No newline at end of file diff --git a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java index a70eac6b25..f5b6fff101 100644 --- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java +++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java @@ -286,8 +286,7 @@ public class GraphBinaryMessageSerializerV4 extends AbstractMessageSerializerV4< try { // empty input buffer if (buffer.readableBytes() == 0) { - return ResponseMessageV4.build(). - code(HttpResponseStatus.NO_CONTENT).result(Collections.emptyList()).create(); + return ResponseMessageV4.build().result(Collections.emptyList()).create(); } if (isFirstChunk) {