You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/03/12 18:18:42 UTC
[1/3] incubator-tinkerpop git commit: Renamed GremlinExecutorTest in
preparation to split test between those that need a Graph and those that
don't.
Repository: incubator-tinkerpop
Updated Branches:
refs/heads/master 3b4b39432 -> 26c2b99a7
Renamed GremlinExecutorTest in preparation to split test between those that need a Graph and those that don't.
This will allow for some separation between tests required for integration testing with graphs and those that can just be treated as a unit test.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/8153a0a5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/8153a0a5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/8153a0a5
Branch: refs/heads/master
Commit: 8153a0a5c3a3415624492b1576ba1788646d757b
Parents: 3b4b394
Author: Stephen Mallette <sp...@apache.org>
Authored: Thu Mar 12 12:39:37 2015 -0400
Committer: Stephen Mallette <sp...@apache.org>
Committed: Thu Mar 12 12:39:37 2015 -0400
----------------------------------------------------------------------
.../gremlin/groovy/GroovyEnvironmentSuite.java | 4 +-
.../engine/GremlinExecutorOverGraphTest.java | 481 ++++++++++++++++++
.../groovy/engine/GremlinExecutorTest.java | 487 -------------------
3 files changed, 483 insertions(+), 489 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8153a0a5/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
index b0108b3..54ec7ed 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
@@ -21,7 +21,7 @@ package org.apache.tinkerpop.gremlin.groovy;
import org.apache.tinkerpop.gremlin.AbstractGremlinSuite;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.GraphManager;
-import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutorTest;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutorOverGraphTest;
import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineTest;
import org.apache.tinkerpop.gremlin.groovy.loaders.GremlinLoaderTest;
import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader;
@@ -42,7 +42,7 @@ public class GroovyEnvironmentSuite extends AbstractGremlinSuite {
private static final Class<?>[] allTests = new Class<?>[]{
GremlinGroovyScriptEngineTest.class,
- GremlinExecutorTest.class,
+ GremlinExecutorOverGraphTest.class,
GremlinLoaderTest.class,
SugarLoaderTest.class,
};
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8153a0a5/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
new file mode 100644
index 0000000..99b4c8c
--- /dev/null
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
@@ -0,0 +1,481 @@
+/*
+ * 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.groovy.engine;
+
+import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.TestHelper;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineTest;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.junit.Test;
+import org.kohsuke.groovy.sandbox.GroovyInterceptor;
+
+import javax.script.Bindings;
+import javax.script.CompiledScript;
+import javax.script.SimpleBindings;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.IntStream;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinExecutorOverGraphTest extends AbstractGremlinTest {
+ public static Map<String, String> PATHS = new HashMap<>();
+ private final BasicThreadFactory testingThreadFactory = new BasicThreadFactory.Builder().namingPattern("test-gremlin-executor-%d").build();
+
+ static {
+ try {
+ final List<String> groovyScriptResources = Arrays.asList("GremlinExecutorInit.groovy");
+ for (final String fileName : groovyScriptResources) {
+ PATHS.put(fileName, TestHelper.generateTempFileFromResource(GremlinExecutorOverGraphTest.class, fileName, "").getAbsolutePath());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void shouldEvalScript() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ assertEquals(2, gremlinExecutor.eval("1+1").get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldCompileScript() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ final CompiledScript script = gremlinExecutor.compile("1+1").get();
+ assertEquals(2, script.eval());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalMultipleScripts() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ assertEquals(2, gremlinExecutor.eval("1+1").get());
+ assertEquals(3, gremlinExecutor.eval("1+2").get());
+ assertEquals(4, gremlinExecutor.eval("1+3").get());
+ assertEquals(5, gremlinExecutor.eval("1+4").get());
+ assertEquals(6, gremlinExecutor.eval("1+5").get());
+ assertEquals(7, gremlinExecutor.eval("1+6").get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithBindings() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ final Bindings b = new SimpleBindings();
+ b.put("x", 1);
+ assertEquals(2, gremlinExecutor.eval("1+x", b).get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithGlobalBindings() throws Exception {
+ final Bindings b = new SimpleBindings();
+ b.put("x", 1);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(b).create();
+ assertEquals(2, gremlinExecutor.eval("1+x").get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithGlobalAndLocalBindings() throws Exception {
+ final Bindings g = new SimpleBindings();
+ g.put("x", 1);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
+ final Bindings b = new SimpleBindings();
+ b.put("y", 1);
+ assertEquals(2, gremlinExecutor.eval("y+x", b).get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithLocalOverridingGlobalBindings() throws Exception {
+ final Bindings g = new SimpleBindings();
+ g.put("x", 1);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
+ final Bindings b = new SimpleBindings();
+ b.put("x", 10);
+ assertEquals(11, gremlinExecutor.eval("x+1", b).get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldTimeoutSleepingScript() throws Exception {
+ final AtomicBoolean successCalled = new AtomicBoolean(false);
+ final AtomicBoolean failureCalled = new AtomicBoolean(false);
+
+ final CountDownLatch timeOutCount = new CountDownLatch(1);
+
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .scriptEvaluationTimeout(250)
+ .afterFailure((b, e) -> failureCalled.set(true))
+ .afterSuccess((b) -> successCalled.set(true))
+ .afterTimeout((b) -> timeOutCount.countDown()).create();
+ try {
+ gremlinExecutor.eval("Thread.sleep(1000);10").get();
+ fail("This script should have timed out with an exception");
+ } catch (Exception ex) {
+ assertEquals(TimeoutException.class, ex.getCause().getClass());
+ }
+
+ assertTrue(timeOutCount.await(2000, TimeUnit.MILLISECONDS));
+
+ assertFalse(successCalled.get());
+ assertFalse(failureCalled.get());
+ assertEquals(0, timeOutCount.getCount());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldCallFail() throws Exception {
+ final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
+ final AtomicBoolean successCalled = new AtomicBoolean(false);
+ final AtomicBoolean failureCalled = new AtomicBoolean(false);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .afterFailure((b, e) -> failureCalled.set(true))
+ .afterSuccess((b) -> successCalled.set(true))
+ .afterTimeout((b) -> timeoutCalled.set(true)).create();
+ try {
+ gremlinExecutor.eval("10/0").get();
+ fail();
+ } catch (Exception ex) {
+
+ }
+
+ // need to wait long enough for the script to complete
+ Thread.sleep(750);
+
+ assertFalse(timeoutCalled.get());
+ assertFalse(successCalled.get());
+ assertTrue(failureCalled.get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldCallSuccess() throws Exception {
+ final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
+ final AtomicBoolean successCalled = new AtomicBoolean(false);
+ final AtomicBoolean failureCalled = new AtomicBoolean(false);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .afterFailure((b, e) -> failureCalled.set(true))
+ .afterSuccess((b) -> successCalled.set(true))
+ .afterTimeout((b) -> timeoutCalled.set(true)).create();
+ assertEquals(2, gremlinExecutor.eval("1+1").get());
+
+ // need to wait long enough for the script to complete
+ Thread.sleep(750);
+
+ assertFalse(timeoutCalled.get());
+ assertTrue(successCalled.get());
+ assertFalse(failureCalled.get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldAllowTraversalToIterateInDifferentThreadThanOriginallyEvaluatedWithAutoCommit() throws Exception {
+ // this test sort of simulates Gremlin Server interaction where a Traversal is eval'd in one Thread, but
+ // then iterated in another. note that Gremlin Server configures the script engine to auto-commit
+ // after evaluation. this basically tests the state of the Gremlin Server GremlinExecutor when
+ // being used in sessionless mode
+ final ExecutorService evalExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .afterSuccess(b -> {
+ final Graph graph = (Graph) b.get("g");
+ if (graph.features().graph().supportsTransactions())
+ graph.tx().commit();
+ })
+ .executorService(evalExecutor).create();
+
+ final Map<String,Object> bindings = new HashMap<>();
+ bindings.put("g", g);
+
+ final AtomicInteger vertexCount = new AtomicInteger(0);
+
+ final ExecutorService iterationExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
+ gremlinExecutor.eval("g.V().out()", bindings).thenAcceptAsync(o -> {
+ final Iterator itty = (Iterator) o;
+ itty.forEachRemaining(v -> vertexCount.incrementAndGet());
+ }, iterationExecutor).join();
+
+ assertEquals(6, vertexCount.get());
+
+ gremlinExecutor.close();
+ evalExecutor.shutdown();
+ evalExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ iterationExecutor.shutdown();
+ iterationExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldAllowTraversalToIterateInDifferentThreadThanOriginallyEvaluatedWithoutAutoCommit() throws Exception {
+ // this test sort of simulates Gremlin Server interaction where a Traversal is eval'd in one Thread, but
+ // then iterated in another. this basically tests the state of the Gremlin Server GremlinExecutor when
+ // being used in session mode
+ final ExecutorService evalExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().executorService(evalExecutor).create();
+
+ final Map<String,Object> bindings = new HashMap<>();
+ bindings.put("g", g);
+
+ final AtomicInteger vertexCount = new AtomicInteger(0);
+
+ final ExecutorService iterationExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
+ gremlinExecutor.eval("g.V().out()", bindings).thenAcceptAsync(o -> {
+ final Iterator itty = (Iterator) o;
+ itty.forEachRemaining(v -> vertexCount.incrementAndGet());
+ }, iterationExecutor).join();
+
+ assertEquals(6, vertexCount.get());
+
+ gremlinExecutor.close();
+ evalExecutor.shutdown();
+ evalExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ iterationExecutor.shutdown();
+ iterationExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void shouldEvalInMultipleThreads() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+
+ final CyclicBarrier barrier = new CyclicBarrier(2);
+ final AtomicInteger i1 = new AtomicInteger(0);
+ final AtomicBoolean b1 = new AtomicBoolean(false);
+ final Thread t1 = new Thread(() -> {
+ try {
+ barrier.await();
+ i1.set((Integer) gremlinExecutor.eval("1+1").get());
+ } catch (Exception ex) {
+ b1.set(true);
+ }
+ });
+
+ final AtomicInteger i2 = new AtomicInteger(0);
+ final AtomicBoolean b2 = new AtomicBoolean(false);
+ final Thread t2 = new Thread(() -> {
+ try {
+ barrier.await();
+ i2.set((Integer) gremlinExecutor.eval("1+1").get());
+ } catch (Exception ex) {
+ b2.set(true);
+ }
+ });
+
+ t1.start();
+ t2.start();
+
+ t1.join();
+ t2.join();
+
+ assertEquals(2, i1.get());
+ assertEquals(2, i2.get());
+ assertFalse(b1.get());
+ assertFalse(b2.get());
+
+ gremlinExecutor.close();
+
+ }
+
+ @Test
+ public void shouldNotExhaustThreads() throws Exception {
+ final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2, testingThreadFactory);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .executorService(executorService)
+ .scheduledExecutorService(executorService).create();
+
+ final AtomicInteger count = new AtomicInteger(0);
+ assertTrue(IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("1+1")).allMatch(f -> {
+ try {
+ return (Integer) f.get() == 2;
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ count.incrementAndGet();
+ }
+ }));
+
+ assertEquals(1000, count.intValue());
+
+ executorService.shutdown();
+ executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void shouldFailUntilImportExecutes() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+
+ final Set<String> imports = new HashSet<String>() {{
+ add("import java.awt.Color");
+ }};
+
+ final AtomicInteger successes = new AtomicInteger(0);
+ final AtomicInteger failures = new AtomicInteger(0);
+
+ // issue 1000 scripts in one thread using a class that isn't imported. this will result in failure.
+ // while that thread is running start a new thread that issues an addImports to include that class.
+ // this should block further evals in the first thread until the import is complete at which point
+ // evals in the first thread will resume and start to succeed
+ final Thread t1 = new Thread(() ->
+ IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("Color.BLACK"))
+ .forEach(f -> {
+ f.exceptionally(t -> failures.incrementAndGet()).join();
+ if (!f.isCompletedExceptionally())
+ successes.incrementAndGet();
+ })
+ );
+
+ final Thread t2 = new Thread(() -> {
+ while (failures.get() < 500) {
+ }
+ gremlinExecutor.getScriptEngines().addImports(imports);
+ });
+
+ t1.start();
+ t2.start();
+
+ t1.join();
+ t2.join();
+
+ assertTrue(successes.intValue() > 0);
+ assertTrue(failures.intValue() >= 500);
+
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldInitializeWithScript() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ Collections.emptyMap())
+ .create();
+
+ assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
+
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldSecureAll() throws Exception {
+ GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
+ final Map<String, Object> config = new HashMap<>();
+ config.put("sandbox", GremlinGroovyScriptEngineTest.DenyAll.class.getName());
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ config)
+ .create();
+ try {
+ gremlinExecutor.eval("c = new java.awt.Color(255, 255, 255)").get();
+ fail("Should have failed security");
+ } catch (Exception se) {
+ assertEquals(SecurityException.class, se.getCause().getClass());
+ } finally {
+ gremlinExecutor.close();
+ }
+ }
+
+ @Test
+ public void shouldSecureSome() throws Exception {
+ GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
+ final Map<String, Object> config = new HashMap<>();
+ config.put("sandbox", GremlinGroovyScriptEngineTest.AllowSome.class.getName());
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ config)
+ .create();
+ try {
+ gremlinExecutor.eval("c = 'new java.awt.Color(255, 255, 255)'").get();
+ fail("Should have failed security");
+ } catch (Exception se) {
+ assertEquals(SecurityException.class, se.getCause().getClass());
+ }
+
+ try {
+ final java.awt.Color c = (java.awt.Color) gremlinExecutor.eval("g = new java.awt.Color(255, 255, 255)").get();
+ assertEquals(java.awt.Color.class, c.getClass());
+ } catch (Exception ignored) {
+ fail("Should not have tossed an exception");
+ } finally {
+ gremlinExecutor.close();
+ }
+ }
+
+ @Test
+ public void shouldInitializeWithScriptAndWorkAfterReset() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ Collections.emptyMap())
+ .create();
+
+ assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
+
+ gremlinExecutor.getScriptEngines().reset();
+
+ assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
+
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldNotShutdownExecutorServicesSuppliedToGremlinExecutor() throws Exception {
+ final ScheduledExecutorService service = Executors.newScheduledThreadPool(4, testingThreadFactory);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .executorService(service)
+ .scheduledExecutorService(service).create();
+
+ gremlinExecutor.close();
+ assertFalse(service.isShutdown());
+ service.shutdown();
+ service.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8153a0a5/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
deleted file mode 100644
index d516bab..0000000
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * 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.groovy.engine;
-
-import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.TestHelper;
-import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineTest;
-import org.apache.tinkerpop.gremlin.process.TraversalStrategies;
-import org.apache.tinkerpop.gremlin.process.graph.traversal.strategy.TimeLimitedStrategy;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
-import org.junit.Test;
-import org.kohsuke.groovy.sandbox.GroovyInterceptor;
-
-import javax.script.Bindings;
-import javax.script.CompiledScript;
-import javax.script.SimpleBindings;
-import java.sql.Time;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-
-import static org.junit.Assert.*;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class GremlinExecutorTest extends AbstractGremlinTest {
- public static Map<String, String> PATHS = new HashMap<>();
- private final BasicThreadFactory testingThreadFactory = new BasicThreadFactory.Builder().namingPattern("test-gremlin-executor-%d").build();
-
- static {
- try {
- final List<String> groovyScriptResources = Arrays.asList("GremlinExecutorInit.groovy");
- for (final String fileName : groovyScriptResources) {
- PATHS.put(fileName, TestHelper.generateTempFileFromResource(GremlinExecutorTest.class, fileName, "").getAbsolutePath());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @Test
- public void shouldEvalScript() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- assertEquals(2, gremlinExecutor.eval("1+1").get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldCompileScript() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- final CompiledScript script = gremlinExecutor.compile("1+1").get();
- assertEquals(2, script.eval());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalMultipleScripts() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- assertEquals(2, gremlinExecutor.eval("1+1").get());
- assertEquals(3, gremlinExecutor.eval("1+2").get());
- assertEquals(4, gremlinExecutor.eval("1+3").get());
- assertEquals(5, gremlinExecutor.eval("1+4").get());
- assertEquals(6, gremlinExecutor.eval("1+5").get());
- assertEquals(7, gremlinExecutor.eval("1+6").get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithBindings() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- final Bindings b = new SimpleBindings();
- b.put("x", 1);
- assertEquals(2, gremlinExecutor.eval("1+x", b).get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithGlobalBindings() throws Exception {
- final Bindings b = new SimpleBindings();
- b.put("x", 1);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(b).create();
- assertEquals(2, gremlinExecutor.eval("1+x").get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithGlobalAndLocalBindings() throws Exception {
- final Bindings g = new SimpleBindings();
- g.put("x", 1);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
- final Bindings b = new SimpleBindings();
- b.put("y", 1);
- assertEquals(2, gremlinExecutor.eval("y+x", b).get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithLocalOverridingGlobalBindings() throws Exception {
- final Bindings g = new SimpleBindings();
- g.put("x", 1);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
- final Bindings b = new SimpleBindings();
- b.put("x", 10);
- assertEquals(11, gremlinExecutor.eval("x+1", b).get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldTimeoutSleepingScript() throws Exception {
- final AtomicBoolean successCalled = new AtomicBoolean(false);
- final AtomicBoolean failureCalled = new AtomicBoolean(false);
-
- final CountDownLatch timeOutCount = new CountDownLatch(1);
-
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .scriptEvaluationTimeout(250)
- .afterFailure((b, e) -> failureCalled.set(true))
- .afterSuccess((b) -> successCalled.set(true))
- .afterTimeout((b) -> timeOutCount.countDown()).create();
- try {
- gremlinExecutor.eval("Thread.sleep(1000);10").get();
- fail("This script should have timed out with an exception");
- } catch (Exception ex) {
- assertEquals(TimeoutException.class, ex.getCause().getClass());
- }
-
- assertTrue(timeOutCount.await(2000, TimeUnit.MILLISECONDS));
-
- assertFalse(successCalled.get());
- assertFalse(failureCalled.get());
- assertEquals(0, timeOutCount.getCount());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldCallFail() throws Exception {
- final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
- final AtomicBoolean successCalled = new AtomicBoolean(false);
- final AtomicBoolean failureCalled = new AtomicBoolean(false);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .afterFailure((b, e) -> failureCalled.set(true))
- .afterSuccess((b) -> successCalled.set(true))
- .afterTimeout((b) -> timeoutCalled.set(true)).create();
- try {
- gremlinExecutor.eval("10/0").get();
- fail();
- } catch (Exception ex) {
-
- }
-
- // need to wait long enough for the script to complete
- Thread.sleep(750);
-
- assertFalse(timeoutCalled.get());
- assertFalse(successCalled.get());
- assertTrue(failureCalled.get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldCallSuccess() throws Exception {
- final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
- final AtomicBoolean successCalled = new AtomicBoolean(false);
- final AtomicBoolean failureCalled = new AtomicBoolean(false);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .afterFailure((b, e) -> failureCalled.set(true))
- .afterSuccess((b) -> successCalled.set(true))
- .afterTimeout((b) -> timeoutCalled.set(true)).create();
- assertEquals(2, gremlinExecutor.eval("1+1").get());
-
- // need to wait long enough for the script to complete
- Thread.sleep(750);
-
- assertFalse(timeoutCalled.get());
- assertTrue(successCalled.get());
- assertFalse(failureCalled.get());
- gremlinExecutor.close();
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldAllowTraversalToIterateInDifferentThreadThanOriginallyEvaluatedWithAutoCommit() throws Exception {
- // this test sort of simulates Gremlin Server interaction where a Traversal is eval'd in one Thread, but
- // then iterated in another. note that Gremlin Server configures the script engine to auto-commit
- // after evaluation. this basically tests the state of the Gremlin Server GremlinExecutor when
- // being used in sessionless mode
- final ExecutorService evalExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .afterSuccess(b -> {
- final Graph graph = (Graph) b.get("g");
- if (graph.features().graph().supportsTransactions())
- graph.tx().commit();
- })
- .executorService(evalExecutor).create();
-
- final Map<String,Object> bindings = new HashMap<>();
- bindings.put("g", g);
-
- final AtomicInteger vertexCount = new AtomicInteger(0);
-
- final ExecutorService iterationExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
- gremlinExecutor.eval("g.V().out()", bindings).thenAcceptAsync(o -> {
- final Iterator itty = (Iterator) o;
- itty.forEachRemaining(v -> vertexCount.incrementAndGet());
- }, iterationExecutor).join();
-
- assertEquals(6, vertexCount.get());
-
- gremlinExecutor.close();
- evalExecutor.shutdown();
- evalExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
- iterationExecutor.shutdown();
- iterationExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldAllowTraversalToIterateInDifferentThreadThanOriginallyEvaluatedWithoutAutoCommit() throws Exception {
- // this test sort of simulates Gremlin Server interaction where a Traversal is eval'd in one Thread, but
- // then iterated in another. this basically tests the state of the Gremlin Server GremlinExecutor when
- // being used in session mode
- final ExecutorService evalExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().executorService(evalExecutor).create();
-
- final Map<String,Object> bindings = new HashMap<>();
- bindings.put("g", g);
-
- final AtomicInteger vertexCount = new AtomicInteger(0);
-
- final ExecutorService iterationExecutor = Executors.newSingleThreadExecutor(testingThreadFactory);
- gremlinExecutor.eval("g.V().out()", bindings).thenAcceptAsync(o -> {
- final Iterator itty = (Iterator) o;
- itty.forEachRemaining(v -> vertexCount.incrementAndGet());
- }, iterationExecutor).join();
-
- assertEquals(6, vertexCount.get());
-
- gremlinExecutor.close();
- evalExecutor.shutdown();
- evalExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
- iterationExecutor.shutdown();
- iterationExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
- }
-
- @Test
- public void shouldEvalInMultipleThreads() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
-
- final CyclicBarrier barrier = new CyclicBarrier(2);
- final AtomicInteger i1 = new AtomicInteger(0);
- final AtomicBoolean b1 = new AtomicBoolean(false);
- final Thread t1 = new Thread(() -> {
- try {
- barrier.await();
- i1.set((Integer) gremlinExecutor.eval("1+1").get());
- } catch (Exception ex) {
- b1.set(true);
- }
- });
-
- final AtomicInteger i2 = new AtomicInteger(0);
- final AtomicBoolean b2 = new AtomicBoolean(false);
- final Thread t2 = new Thread(() -> {
- try {
- barrier.await();
- i2.set((Integer) gremlinExecutor.eval("1+1").get());
- } catch (Exception ex) {
- b2.set(true);
- }
- });
-
- t1.start();
- t2.start();
-
- t1.join();
- t2.join();
-
- assertEquals(2, i1.get());
- assertEquals(2, i2.get());
- assertFalse(b1.get());
- assertFalse(b2.get());
-
- gremlinExecutor.close();
-
- }
-
- @Test
- public void shouldNotExhaustThreads() throws Exception {
- final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2, testingThreadFactory);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .executorService(executorService)
- .scheduledExecutorService(executorService).create();
-
- final AtomicInteger count = new AtomicInteger(0);
- assertTrue(IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("1+1")).allMatch(f -> {
- try {
- return (Integer) f.get() == 2;
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- } finally {
- count.incrementAndGet();
- }
- }));
-
- assertEquals(1000, count.intValue());
-
- executorService.shutdown();
- executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);
- }
-
- @Test
- public void shouldFailUntilImportExecutes() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
-
- final Set<String> imports = new HashSet<String>() {{
- add("import java.awt.Color");
- }};
-
- final AtomicInteger successes = new AtomicInteger(0);
- final AtomicInteger failures = new AtomicInteger(0);
-
- // issue 1000 scripts in one thread using a class that isn't imported. this will result in failure.
- // while that thread is running start a new thread that issues an addImports to include that class.
- // this should block further evals in the first thread until the import is complete at which point
- // evals in the first thread will resume and start to succeed
- final Thread t1 = new Thread(() ->
- IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("Color.BLACK"))
- .forEach(f -> {
- f.exceptionally(t -> failures.incrementAndGet()).join();
- if (!f.isCompletedExceptionally())
- successes.incrementAndGet();
- })
- );
-
- final Thread t2 = new Thread(() -> {
- while (failures.get() < 500) {
- }
- gremlinExecutor.getScriptEngines().addImports(imports);
- });
-
- t1.start();
- t2.start();
-
- t1.join();
- t2.join();
-
- assertTrue(successes.intValue() > 0);
- assertTrue(failures.intValue() >= 500);
-
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldInitializeWithScript() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- Collections.emptyMap())
- .create();
-
- assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldSecureAll() throws Exception {
- GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
- final Map<String, Object> config = new HashMap<>();
- config.put("sandbox", GremlinGroovyScriptEngineTest.DenyAll.class.getName());
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- config)
- .create();
- try {
- gremlinExecutor.eval("c = new java.awt.Color(255, 255, 255)").get();
- fail("Should have failed security");
- } catch (Exception se) {
- assertEquals(SecurityException.class, se.getCause().getClass());
- } finally {
- gremlinExecutor.close();
- }
- }
-
- @Test
- public void shouldSecureSome() throws Exception {
- GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
- final Map<String, Object> config = new HashMap<>();
- config.put("sandbox", GremlinGroovyScriptEngineTest.AllowSome.class.getName());
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- config)
- .create();
- try {
- gremlinExecutor.eval("c = 'new java.awt.Color(255, 255, 255)'").get();
- fail("Should have failed security");
- } catch (Exception se) {
- assertEquals(SecurityException.class, se.getCause().getClass());
- }
-
- try {
- final java.awt.Color c = (java.awt.Color) gremlinExecutor.eval("g = new java.awt.Color(255, 255, 255)").get();
- assertEquals(java.awt.Color.class, c.getClass());
- } catch (Exception ignored) {
- fail("Should not have tossed an exception");
- } finally {
- gremlinExecutor.close();
- }
- }
-
- @Test
- public void shouldInitializeWithScriptAndWorkAfterReset() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- Collections.emptyMap())
- .create();
-
- assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-
- gremlinExecutor.getScriptEngines().reset();
-
- assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldNotShutdownExecutorServicesSuppliedToGremlinExecutor() throws Exception {
- final ScheduledExecutorService service = Executors.newScheduledThreadPool(4, testingThreadFactory);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .executorService(service)
- .scheduledExecutorService(service).create();
-
- gremlinExecutor.close();
- assertFalse(service.isShutdown());
- service.shutdown();
- service.awaitTermination(30000, TimeUnit.MILLISECONDS);
- }
-}
[3/3] incubator-tinkerpop git commit: Move unit tests that don't need
a graph from gremlin-groovy-test to gremlin-groovy.
Posted by sp...@apache.org.
Move unit tests that don't need a graph from gremlin-groovy-test to gremlin-groovy.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/26c2b99a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/26c2b99a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/26c2b99a
Branch: refs/heads/master
Commit: 26c2b99a79d54e157bc2dcb2be964b3bedf7347f
Parents: 8153a0a
Author: Stephen Mallette <sp...@apache.org>
Authored: Thu Mar 12 13:18:11 2015 -0400
Committer: Stephen Mallette <sp...@apache.org>
Committed: Thu Mar 12 13:18:11 2015 -0400
----------------------------------------------------------------------
.../gremlin/groovy/GroovyEnvironmentSuite.java | 4 +-
.../engine/GremlinExecutorOverGraphTest.java | 378 +----------
.../GremlinGroovyScriptEngineOverGraphTest.java | 369 +++++++++++
.../jsr223/GremlinGroovyScriptEngineTest.java | 644 -------------------
gremlin-groovy/pom.xml | 18 +
.../groovy/engine/GremlinExecutorTest.java | 396 ++++++++++++
.../jsr223/GremlinGroovyScriptEngineTest.java | 309 +++++++++
.../groovy/engine/GremlinExecutorInit.groovy | 19 +
8 files changed, 1115 insertions(+), 1022 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
index 54ec7ed..2e0a114 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/GroovyEnvironmentSuite.java
@@ -22,7 +22,7 @@ import org.apache.tinkerpop.gremlin.AbstractGremlinSuite;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.GraphManager;
import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutorOverGraphTest;
-import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineTest;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineOverGraphTest;
import org.apache.tinkerpop.gremlin.groovy.loaders.GremlinLoaderTest;
import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoader;
import org.apache.tinkerpop.gremlin.groovy.loaders.SugarLoaderTest;
@@ -41,7 +41,7 @@ import java.util.stream.Stream;
public class GroovyEnvironmentSuite extends AbstractGremlinSuite {
private static final Class<?>[] allTests = new Class<?>[]{
- GremlinGroovyScriptEngineTest.class,
+ GremlinGroovyScriptEngineOverGraphTest.class,
GremlinExecutorOverGraphTest.class,
GremlinLoaderTest.class,
SugarLoaderTest.class,
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
index 99b4c8c..cc6b34f 100644
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorOverGraphTest.java
@@ -18,196 +18,28 @@
*/
package org.apache.tinkerpop.gremlin.groovy.engine;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.TestHelper;
-import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineTest;
import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.junit.Test;
-import org.kohsuke.groovy.sandbox.GroovyInterceptor;
-import javax.script.Bindings;
-import javax.script.CompiledScript;
-import javax.script.SimpleBindings;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
/**
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
public class GremlinExecutorOverGraphTest extends AbstractGremlinTest {
- public static Map<String, String> PATHS = new HashMap<>();
private final BasicThreadFactory testingThreadFactory = new BasicThreadFactory.Builder().namingPattern("test-gremlin-executor-%d").build();
- static {
- try {
- final List<String> groovyScriptResources = Arrays.asList("GremlinExecutorInit.groovy");
- for (final String fileName : groovyScriptResources) {
- PATHS.put(fileName, TestHelper.generateTempFileFromResource(GremlinExecutorOverGraphTest.class, fileName, "").getAbsolutePath());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @Test
- public void shouldEvalScript() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- assertEquals(2, gremlinExecutor.eval("1+1").get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldCompileScript() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- final CompiledScript script = gremlinExecutor.compile("1+1").get();
- assertEquals(2, script.eval());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalMultipleScripts() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- assertEquals(2, gremlinExecutor.eval("1+1").get());
- assertEquals(3, gremlinExecutor.eval("1+2").get());
- assertEquals(4, gremlinExecutor.eval("1+3").get());
- assertEquals(5, gremlinExecutor.eval("1+4").get());
- assertEquals(6, gremlinExecutor.eval("1+5").get());
- assertEquals(7, gremlinExecutor.eval("1+6").get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithBindings() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
- final Bindings b = new SimpleBindings();
- b.put("x", 1);
- assertEquals(2, gremlinExecutor.eval("1+x", b).get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithGlobalBindings() throws Exception {
- final Bindings b = new SimpleBindings();
- b.put("x", 1);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(b).create();
- assertEquals(2, gremlinExecutor.eval("1+x").get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithGlobalAndLocalBindings() throws Exception {
- final Bindings g = new SimpleBindings();
- g.put("x", 1);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
- final Bindings b = new SimpleBindings();
- b.put("y", 1);
- assertEquals(2, gremlinExecutor.eval("y+x", b).get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldEvalScriptWithLocalOverridingGlobalBindings() throws Exception {
- final Bindings g = new SimpleBindings();
- g.put("x", 1);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
- final Bindings b = new SimpleBindings();
- b.put("x", 10);
- assertEquals(11, gremlinExecutor.eval("x+1", b).get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldTimeoutSleepingScript() throws Exception {
- final AtomicBoolean successCalled = new AtomicBoolean(false);
- final AtomicBoolean failureCalled = new AtomicBoolean(false);
-
- final CountDownLatch timeOutCount = new CountDownLatch(1);
-
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .scriptEvaluationTimeout(250)
- .afterFailure((b, e) -> failureCalled.set(true))
- .afterSuccess((b) -> successCalled.set(true))
- .afterTimeout((b) -> timeOutCount.countDown()).create();
- try {
- gremlinExecutor.eval("Thread.sleep(1000);10").get();
- fail("This script should have timed out with an exception");
- } catch (Exception ex) {
- assertEquals(TimeoutException.class, ex.getCause().getClass());
- }
-
- assertTrue(timeOutCount.await(2000, TimeUnit.MILLISECONDS));
-
- assertFalse(successCalled.get());
- assertFalse(failureCalled.get());
- assertEquals(0, timeOutCount.getCount());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldCallFail() throws Exception {
- final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
- final AtomicBoolean successCalled = new AtomicBoolean(false);
- final AtomicBoolean failureCalled = new AtomicBoolean(false);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .afterFailure((b, e) -> failureCalled.set(true))
- .afterSuccess((b) -> successCalled.set(true))
- .afterTimeout((b) -> timeoutCalled.set(true)).create();
- try {
- gremlinExecutor.eval("10/0").get();
- fail();
- } catch (Exception ex) {
-
- }
-
- // need to wait long enough for the script to complete
- Thread.sleep(750);
-
- assertFalse(timeoutCalled.get());
- assertFalse(successCalled.get());
- assertTrue(failureCalled.get());
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldCallSuccess() throws Exception {
- final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
- final AtomicBoolean successCalled = new AtomicBoolean(false);
- final AtomicBoolean failureCalled = new AtomicBoolean(false);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .afterFailure((b, e) -> failureCalled.set(true))
- .afterSuccess((b) -> successCalled.set(true))
- .afterTimeout((b) -> timeoutCalled.set(true)).create();
- assertEquals(2, gremlinExecutor.eval("1+1").get());
-
- // need to wait long enough for the script to complete
- Thread.sleep(750);
-
- assertFalse(timeoutCalled.get());
- assertTrue(successCalled.get());
- assertFalse(failureCalled.get());
- gremlinExecutor.close();
- }
-
@Test
@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
public void shouldAllowTraversalToIterateInDifferentThreadThanOriginallyEvaluatedWithAutoCommit() throws Exception {
@@ -272,210 +104,4 @@ public class GremlinExecutorOverGraphTest extends AbstractGremlinTest {
iterationExecutor.shutdown();
iterationExecutor.awaitTermination(30000, TimeUnit.MILLISECONDS);
}
-
- @Test
- public void shouldEvalInMultipleThreads() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
-
- final CyclicBarrier barrier = new CyclicBarrier(2);
- final AtomicInteger i1 = new AtomicInteger(0);
- final AtomicBoolean b1 = new AtomicBoolean(false);
- final Thread t1 = new Thread(() -> {
- try {
- barrier.await();
- i1.set((Integer) gremlinExecutor.eval("1+1").get());
- } catch (Exception ex) {
- b1.set(true);
- }
- });
-
- final AtomicInteger i2 = new AtomicInteger(0);
- final AtomicBoolean b2 = new AtomicBoolean(false);
- final Thread t2 = new Thread(() -> {
- try {
- barrier.await();
- i2.set((Integer) gremlinExecutor.eval("1+1").get());
- } catch (Exception ex) {
- b2.set(true);
- }
- });
-
- t1.start();
- t2.start();
-
- t1.join();
- t2.join();
-
- assertEquals(2, i1.get());
- assertEquals(2, i2.get());
- assertFalse(b1.get());
- assertFalse(b2.get());
-
- gremlinExecutor.close();
-
- }
-
- @Test
- public void shouldNotExhaustThreads() throws Exception {
- final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2, testingThreadFactory);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .executorService(executorService)
- .scheduledExecutorService(executorService).create();
-
- final AtomicInteger count = new AtomicInteger(0);
- assertTrue(IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("1+1")).allMatch(f -> {
- try {
- return (Integer) f.get() == 2;
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- } finally {
- count.incrementAndGet();
- }
- }));
-
- assertEquals(1000, count.intValue());
-
- executorService.shutdown();
- executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);
- }
-
- @Test
- public void shouldFailUntilImportExecutes() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
-
- final Set<String> imports = new HashSet<String>() {{
- add("import java.awt.Color");
- }};
-
- final AtomicInteger successes = new AtomicInteger(0);
- final AtomicInteger failures = new AtomicInteger(0);
-
- // issue 1000 scripts in one thread using a class that isn't imported. this will result in failure.
- // while that thread is running start a new thread that issues an addImports to include that class.
- // this should block further evals in the first thread until the import is complete at which point
- // evals in the first thread will resume and start to succeed
- final Thread t1 = new Thread(() ->
- IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("Color.BLACK"))
- .forEach(f -> {
- f.exceptionally(t -> failures.incrementAndGet()).join();
- if (!f.isCompletedExceptionally())
- successes.incrementAndGet();
- })
- );
-
- final Thread t2 = new Thread(() -> {
- while (failures.get() < 500) {
- }
- gremlinExecutor.getScriptEngines().addImports(imports);
- });
-
- t1.start();
- t2.start();
-
- t1.join();
- t2.join();
-
- assertTrue(successes.intValue() > 0);
- assertTrue(failures.intValue() >= 500);
-
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldInitializeWithScript() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- Collections.emptyMap())
- .create();
-
- assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldSecureAll() throws Exception {
- GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
- final Map<String, Object> config = new HashMap<>();
- config.put("sandbox", GremlinGroovyScriptEngineTest.DenyAll.class.getName());
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- config)
- .create();
- try {
- gremlinExecutor.eval("c = new java.awt.Color(255, 255, 255)").get();
- fail("Should have failed security");
- } catch (Exception se) {
- assertEquals(SecurityException.class, se.getCause().getClass());
- } finally {
- gremlinExecutor.close();
- }
- }
-
- @Test
- public void shouldSecureSome() throws Exception {
- GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
- final Map<String, Object> config = new HashMap<>();
- config.put("sandbox", GremlinGroovyScriptEngineTest.AllowSome.class.getName());
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- config)
- .create();
- try {
- gremlinExecutor.eval("c = 'new java.awt.Color(255, 255, 255)'").get();
- fail("Should have failed security");
- } catch (Exception se) {
- assertEquals(SecurityException.class, se.getCause().getClass());
- }
-
- try {
- final java.awt.Color c = (java.awt.Color) gremlinExecutor.eval("g = new java.awt.Color(255, 255, 255)").get();
- assertEquals(java.awt.Color.class, c.getClass());
- } catch (Exception ignored) {
- fail("Should not have tossed an exception");
- } finally {
- gremlinExecutor.close();
- }
- }
-
- @Test
- public void shouldInitializeWithScriptAndWorkAfterReset() throws Exception {
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .addEngineSettings("gremlin-groovy",
- Collections.emptyList(),
- Collections.emptyList(),
- Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
- Collections.emptyMap())
- .create();
-
- assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-
- gremlinExecutor.getScriptEngines().reset();
-
- assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-
- gremlinExecutor.close();
- }
-
- @Test
- public void shouldNotShutdownExecutorServicesSuppliedToGremlinExecutor() throws Exception {
- final ScheduledExecutorService service = Executors.newScheduledThreadPool(4, testingThreadFactory);
- final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
- .executorService(service)
- .scheduledExecutorService(service).create();
-
- gremlinExecutor.close();
- assertFalse(service.isShutdown());
- service.shutdown();
- service.awaitTermination(30000, TimeUnit.MILLISECONDS);
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineOverGraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineOverGraphTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineOverGraphTest.java
new file mode 100644
index 0000000..7acdc84
--- /dev/null
+++ b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineOverGraphTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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.groovy.jsr223;
+
+import groovy.lang.MissingPropertyException;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
+import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.SecurityCustomizerProvider;
+import org.apache.tinkerpop.gremlin.process.T;
+import org.apache.tinkerpop.gremlin.process.Traversal;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.util.StreamFactory;
+import org.apache.tinkerpop.gremlin.util.config.YamlConfiguration;
+import groovy.lang.Closure;
+import groovy.lang.Script;
+import org.junit.Assert;
+import org.junit.Test;
+import org.kohsuke.groovy.sandbox.GroovyInterceptor;
+import org.kohsuke.groovy.sandbox.GroovyValueFilter;
+
+import javax.script.Bindings;
+import javax.script.CompiledScript;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinGroovyScriptEngineOverGraphTest extends AbstractGremlinTest {
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldDoSomeGremlin() throws Exception {
+ final ScriptEngine engine = new GremlinGroovyScriptEngine();
+ final List list = new ArrayList();
+ engine.put("g", g);
+ engine.put("temp", list);
+ assertEquals(list.size(), 0);
+ engine.eval("g.V(" + convertToVertexId("marko") +").out().fill(temp)");
+ assertEquals(list.size(), 3);
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldLoadImports() throws Exception {
+ final ScriptEngine engineNoImports = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
+ try {
+ engineNoImports.eval("Vertex.class.getName()");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ final ScriptEngine engineWithImports = new GremlinGroovyScriptEngine(new DefaultImportCustomizerProvider());
+ engineWithImports.put("g", g);
+ assertEquals(Vertex.class.getName(), engineWithImports.eval("Vertex.class.getName()"));
+ assertEquals(2l, engineWithImports.eval("g.V().has('age',Compare.gt,30).count().next()"));
+ assertEquals(Direction.IN, engineWithImports.eval("Direction.IN"));
+ assertEquals(Direction.OUT, engineWithImports.eval("Direction.OUT"));
+ assertEquals(Direction.BOTH, engineWithImports.eval("Direction.BOTH"));
+ }
+
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldLoadStandardImportsAndThenAddToThem() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new DefaultImportCustomizerProvider());
+ engine.put("g", g);
+ assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
+ assertEquals(2l, engine.eval("g.V().has('age',Compare.gt,30).count().next()"));
+ assertEquals(Direction.IN, engine.eval("Direction.IN"));
+ assertEquals(Direction.OUT, engine.eval("Direction.OUT"));
+ assertEquals(Direction.BOTH, engine.eval("Direction.BOTH"));
+
+ try {
+ engine.eval("YamlConfiguration.class.getName()");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ engine.addImports(new HashSet<>(Arrays.asList("import " + YamlConfiguration.class.getCanonicalName())));
+ engine.put("g", g);
+ assertEquals(YamlConfiguration.class.getName(), engine.eval("YamlConfiguration.class.getName()"));
+ assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
+ assertEquals(2l, engine.eval("g.V().has('age',Compare.gt,30).count().next()"));
+ assertEquals(Direction.IN, engine.eval("Direction.IN"));
+ assertEquals(Direction.OUT, engine.eval("Direction.OUT"));
+ assertEquals(Direction.BOTH, engine.eval("Direction.BOTH"));
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
+ public void shouldProperlyHandleBindings() throws Exception {
+ final ScriptEngine engine = new GremlinGroovyScriptEngine();
+ engine.put("g", g);
+ Assert.assertEquals(g.V(convertToVertexId("marko")).next(), engine.eval("g.V(" + convertToVertexId("marko") + ").next()"));
+
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+ bindings.put("s", "marko");
+ bindings.put("f", 0.5f);
+ bindings.put("i", 1);
+ bindings.put("b", true);
+ bindings.put("l", 100l);
+ bindings.put("d", 1.55555d);
+
+ assertEquals(engine.eval("g.E().has('weight',f).next()", bindings), g.E(convertToEdgeId("marko", "knows", "vadas")).next());
+ assertEquals(engine.eval("g.V().has('name',s).next()", bindings), g.V(convertToVertexId("marko")).next());
+ assertEquals(engine.eval("g.V().sideEffect{it.get().property('bbb',it.get().value('name')=='marko')}.iterate();g.V().has('bbb',b).next()", bindings), g.V(convertToVertexId("marko")).next());
+ assertEquals(engine.eval("g.V().sideEffect{it.get().property('iii',it.get().value('name')=='marko'?1:0)}.iterate();g.V().has('iii',i).next()", bindings), g.V(convertToVertexId("marko")).next());
+ assertEquals(engine.eval("g.V().sideEffect{it.get().property('lll',it.get().value('name')=='marko'?100l:0l)}.iterate();g.V().has('lll',l).next()", bindings), g.V(convertToVertexId("marko")).next());
+ assertEquals(engine.eval("g.V().sideEffect{it.get().property('ddd',it.get().value('name')=='marko'?1.55555d:0)}.iterate();g.V().has('ddd',d).next()", bindings), g.V(convertToVertexId("marko")).next());
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldClearBindingsBetweenEvals() throws Exception {
+ final ScriptEngine engine = new GremlinGroovyScriptEngine();
+ engine.put("g", g);
+ Assert.assertEquals(g.V(convertToVertexId("marko")).next(), engine.eval("g.V(" + convertToVertexId("marko") + ").next()"));
+
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+ bindings.put("s", "marko");
+
+ assertEquals(engine.eval("g.V().has('name',s).next()", bindings), g.V(convertToVertexId("marko")).next());
+
+ try {
+ engine.eval("g.V().has('name',s).next()");
+ fail("This should have failed because s is no longer bound");
+ } catch (Exception ex) {
+ final Throwable t = ExceptionUtils.getRootCause(ex);
+ assertEquals(MissingPropertyException.class, t.getClass());
+ assertTrue(t.getMessage().startsWith("No such property: s for class"));
+ }
+
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldBeThreadSafe() throws Exception {
+ final ScriptEngine engine = new GremlinGroovyScriptEngine();
+
+ int runs = 500;
+ final CountDownLatch latch = new CountDownLatch(runs);
+ final List<String> names = Arrays.asList("marko", "peter", "josh", "vadas", "stephen", "pavel", "matthias");
+ final Random random = new Random();
+
+ for (int i = 0; i < runs; i++) {
+ new Thread("test-thread-safe-" + i) {
+ public void run() {
+ String name = names.get(random.nextInt(names.size() - 1));
+ try {
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+ bindings.put("name", name);
+ final Object result = engine.eval("t = g.V().has('name',name); if(t.hasNext()) { t } else { null }", bindings);
+ if (name.equals("stephen") || name.equals("pavel") || name.equals("matthias"))
+ assertNull(result);
+ else
+ assertNotNull(result);
+ } catch (ScriptException e) {
+ assertFalse(true);
+ }
+ latch.countDown();
+ }
+ }.start();
+ }
+ latch.await();
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldBeThreadSafeOnCompiledScript() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+ final CompiledScript script = engine.compile("t = g.V().has('name',name); if(t.hasNext()) { t } else { null }");
+
+ int runs = 500;
+ final CountDownLatch latch = new CountDownLatch(runs);
+ final List<String> names = Arrays.asList("marko", "peter", "josh", "vadas", "stephen", "pavel", "matthias");
+ final Random random = new Random();
+
+ for (int i = 0; i < runs; i++) {
+ new Thread("test-thread-safety-on-compiled-script-" + i) {
+ public void run() {
+ String name = names.get(random.nextInt(names.size() - 1));
+ try {
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+ bindings.put("name", name);
+ Object result = script.eval(bindings);
+ if (name.equals("stephen") || name.equals("pavel") || name.equals("matthias"))
+ assertNull(result);
+ else
+ assertNotNull(result);
+ } catch (ScriptException e) {
+ //System.out.println(e);
+ assertFalse(true);
+ }
+ latch.countDown();
+ }
+ }.start();
+ }
+ latch.await();
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldEvalGlobalClosuresEvenAfterEvictionOfClass() throws ScriptException {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+
+ // strong referenced global closure
+ engine.eval("def isVadas(v){v.value('name')=='vadas'}", bindings);
+ assertEquals(true, engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
+
+ // phantom referenced global closure
+ bindings.put(GremlinGroovyScriptEngine.KEY_REFERENCE_TYPE, GremlinGroovyScriptEngine.REFERENCE_TYPE_PHANTOM);
+ engine.eval("def isMarko(v){v.value('name')=='marko'}", bindings);
+
+ try {
+ engine.eval("isMarko(g.V(" + convertToVertexId("marko") + ").next())", bindings);
+ fail("the isMarko function should not be present");
+ } catch (Exception ex) {
+
+ }
+
+ assertEquals(true, engine.eval("def isMarko(v){v.value('name')=='marko'}; isMarko(g.V(1).next())", bindings));
+
+ try {
+ engine.eval("isMarko(g.V(" + convertToVertexId("marko") + ").next())", bindings);
+ fail("the isMarko function should not be present");
+ } catch (Exception ex) {
+
+ }
+
+ bindings.remove(GremlinGroovyScriptEngine.KEY_REFERENCE_TYPE);
+
+ // isVadas class was a hard reference so it should still be hanging about
+ assertEquals(true, engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
+ }
+
+ @Test
+ @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+ public void shouldAllowFunctionsUsedInClosure() throws ScriptException {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+ bindings.put("#jsr223.groovy.engine.keep.globals", "phantom");
+
+ // this works on its own when the function and the line that uses it is in one "script". this is the
+ // current workaround
+ assertEquals(g.V(convertToVertexId("vadas")).next(), engine.eval("def isVadas(v){v.value('name')=='vadas'};g.V().filter{isVadas(it.get())}.next()", bindings));
+
+ // let's reset this piece and make sure isVadas is not hanging around.
+ engine.reset();
+
+ // validate that isVadas throws an exception since it is not defined
+ try {
+ engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings);
+
+ // fail the test if the above doesn't throw an exception
+ fail();
+ } catch (Exception ex) {
+ // this is good...we want this. it means isVadas isn't hanging about
+ }
+
+ // now...define the function separately on its own in one script
+ bindings.remove("#jsr223.groovy.engine.keep.globals");
+ engine.eval("def isVadas(v){v.value('name')=='vadas'}", bindings);
+
+ // make sure the function works on its own...no problem
+ assertEquals(true, engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
+
+ // make sure the function works in a closure...this generates a StackOverflowError
+ assertEquals(g.V(convertToVertexId("vadas")).next(), engine.eval("g.V().filter{isVadas(it.get())}.next()", bindings));
+ }
+
+ @Test
+ @org.junit.Ignore
+ @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
+ public void shouldAllowUseOfClasses() throws ScriptException {
+ GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+
+ final Bindings bindings = engine.createBindings();
+ bindings.put("g", g);
+
+ // works when it's all defined together
+ assertEquals(true, engine.eval("class c { static def isVadas(v){v.value('name')=='vadas'}};c.isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
+
+ // let's reset this piece and make sure isVadas is not hanging around.
+ engine.reset();
+
+ // validate that isVadas throws an exception since it is not defined
+ try {
+ engine.eval("c.isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings);
+
+ // fail the test if the above doesn't throw an exception
+ fail("Function should be gone");
+ } catch (Exception ex) {
+ // this is good...we want this. it means isVadas isn't hanging about
+ }
+
+ // now...define the class separately on its own in one script...
+ // HERE'S an AWKWARD BIT.........
+ // YOU HAVE TO END WITH: null;
+ // ....OR ELSE YOU GET:
+ // javax.script.ScriptException: javax.script.ScriptException:
+ // org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack: No signature of method: c.main()
+ // is applicable for argument types: ([Ljava.lang.String;) values: [[]]
+ // WOULD BE NICE IF WE DIDN'T HAVE TO DO THAT
+ engine.eval("class c { static def isVadas(v){v.name=='vadas'}};null;", bindings);
+
+ // make sure the class works on its own...this generates: groovy.lang.MissingPropertyException: No such property: c for class: Script2
+ assertEquals(true, engine.eval("c.isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldProcessUTF8Query() throws Exception {
+ final Vertex nonUtf8 = graph.addVertex(T.id, "1", "name", "marko", "age", 29);
+ final Vertex utf8Name = graph.addVertex(T.id, "2", "name", "轉注", "age", 32);
+
+ final ScriptEngine engine = new GremlinGroovyScriptEngine();
+
+ engine.put("g", g);
+ Traversal eval = (Traversal) engine.eval("g.V().has('name', 'marko')");
+ assertEquals(nonUtf8, eval.next());
+ eval = (Traversal) engine.eval("g.V().has('name','轉注')");
+ assertEquals(utf8Name, eval.next());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
deleted file mode 100644
index fdc0899..0000000
--- a/gremlin-groovy-test/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * 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.groovy.jsr223;
-
-import groovy.lang.MissingPropertyException;
-import org.apache.commons.lang.exception.ExceptionUtils;
-import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
-import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
-import org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
-import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
-import org.apache.tinkerpop.gremlin.groovy.SecurityCustomizerProvider;
-import org.apache.tinkerpop.gremlin.process.T;
-import org.apache.tinkerpop.gremlin.process.Traversal;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.util.StreamFactory;
-import org.apache.tinkerpop.gremlin.util.config.YamlConfiguration;
-import groovy.lang.Closure;
-import groovy.lang.Script;
-import org.junit.Assert;
-import org.junit.Test;
-import org.kohsuke.groovy.sandbox.GroovyInterceptor;
-import org.kohsuke.groovy.sandbox.GroovyValueFilter;
-
-import javax.script.Bindings;
-import javax.script.CompiledScript;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static org.junit.Assert.*;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-public class GremlinGroovyScriptEngineTest extends AbstractGremlinTest {
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldDoSomeGremlin() throws Exception {
- final ScriptEngine engine = new GremlinGroovyScriptEngine();
- final List list = new ArrayList();
- engine.put("g", g);
- engine.put("temp", list);
- assertEquals(list.size(), 0);
- engine.eval("g.V(" + convertToVertexId("marko") +").out().fill(temp)");
- assertEquals(list.size(), 3);
- }
-
- @Test
- public void shouldCompileScriptWithoutRequiringVariableBindings() throws Exception {
- // compile() should cache the script to avoid future compilation
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
-
- final String script = "g.V(x).out()";
- assertFalse(engine.isCached(script));
- assertNotNull(engine.compile(script));
- assertTrue(engine.isCached(script));
-
- engine.reset();
-
- assertFalse(engine.isCached(script));
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldLoadImports() throws Exception {
- final ScriptEngine engineNoImports = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
- try {
- engineNoImports.eval("Vertex.class.getName()");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- final ScriptEngine engineWithImports = new GremlinGroovyScriptEngine(new DefaultImportCustomizerProvider());
- engineWithImports.put("g", g);
- assertEquals(Vertex.class.getName(), engineWithImports.eval("Vertex.class.getName()"));
- assertEquals(2l, engineWithImports.eval("g.V().has('age',Compare.gt,30).count().next()"));
- assertEquals(Direction.IN, engineWithImports.eval("Direction.IN"));
- assertEquals(Direction.OUT, engineWithImports.eval("Direction.OUT"));
- assertEquals(Direction.BOTH, engineWithImports.eval("Direction.BOTH"));
- }
-
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldLoadStandardImportsAndThenAddToThem() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new DefaultImportCustomizerProvider());
- engine.put("g", g);
- assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
- assertEquals(2l, engine.eval("g.V().has('age',Compare.gt,30).count().next()"));
- assertEquals(Direction.IN, engine.eval("Direction.IN"));
- assertEquals(Direction.OUT, engine.eval("Direction.OUT"));
- assertEquals(Direction.BOTH, engine.eval("Direction.BOTH"));
-
- try {
- engine.eval("YamlConfiguration.class.getName()");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- engine.addImports(new HashSet<>(Arrays.asList("import " + YamlConfiguration.class.getCanonicalName())));
- engine.put("g", g);
- assertEquals(YamlConfiguration.class.getName(), engine.eval("YamlConfiguration.class.getName()"));
- assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
- assertEquals(2l, engine.eval("g.V().has('age',Compare.gt,30).count().next()"));
- assertEquals(Direction.IN, engine.eval("Direction.IN"));
- assertEquals(Direction.OUT, engine.eval("Direction.OUT"));
- assertEquals(Direction.BOTH, engine.eval("Direction.BOTH"));
- }
-
- @Test
- public void shouldLoadImportsViaDependencyManagerInterface() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
- try {
- engine.eval("Vertex.class.getName()");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- engine.addImports(new HashSet<>(Arrays.asList("import org.apache.tinkerpop.gremlin.structure.Vertex")));
- assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
- }
-
- @Test
- public void shouldLoadImportsViaDependencyManagerInterfaceAdditively() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
- try {
- engine.eval("Vertex.class.getName()");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- try {
- engine.eval("StreamFactory.class.getName()");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- engine.addImports(new HashSet<>(Arrays.asList("import " + Vertex.class.getCanonicalName())));
- assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
-
- try {
- engine.eval("StreamFactory.class.getName()");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- engine.addImports(new HashSet<>(Arrays.asList("import " + StreamFactory.class.getCanonicalName())));
- assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
- assertEquals(StreamFactory.class.getName(), engine.eval("StreamFactory.class.getName()"));
- }
-
- @Test
- public void shouldLoadImportsViaDependencyManagerFromDependencyGatheredByUse() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
- try {
- engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- engine.addImports(new HashSet<>(Arrays.asList("import org.apache.commons.math3.util.FastMath")));
- engine.use("org.apache.commons", "commons-math3", "3.2");
- assertEquals(1235, engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)"));
- }
-
- @Test
- public void shouldAllowsUseToBeExecutedAfterImport() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
- try {
- engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)");
- fail("Should have thrown an exception because no imports were supplied");
- } catch (Exception se) {
- assertTrue(se instanceof ScriptException);
- }
-
- engine.use("org.apache.commons", "commons-math3", "3.2");
- engine.addImports(new HashSet<>(Arrays.asList("import org.apache.commons.math3.util.FastMath")));
- assertEquals(1235, engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)"));
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
- public void shouldProperlyHandleBindings() throws Exception {
- final ScriptEngine engine = new GremlinGroovyScriptEngine();
- engine.put("g", g);
- Assert.assertEquals(g.V(convertToVertexId("marko")).next(), engine.eval("g.V(" + convertToVertexId("marko") + ").next()"));
-
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
- bindings.put("s", "marko");
- bindings.put("f", 0.5f);
- bindings.put("i", 1);
- bindings.put("b", true);
- bindings.put("l", 100l);
- bindings.put("d", 1.55555d);
-
- assertEquals(engine.eval("g.E().has('weight',f).next()", bindings), g.E(convertToEdgeId("marko", "knows", "vadas")).next());
- assertEquals(engine.eval("g.V().has('name',s).next()", bindings), g.V(convertToVertexId("marko")).next());
- assertEquals(engine.eval("g.V().sideEffect{it.get().property('bbb',it.get().value('name')=='marko')}.iterate();g.V().has('bbb',b).next()", bindings), g.V(convertToVertexId("marko")).next());
- assertEquals(engine.eval("g.V().sideEffect{it.get().property('iii',it.get().value('name')=='marko'?1:0)}.iterate();g.V().has('iii',i).next()", bindings), g.V(convertToVertexId("marko")).next());
- assertEquals(engine.eval("g.V().sideEffect{it.get().property('lll',it.get().value('name')=='marko'?100l:0l)}.iterate();g.V().has('lll',l).next()", bindings), g.V(convertToVertexId("marko")).next());
- assertEquals(engine.eval("g.V().sideEffect{it.get().property('ddd',it.get().value('name')=='marko'?1.55555d:0)}.iterate();g.V().has('ddd',d).next()", bindings), g.V(convertToVertexId("marko")).next());
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldClearBindingsBetweenEvals() throws Exception {
- final ScriptEngine engine = new GremlinGroovyScriptEngine();
- engine.put("g", g);
- Assert.assertEquals(g.V(convertToVertexId("marko")).next(), engine.eval("g.V(" + convertToVertexId("marko") + ").next()"));
-
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
- bindings.put("s", "marko");
-
- assertEquals(engine.eval("g.V().has('name',s).next()", bindings), g.V(convertToVertexId("marko")).next());
-
- try {
- engine.eval("g.V().has('name',s).next()");
- fail("This should have failed because s is no longer bound");
- } catch (Exception ex) {
- final Throwable t = ExceptionUtils.getRootCause(ex);
- assertEquals(MissingPropertyException.class, t.getClass());
- assertTrue(t.getMessage().startsWith("No such property: s for class"));
- }
-
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldBeThreadSafe() throws Exception {
- final ScriptEngine engine = new GremlinGroovyScriptEngine();
-
- int runs = 500;
- final CountDownLatch latch = new CountDownLatch(runs);
- final List<String> names = Arrays.asList("marko", "peter", "josh", "vadas", "stephen", "pavel", "matthias");
- final Random random = new Random();
-
- for (int i = 0; i < runs; i++) {
- new Thread("test-thread-safe-" + i) {
- public void run() {
- String name = names.get(random.nextInt(names.size() - 1));
- try {
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
- bindings.put("name", name);
- final Object result = engine.eval("t = g.V().has('name',name); if(t.hasNext()) { t } else { null }", bindings);
- if (name.equals("stephen") || name.equals("pavel") || name.equals("matthias"))
- assertNull(result);
- else
- assertNotNull(result);
- } catch (ScriptException e) {
- assertFalse(true);
- }
- latch.countDown();
- }
- }.start();
- }
- latch.await();
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldBeThreadSafeOnCompiledScript() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
- final CompiledScript script = engine.compile("t = g.V().has('name',name); if(t.hasNext()) { t } else { null }");
-
- int runs = 500;
- final CountDownLatch latch = new CountDownLatch(runs);
- final List<String> names = Arrays.asList("marko", "peter", "josh", "vadas", "stephen", "pavel", "matthias");
- final Random random = new Random();
-
- for (int i = 0; i < runs; i++) {
- new Thread("test-thread-safety-on-compiled-script-" + i) {
- public void run() {
- String name = names.get(random.nextInt(names.size() - 1));
- try {
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
- bindings.put("name", name);
- Object result = script.eval(bindings);
- if (name.equals("stephen") || name.equals("pavel") || name.equals("matthias"))
- assertNull(result);
- else
- assertNotNull(result);
- } catch (ScriptException e) {
- //System.out.println(e);
- assertFalse(true);
- }
- latch.countDown();
- }
- }.start();
- }
- latch.await();
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldEvalGlobalClosuresEvenAfterEvictionOfClass() throws ScriptException {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
-
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
-
- // strong referenced global closure
- engine.eval("def isVadas(v){v.value('name')=='vadas'}", bindings);
- assertEquals(true, engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
-
- // phantom referenced global closure
- bindings.put(GremlinGroovyScriptEngine.KEY_REFERENCE_TYPE, GremlinGroovyScriptEngine.REFERENCE_TYPE_PHANTOM);
- engine.eval("def isMarko(v){v.value('name')=='marko'}", bindings);
-
- try {
- engine.eval("isMarko(g.V(" + convertToVertexId("marko") + ").next())", bindings);
- fail("the isMarko function should not be present");
- } catch (Exception ex) {
-
- }
-
- assertEquals(true, engine.eval("def isMarko(v){v.value('name')=='marko'}; isMarko(g.V(1).next())", bindings));
-
- try {
- engine.eval("isMarko(g.V(" + convertToVertexId("marko") + ").next())", bindings);
- fail("the isMarko function should not be present");
- } catch (Exception ex) {
-
- }
-
- bindings.remove(GremlinGroovyScriptEngine.KEY_REFERENCE_TYPE);
-
- // isVadas class was a hard reference so it should still be hanging about
- assertEquals(true, engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
- }
-
- @Test
- @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
- public void shouldAllowFunctionsUsedInClosure() throws ScriptException {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
-
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
- bindings.put("#jsr223.groovy.engine.keep.globals", "phantom");
-
- // this works on its own when the function and the line that uses it is in one "script". this is the
- // current workaround
- assertEquals(g.V(convertToVertexId("vadas")).next(), engine.eval("def isVadas(v){v.value('name')=='vadas'};g.V().filter{isVadas(it.get())}.next()", bindings));
-
- // let's reset this piece and make sure isVadas is not hanging around.
- engine.reset();
-
- // validate that isVadas throws an exception since it is not defined
- try {
- engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings);
-
- // fail the test if the above doesn't throw an exception
- fail();
- } catch (Exception ex) {
- // this is good...we want this. it means isVadas isn't hanging about
- }
-
- // now...define the function separately on its own in one script
- bindings.remove("#jsr223.groovy.engine.keep.globals");
- engine.eval("def isVadas(v){v.value('name')=='vadas'}", bindings);
-
- // make sure the function works on its own...no problem
- assertEquals(true, engine.eval("isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
-
- // make sure the function works in a closure...this generates a StackOverflowError
- assertEquals(g.V(convertToVertexId("vadas")).next(), engine.eval("g.V().filter{isVadas(it.get())}.next()", bindings));
- }
-
- @Test
- @org.junit.Ignore
- @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
- public void shouldAllowUseOfClasses() throws ScriptException {
- GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
-
- final Bindings bindings = engine.createBindings();
- bindings.put("g", g);
-
- // works when it's all defined together
- assertEquals(true, engine.eval("class c { static def isVadas(v){v.value('name')=='vadas'}};c.isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
-
- // let's reset this piece and make sure isVadas is not hanging around.
- engine.reset();
-
- // validate that isVadas throws an exception since it is not defined
- try {
- engine.eval("c.isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings);
-
- // fail the test if the above doesn't throw an exception
- fail("Function should be gone");
- } catch (Exception ex) {
- // this is good...we want this. it means isVadas isn't hanging about
- }
-
- // now...define the class separately on its own in one script...
- // HERE'S an AWKWARD BIT.........
- // YOU HAVE TO END WITH: null;
- // ....OR ELSE YOU GET:
- // javax.script.ScriptException: javax.script.ScriptException:
- // org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack: No signature of method: c.main()
- // is applicable for argument types: ([Ljava.lang.String;) values: [[]]
- // WOULD BE NICE IF WE DIDN'T HAVE TO DO THAT
- engine.eval("class c { static def isVadas(v){v.name=='vadas'}};null;", bindings);
-
- // make sure the class works on its own...this generates: groovy.lang.MissingPropertyException: No such property: c for class: Script2
- assertEquals(true, engine.eval("c.isVadas(g.V(" + convertToVertexId("vadas") + ").next())", bindings));
- }
-
- @Test
- public void shouldClearEngineScopeOnReset() throws Exception {
- final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
- engine.eval("x = { y -> y + 1}");
- Bindings b = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
- assertTrue(b.containsKey("x"));
- assertEquals(2, ((Closure) b.get("x")).call(1));
-
- // should clear the bindings
- engine.reset();
- try {
- engine.eval("x(1)");
- fail("Bindings should have been cleared.");
- } catch (Exception ex) {
-
- }
-
- b = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
- assertFalse(b.containsKey("x"));
-
- // redefine x
- engine.eval("x = { y -> y + 2}");
- assertEquals(3, engine.eval("x(1)"));
- b = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
- assertTrue(b.containsKey("x"));
- assertEquals(3, ((Closure) b.get("x")).call(1));
- }
-
- @Test
- public void shouldReloadClassLoaderWhileDoingEvalInSeparateThread() throws Exception {
- final AtomicBoolean fail = new AtomicBoolean(false);
- final CountDownLatch latch = new CountDownLatch(1);
- final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine();
- final Thread t = new Thread(() -> {
- try {
- final Object o = scriptEngine.eval("Color.BLACK");
- System.out.println("Should not print: " + o);
- fail.set(true);
- } catch (ScriptException se) {
- // should get here as Color.BLACK is not imported yet.
- System.out.println("Failed to execute Color.BLACK as expected.");
- }
-
- try {
- int counter = 0;
- while (latch.getCount() == 1) {
- scriptEngine.eval("1+1");
- counter++;
- }
-
- System.out.println(counter + " executions.");
-
- scriptEngine.eval("Color.BLACK");
- System.out.println("Color.BLACK now evaluates");
- } catch (Exception se) {
- se.printStackTrace();
- fail.set(true);
- }
- }, "test-reload-classloader-1");
-
- t.start();
-
- // let the first thead execute a bit.
- Thread.sleep(1000);
-
- new Thread(() -> {
- System.out.println("Importing java.awt.Color...");
- final Set<String> imports = new HashSet<String>() {{
- add("import java.awt.Color");
- }};
- scriptEngine.addImports(imports);
- latch.countDown();
- }, "test-reload-classloader-2").start();
-
- t.join();
-
- assertFalse(fail.get());
- }
-
- @Test
- public void shouldResetClassLoader() throws Exception {
- final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine();
- try {
- scriptEngine.eval("addOne(1)");
- fail("Should have tossed ScriptException since addOne is not yet defined.");
- } catch (ScriptException se) {
- }
-
- // validate that the addOne function works
- scriptEngine.eval("addOne = { y-> y + 1}");
- assertEquals(2, scriptEngine.eval("addOne(1)"));
-
- // reset the script engine which should blow out the addOne function that's there.
- scriptEngine.reset();
-
- try {
- scriptEngine.eval("addOne(1)");
- fail("Should have tossed ScriptException since addOne is no longer defined after reset.");
- } catch (ScriptException se) {
- }
- }
-
- @Test
- public void shouldSecureAll() throws Exception {
- GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
- final SecurityCustomizerProvider provider = new SecurityCustomizerProvider(new DenyAll());
- final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine(
- new DefaultImportCustomizerProvider(), provider);
- try {
- scriptEngine.eval("g = new java.awt.Color(255, 255, 255)");
- fail("Should have failed security");
- } catch (ScriptException se) {
- assertEquals(SecurityException.class, se.getCause().getCause().getClass());
- } finally {
- provider.unregisterInterceptors();
- }
- }
-
- @Test
- public void shouldSecureSome() throws Exception {
- GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
- final SecurityCustomizerProvider provider = new SecurityCustomizerProvider(new AllowSome());
- final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine(
- new DefaultImportCustomizerProvider(), provider);
- try {
- scriptEngine.eval("g = 'new java.awt.Color(255, 255, 255)'");
- fail("Should have failed security");
- } catch (ScriptException se) {
- assertEquals(SecurityException.class, se.getCause().getCause().getClass());
- }
-
- try {
- assertNotNull(g);
- final java.awt.Color c = (java.awt.Color) scriptEngine.eval("c = new java.awt.Color(255, 255, 255)");
- assertEquals(java.awt.Color.class, c.getClass());
- } catch (Exception ex) {
- fail("Should not have tossed an exception");
- } finally {
- provider.unregisterInterceptors();
- }
- }
-
- @Test
- public void shouldProcessScriptWithUTF8Characters() throws Exception {
- final ScriptEngine engine = new GremlinGroovyScriptEngine();
- assertEquals("轉注", engine.eval("'轉注'"));
- }
-
- @Test
- @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
- public void shouldProcessUTF8Query() throws Exception {
- final Vertex nonUtf8 = graph.addVertex(T.id, "1", "name", "marko", "age", 29);
- final Vertex utf8Name = graph.addVertex(T.id, "2", "name", "轉注", "age", 32);
-
- final ScriptEngine engine = new GremlinGroovyScriptEngine();
-
- engine.put("g", g);
- Traversal eval = (Traversal) engine.eval("g.V().has('name', 'marko')");
- assertEquals(nonUtf8, eval.next());
- eval = (Traversal) engine.eval("g.V().has('name','轉注')");
- assertEquals(utf8Name, eval.next());
- }
-
- @Test
- public void shouldTimeoutScriptOnTimedWhile() throws Exception {
- final ScriptEngine engine = new GremlinGroovyScriptEngine(new DefaultImportCustomizerProvider(), null, 3000);
- try {
- engine.eval("s = System.currentTimeMillis();\nwhile((System.currentTimeMillis() - s) < 10000) {}");
- fail("This should have timed out");
- } catch (ScriptException se) {
- assertEquals(TimeoutException.class, se.getCause().getCause().getClass());
- }
- }
-
- public static class DenyAll extends GroovyValueFilter {
- @Override
- public Object filter(final Object o) {
- throw new SecurityException("Denied!");
- }
- }
-
- public static class AllowSome extends GroovyValueFilter {
-
- public static final Set<Class> ALLOWED_TYPES = new HashSet<Class>() {{
- add(java.awt.Color.class);
- add(Integer.class);
- add(Class.class);
- }};
-
- @Override
- public Object filter(final Object o) {
- if (null == o || ALLOWED_TYPES.contains(o.getClass()))
- return o;
- if (o instanceof Script || o instanceof Closure)
- return o; // access to properties of compiled groovy script
- throw new SecurityException("Unexpected type: " + o.getClass());
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-groovy/pom.xml b/gremlin-groovy/pom.xml
index 73f7545..d1121b1 100644
--- a/gremlin-groovy/pom.xml
+++ b/gremlin-groovy/pom.xml
@@ -68,6 +68,12 @@ limitations under the License.
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.tinkerpop</groupId>
+ <artifactId>gremlin-test</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<repositories>
<repository>
@@ -78,6 +84,18 @@ limitations under the License.
<build>
<directory>${basedir}/target</directory>
<finalName>${project.artifactId}-${project.version}</finalName>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/main/resources
+ </directory>
+ </resource>
+ </resources>
+ <testResources>
+ <testResource>
+ <directory>${basedir}/src/test/resources
+ </directory>
+ </testResource>
+ </testResources>
<plugins>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
new file mode 100644
index 0000000..e05a550
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
@@ -0,0 +1,396 @@
+package org.apache.tinkerpop.gremlin.groovy.engine;
+
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.tinkerpop.gremlin.TestHelper;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineTest;
+import org.junit.Test;
+import org.kohsuke.groovy.sandbox.GroovyInterceptor;
+
+import javax.script.Bindings;
+import javax.script.CompiledScript;
+import javax.script.SimpleBindings;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.IntStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinExecutorTest {
+ public static Map<String, String> PATHS = new HashMap<>();
+ private final BasicThreadFactory testingThreadFactory = new BasicThreadFactory.Builder().namingPattern("test-gremlin-executor-%d").build();
+
+ static {
+ try {
+ final List<String> groovyScriptResources = Arrays.asList("GremlinExecutorInit.groovy");
+ for (final String fileName : groovyScriptResources) {
+ PATHS.put(fileName, TestHelper.generateTempFileFromResource(GremlinExecutorTest.class, fileName, "").getAbsolutePath());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void shouldEvalScript() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ assertEquals(2, gremlinExecutor.eval("1+1").get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldCompileScript() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ final CompiledScript script = gremlinExecutor.compile("1+1").get();
+ assertEquals(2, script.eval());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalMultipleScripts() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ assertEquals(2, gremlinExecutor.eval("1+1").get());
+ assertEquals(3, gremlinExecutor.eval("1+2").get());
+ assertEquals(4, gremlinExecutor.eval("1+3").get());
+ assertEquals(5, gremlinExecutor.eval("1+4").get());
+ assertEquals(6, gremlinExecutor.eval("1+5").get());
+ assertEquals(7, gremlinExecutor.eval("1+6").get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithBindings() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+ final Bindings b = new SimpleBindings();
+ b.put("x", 1);
+ assertEquals(2, gremlinExecutor.eval("1+x", b).get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithGlobalBindings() throws Exception {
+ final Bindings b = new SimpleBindings();
+ b.put("x", 1);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(b).create();
+ assertEquals(2, gremlinExecutor.eval("1+x").get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithGlobalAndLocalBindings() throws Exception {
+ final Bindings g = new SimpleBindings();
+ g.put("x", 1);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
+ final Bindings b = new SimpleBindings();
+ b.put("y", 1);
+ assertEquals(2, gremlinExecutor.eval("y+x", b).get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalScriptWithLocalOverridingGlobalBindings() throws Exception {
+ final Bindings g = new SimpleBindings();
+ g.put("x", 1);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(g).create();
+ final Bindings b = new SimpleBindings();
+ b.put("x", 10);
+ assertEquals(11, gremlinExecutor.eval("x+1", b).get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldTimeoutSleepingScript() throws Exception {
+ final AtomicBoolean successCalled = new AtomicBoolean(false);
+ final AtomicBoolean failureCalled = new AtomicBoolean(false);
+
+ final CountDownLatch timeOutCount = new CountDownLatch(1);
+
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .scriptEvaluationTimeout(250)
+ .afterFailure((b, e) -> failureCalled.set(true))
+ .afterSuccess((b) -> successCalled.set(true))
+ .afterTimeout((b) -> timeOutCount.countDown()).create();
+ try {
+ gremlinExecutor.eval("Thread.sleep(1000);10").get();
+ fail("This script should have timed out with an exception");
+ } catch (Exception ex) {
+ assertEquals(TimeoutException.class, ex.getCause().getClass());
+ }
+
+ assertTrue(timeOutCount.await(2000, TimeUnit.MILLISECONDS));
+
+ assertFalse(successCalled.get());
+ assertFalse(failureCalled.get());
+ assertEquals(0, timeOutCount.getCount());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldCallFail() throws Exception {
+ final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
+ final AtomicBoolean successCalled = new AtomicBoolean(false);
+ final AtomicBoolean failureCalled = new AtomicBoolean(false);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .afterFailure((b, e) -> failureCalled.set(true))
+ .afterSuccess((b) -> successCalled.set(true))
+ .afterTimeout((b) -> timeoutCalled.set(true)).create();
+ try {
+ gremlinExecutor.eval("10/0").get();
+ fail();
+ } catch (Exception ex) {
+
+ }
+
+ // need to wait long enough for the script to complete
+ Thread.sleep(750);
+
+ assertFalse(timeoutCalled.get());
+ assertFalse(successCalled.get());
+ assertTrue(failureCalled.get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldCallSuccess() throws Exception {
+ final AtomicBoolean timeoutCalled = new AtomicBoolean(false);
+ final AtomicBoolean successCalled = new AtomicBoolean(false);
+ final AtomicBoolean failureCalled = new AtomicBoolean(false);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .afterFailure((b, e) -> failureCalled.set(true))
+ .afterSuccess((b) -> successCalled.set(true))
+ .afterTimeout((b) -> timeoutCalled.set(true)).create();
+ assertEquals(2, gremlinExecutor.eval("1+1").get());
+
+ // need to wait long enough for the script to complete
+ Thread.sleep(750);
+
+ assertFalse(timeoutCalled.get());
+ assertTrue(successCalled.get());
+ assertFalse(failureCalled.get());
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldEvalInMultipleThreads() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+
+ final CyclicBarrier barrier = new CyclicBarrier(2);
+ final AtomicInteger i1 = new AtomicInteger(0);
+ final AtomicBoolean b1 = new AtomicBoolean(false);
+ final Thread t1 = new Thread(() -> {
+ try {
+ barrier.await();
+ i1.set((Integer) gremlinExecutor.eval("1+1").get());
+ } catch (Exception ex) {
+ b1.set(true);
+ }
+ });
+
+ final AtomicInteger i2 = new AtomicInteger(0);
+ final AtomicBoolean b2 = new AtomicBoolean(false);
+ final Thread t2 = new Thread(() -> {
+ try {
+ barrier.await();
+ i2.set((Integer) gremlinExecutor.eval("1+1").get());
+ } catch (Exception ex) {
+ b2.set(true);
+ }
+ });
+
+ t1.start();
+ t2.start();
+
+ t1.join();
+ t2.join();
+
+ assertEquals(2, i1.get());
+ assertEquals(2, i2.get());
+ assertFalse(b1.get());
+ assertFalse(b2.get());
+
+ gremlinExecutor.close();
+
+ }
+
+ @Test
+ public void shouldNotExhaustThreads() throws Exception {
+ final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2, testingThreadFactory);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .executorService(executorService)
+ .scheduledExecutorService(executorService).create();
+
+ final AtomicInteger count = new AtomicInteger(0);
+ assertTrue(IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("1+1")).allMatch(f -> {
+ try {
+ return (Integer) f.get() == 2;
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ count.incrementAndGet();
+ }
+ }));
+
+ assertEquals(1000, count.intValue());
+
+ executorService.shutdown();
+ executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void shouldFailUntilImportExecutes() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build().create();
+
+ final Set<String> imports = new HashSet<String>() {{
+ add("import java.awt.Color");
+ }};
+
+ final AtomicInteger successes = new AtomicInteger(0);
+ final AtomicInteger failures = new AtomicInteger(0);
+
+ // issue 1000 scripts in one thread using a class that isn't imported. this will result in failure.
+ // while that thread is running start a new thread that issues an addImports to include that class.
+ // this should block further evals in the first thread until the import is complete at which point
+ // evals in the first thread will resume and start to succeed
+ final Thread t1 = new Thread(() ->
+ IntStream.range(0, 1000).mapToObj(i -> gremlinExecutor.eval("Color.BLACK"))
+ .forEach(f -> {
+ f.exceptionally(t -> failures.incrementAndGet()).join();
+ if (!f.isCompletedExceptionally())
+ successes.incrementAndGet();
+ })
+ );
+
+ final Thread t2 = new Thread(() -> {
+ while (failures.get() < 500) {
+ }
+ gremlinExecutor.getScriptEngines().addImports(imports);
+ });
+
+ t1.start();
+ t2.start();
+
+ t1.join();
+ t2.join();
+
+ assertTrue(successes.intValue() > 0);
+ assertTrue(failures.intValue() >= 500);
+
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldInitializeWithScript() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ Collections.emptyMap())
+ .create();
+
+ assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
+
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldSecureAll() throws Exception {
+ GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
+ final Map<String, Object> config = new HashMap<>();
+ config.put("sandbox", GremlinGroovyScriptEngineTest.DenyAll.class.getName());
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ config)
+ .create();
+ try {
+ gremlinExecutor.eval("c = new java.awt.Color(255, 255, 255)").get();
+ fail("Should have failed security");
+ } catch (Exception se) {
+ assertEquals(SecurityException.class, se.getCause().getClass());
+ } finally {
+ gremlinExecutor.close();
+ }
+ }
+
+ @Test
+ public void shouldSecureSome() throws Exception {
+ GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
+ final Map<String, Object> config = new HashMap<>();
+ config.put("sandbox", GremlinGroovyScriptEngineTest.AllowSome.class.getName());
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ config)
+ .create();
+ try {
+ gremlinExecutor.eval("c = 'new java.awt.Color(255, 255, 255)'").get();
+ fail("Should have failed security");
+ } catch (Exception se) {
+ assertEquals(SecurityException.class, se.getCause().getClass());
+ }
+
+ try {
+ final java.awt.Color c = (java.awt.Color) gremlinExecutor.eval("g = new java.awt.Color(255, 255, 255)").get();
+ assertEquals(java.awt.Color.class, c.getClass());
+ } catch (Exception ignored) {
+ fail("Should not have tossed an exception");
+ } finally {
+ gremlinExecutor.close();
+ }
+ }
+
+ @Test
+ public void shouldInitializeWithScriptAndWorkAfterReset() throws Exception {
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .addEngineSettings("gremlin-groovy",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Arrays.asList(PATHS.get("GremlinExecutorInit.groovy")),
+ Collections.emptyMap())
+ .create();
+
+ assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
+
+ gremlinExecutor.getScriptEngines().reset();
+
+ assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
+
+ gremlinExecutor.close();
+ }
+
+ @Test
+ public void shouldNotShutdownExecutorServicesSuppliedToGremlinExecutor() throws Exception {
+ final ScheduledExecutorService service = Executors.newScheduledThreadPool(4, testingThreadFactory);
+ final GremlinExecutor gremlinExecutor = GremlinExecutor.build()
+ .executorService(service)
+ .scheduledExecutorService(service).create();
+
+ gremlinExecutor.close();
+ assertFalse(service.isShutdown());
+ service.shutdown();
+ service.awaitTermination(30000, TimeUnit.MILLISECONDS);
+ }
+}
[2/3] incubator-tinkerpop git commit: Move unit tests that don't need
a graph from gremlin-groovy-test to gremlin-groovy.
Posted by sp...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
new file mode 100644
index 0000000..b3d41da
--- /dev/null
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
@@ -0,0 +1,309 @@
+package org.apache.tinkerpop.gremlin.groovy.jsr223;
+
+import groovy.lang.Closure;
+import groovy.lang.Script;
+import org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.SecurityCustomizerProvider;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.util.StreamFactory;
+import org.junit.Test;
+import org.kohsuke.groovy.sandbox.GroovyInterceptor;
+import org.kohsuke.groovy.sandbox.GroovyValueFilter;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinGroovyScriptEngineTest {
+
+ @Test
+ public void shouldCompileScriptWithoutRequiringVariableBindings() throws Exception {
+ // compile() should cache the script to avoid future compilation
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+
+ final String script = "g.V(x).out()";
+ assertFalse(engine.isCached(script));
+ assertNotNull(engine.compile(script));
+ assertTrue(engine.isCached(script));
+
+ engine.reset();
+
+ assertFalse(engine.isCached(script));
+ }
+
+ @Test
+ public void shouldLoadImportsViaDependencyManagerInterface() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
+ try {
+ engine.eval("Vertex.class.getName()");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ engine.addImports(new HashSet<>(Arrays.asList("import org.apache.tinkerpop.gremlin.structure.Vertex")));
+ assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
+ }
+
+ @Test
+ public void shouldLoadImportsViaDependencyManagerInterfaceAdditively() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
+ try {
+ engine.eval("Vertex.class.getName()");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ try {
+ engine.eval("StreamFactory.class.getName()");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ engine.addImports(new HashSet<>(Arrays.asList("import " + Vertex.class.getCanonicalName())));
+ assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
+
+ try {
+ engine.eval("StreamFactory.class.getName()");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ engine.addImports(new HashSet<>(Arrays.asList("import " + StreamFactory.class.getCanonicalName())));
+ assertEquals(Vertex.class.getName(), engine.eval("Vertex.class.getName()"));
+ assertEquals(StreamFactory.class.getName(), engine.eval("StreamFactory.class.getName()"));
+ }
+
+ @Test
+ public void shouldLoadImportsViaDependencyManagerFromDependencyGatheredByUse() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
+ try {
+ engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ engine.addImports(new HashSet<>(Arrays.asList("import org.apache.commons.math3.util.FastMath")));
+ engine.use("org.apache.commons", "commons-math3", "3.2");
+ assertEquals(1235, engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)"));
+ }
+
+ @Test
+ public void shouldAllowsUseToBeExecutedAfterImport() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new NoImportCustomizerProvider());
+ try {
+ engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)");
+ fail("Should have thrown an exception because no imports were supplied");
+ } catch (Exception se) {
+ assertTrue(se instanceof ScriptException);
+ }
+
+ engine.use("org.apache.commons", "commons-math3", "3.2");
+ engine.addImports(new HashSet<>(Arrays.asList("import org.apache.commons.math3.util.FastMath")));
+ assertEquals(1235, engine.eval("org.apache.commons.math3.util.FastMath.abs(-1235)"));
+ }
+
+ @Test
+ public void shouldClearEngineScopeOnReset() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+ engine.eval("x = { y -> y + 1}");
+ Bindings b = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
+ assertTrue(b.containsKey("x"));
+ assertEquals(2, ((Closure) b.get("x")).call(1));
+
+ // should clear the bindings
+ engine.reset();
+ try {
+ engine.eval("x(1)");
+ fail("Bindings should have been cleared.");
+ } catch (Exception ex) {
+
+ }
+
+ b = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
+ assertFalse(b.containsKey("x"));
+
+ // redefine x
+ engine.eval("x = { y -> y + 2}");
+ assertEquals(3, engine.eval("x(1)"));
+ b = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
+ assertTrue(b.containsKey("x"));
+ assertEquals(3, ((Closure) b.get("x")).call(1));
+ }
+
+ @Test
+ public void shouldReloadClassLoaderWhileDoingEvalInSeparateThread() throws Exception {
+ final AtomicBoolean fail = new AtomicBoolean(false);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine();
+ final Thread t = new Thread(() -> {
+ try {
+ final Object o = scriptEngine.eval("Color.BLACK");
+ System.out.println("Should not print: " + o);
+ fail.set(true);
+ } catch (ScriptException se) {
+ // should get here as Color.BLACK is not imported yet.
+ System.out.println("Failed to execute Color.BLACK as expected.");
+ }
+
+ try {
+ int counter = 0;
+ while (latch.getCount() == 1) {
+ scriptEngine.eval("1+1");
+ counter++;
+ }
+
+ System.out.println(counter + " executions.");
+
+ scriptEngine.eval("Color.BLACK");
+ System.out.println("Color.BLACK now evaluates");
+ } catch (Exception se) {
+ se.printStackTrace();
+ fail.set(true);
+ }
+ }, "test-reload-classloader-1");
+
+ t.start();
+
+ // let the first thead execute a bit.
+ Thread.sleep(1000);
+
+ new Thread(() -> {
+ System.out.println("Importing java.awt.Color...");
+ final Set<String> imports = new HashSet<String>() {{
+ add("import java.awt.Color");
+ }};
+ scriptEngine.addImports(imports);
+ latch.countDown();
+ }, "test-reload-classloader-2").start();
+
+ t.join();
+
+ assertFalse(fail.get());
+ }
+
+ @Test
+ public void shouldResetClassLoader() throws Exception {
+ final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine();
+ try {
+ scriptEngine.eval("addOne(1)");
+ fail("Should have tossed ScriptException since addOne is not yet defined.");
+ } catch (ScriptException se) {
+ }
+
+ // validate that the addOne function works
+ scriptEngine.eval("addOne = { y-> y + 1}");
+ assertEquals(2, scriptEngine.eval("addOne(1)"));
+
+ // reset the script engine which should blow out the addOne function that's there.
+ scriptEngine.reset();
+
+ try {
+ scriptEngine.eval("addOne(1)");
+ fail("Should have tossed ScriptException since addOne is no longer defined after reset.");
+ } catch (ScriptException se) {
+ }
+ }
+
+ @Test
+ public void shouldSecureAll() throws Exception {
+ GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
+ final SecurityCustomizerProvider provider = new SecurityCustomizerProvider(new DenyAll());
+ final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine(
+ new DefaultImportCustomizerProvider(), provider);
+ try {
+ scriptEngine.eval("g = new java.awt.Color(255, 255, 255)");
+ fail("Should have failed security");
+ } catch (ScriptException se) {
+ assertEquals(SecurityException.class, se.getCause().getCause().getClass());
+ } finally {
+ provider.unregisterInterceptors();
+ }
+ }
+
+ @Test
+ public void shouldSecureSome() throws Exception {
+ GroovyInterceptor.getApplicableInterceptors().forEach(GroovyInterceptor::unregister);
+ final SecurityCustomizerProvider provider = new SecurityCustomizerProvider(new AllowSome());
+ final GremlinGroovyScriptEngine scriptEngine = new GremlinGroovyScriptEngine(
+ new DefaultImportCustomizerProvider(), provider);
+ try {
+ scriptEngine.eval("g = 'new java.awt.Color(255, 255, 255)'");
+ fail("Should have failed security");
+ } catch (ScriptException se) {
+ assertEquals(SecurityException.class, se.getCause().getCause().getClass());
+ }
+
+ try {
+ final java.awt.Color c = (java.awt.Color) scriptEngine.eval("c = new java.awt.Color(255, 255, 255)");
+ assertEquals(java.awt.Color.class, c.getClass());
+ } catch (Exception ex) {
+ fail("Should not have tossed an exception");
+ } finally {
+ provider.unregisterInterceptors();
+ }
+ }
+
+ @Test
+ public void shouldProcessScriptWithUTF8Characters() throws Exception {
+ final ScriptEngine engine = new GremlinGroovyScriptEngine();
+ assertEquals("轉注", engine.eval("'轉注'"));
+ }
+
+ @Test
+ public void shouldTimeoutScriptOnTimedWhile() throws Exception {
+ final ScriptEngine engine = new GremlinGroovyScriptEngine(new DefaultImportCustomizerProvider(), null, 3000);
+ try {
+ engine.eval("s = System.currentTimeMillis();\nwhile((System.currentTimeMillis() - s) < 10000) {}");
+ fail("This should have timed out");
+ } catch (ScriptException se) {
+ assertEquals(TimeoutException.class, se.getCause().getCause().getClass());
+ }
+ }
+
+ public static class DenyAll extends GroovyValueFilter {
+ @Override
+ public Object filter(final Object o) {
+ throw new SecurityException("Denied!");
+ }
+ }
+
+ public static class AllowSome extends GroovyValueFilter {
+
+ public static final Set<Class> ALLOWED_TYPES = new HashSet<Class>() {{
+ add(java.awt.Color.class);
+ add(Integer.class);
+ add(Class.class);
+ }};
+
+ @Override
+ public Object filter(final Object o) {
+ if (null == o || ALLOWED_TYPES.contains(o.getClass()))
+ return o;
+ if (o instanceof Script || o instanceof Closure)
+ return o; // access to properties of compiled groovy script
+ throw new SecurityException("Unexpected type: " + o.getClass());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/26c2b99a/gremlin-groovy/src/test/resources/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorInit.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/resources/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorInit.groovy b/gremlin-groovy/src/test/resources/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorInit.groovy
new file mode 100644
index 0000000..c320195
--- /dev/null
+++ b/gremlin-groovy/src/test/resources/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorInit.groovy
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+def add(x, y) { x + y }
\ No newline at end of file