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