tinkerpop-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dkupp...@apache.org
Subject [tinkerpop] 01/01: Implemented EdgeLabelVerificationStrategy
Date Thu, 04 Apr 2019 15:05:04 GMT
This is an automated email from the ASF dual-hosted git repository.

dkuppitz pushed a commit to branch TINKERPOP-2191
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 0769976c267183ffb9aa22ab9a379d7163e70d84
Author: Daniel Kuppitz <daniel_kuppitz@hotmail.com>
AuthorDate: Thu Mar 14 15:05:09 2019 -0700

    Implemented EdgeLabelVerificationStrategy
---
 CHANGELOG.asciidoc                                 |   2 +-
 docs/src/upgrade/release-3.3.x.asciidoc            |  38 +++++
 .../tinkerpop/gremlin/jsr223/CoreImports.java      |   2 +
 .../EdgeLabelVerificationStrategy.java             | 131 ++++++++++++++
 .../structure/io/graphson/GraphSONModule.java      |   5 +
 .../gremlin/structure/io/gryo/GryoVersion.java     |   7 +-
 .../EdgeLabelVerificationStrategyTest.java         | 188 +++++++++++++++++++++
 7 files changed, 370 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 88df8ad..106761a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -24,7 +24,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 === TinkerPop 3.3.7 (Release Date: NOT OFFICIALLY RELEASED YET)
 
 * Ensure `gremlin.sh` works when directories contain spaces
-
+* Implemented `EdgeLabelVerificationStrategy`
 
 [[release-3-3-6]]
 === TinkerPop 3.3.6 (Release Date: March 18, 2019)
diff --git a/docs/src/upgrade/release-3.3.x.asciidoc b/docs/src/upgrade/release-3.3.x.asciidoc
index c1911d3..a5ece72 100644
--- a/docs/src/upgrade/release-3.3.x.asciidoc
+++ b/docs/src/upgrade/release-3.3.x.asciidoc
@@ -27,6 +27,44 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 Please see the link:https://github.com/apache/tinkerpop/blob/3.3.7/CHANGELOG.asciidoc#release-3-3-7[changelog]
for a complete list of all the modifications that are part of this release.
 
+=== Upgrading for Providers
+
+==== Detection of Anti-Patterns
+
+This release adds a strategy named `EdgeLabelVerificationStrategy`. The strategy will not
be added by default to the traversal source, however, providers can add it explicitly to encourage
(or enforce)
+users to always specify at least one edge label. `EdgeLabelVerificationStrategy` can be configured
to either throw an exception if no edge label was specified, log a warning or do both.
+
+[source,text]
+----
+gremlin> // throw an exception if edge label was not specified
+gremlin> g = TinkerFactory.createModern().traversal().withStrategies(EdgeLabelVerificationStrategy.build().throwException().create())
+==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
+gremlin> g.V(1).out('knows')
+==>v[2]
+==>v[4]
+gremlin> g.V(1).out()
+The provided traversal contains a vertex step without any specified edge label: VertexStep(OUT,vertex)
+Type ':help' or ':h' for help.
+Display stack trace? [yN]
+----
+
+[source,text]
+----
+gremlin> // log a warning if edge label was not specified (Log4j has to be configured
properly)
+gremlin> g = TinkerFactory.createModern().traversal().withStrategies(EdgeLabelVerificationStrategy.build().logWarning().create())
+==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
+gremlin> g.V(1).out('knows')
+==>v[2]
+==>v[4]
+gremlin> g.V(1).out()
+WARN  org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy
 - The provided traversal contains a vertex step without any specified edge label: VertexStep(OUT,vertex)
+==>v[3]
+==>v[2]
+==>v[4]
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2191[TINKERPOP-2191]
+
 == TinkerPop 3.3.6
 
 *Release Date: March 18, 2019*
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
index 576d0de..e298951 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
@@ -86,6 +86,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.Orde
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathProcessorStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.StandardVerificationStrategy;
@@ -241,6 +242,7 @@ public final class CoreImports {
         CLASS_IMPORTS.add(LambdaRestrictionStrategy.class);
         CLASS_IMPORTS.add(ReadOnlyStrategy.class);
         CLASS_IMPORTS.add(StandardVerificationStrategy.class);
+        CLASS_IMPORTS.add(EdgeLabelVerificationStrategy.class);
         // graph traversal
         CLASS_IMPORTS.add(AnonymousTraversalSource.class);
         CLASS_IMPORTS.add(__.class);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java
new file mode 100644
index 0000000..47a016f
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategy.java
@@ -0,0 +1,131 @@
+/*
+ * 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.process.traversal.strategy.verification;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.MapConfiguration;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@code EdgeLabelVerificationStrategy} does not allow edge traversal steps to have no label
specified.
+ * Providing one or more labels is considered to be a best practice, however, TinkerPop will
not force the specification
+ * of edge labels; instead, providers or users will have to enable this strategy explicitly.
+ * <p/>
+ *
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ * @example <pre>
+ * __.outE()           // throws an IllegalStateException
+ * __.out()            // throws an IllegalStateException
+ * __.bothE()          // throws an IllegalStateException
+ * __.to(OUT)          // throws an IllegalStateException
+ * __.toE(IN)          // throws an IllegalStateException
+ * </pre>
+ */
+public final class EdgeLabelVerificationStrategy
+        extends AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy>
+        implements TraversalStrategy.VerificationStrategy {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(EdgeLabelVerificationStrategy.class);
+
+    private static final String THROW_EXCEPTION = "throwException";
+    private static final String LOG_WARNING = "logWarning";
+
+    private final boolean throwException;
+    private final boolean logWarning;
+
+    private EdgeLabelVerificationStrategy(final boolean throwException, final boolean logWarning)
{
+        this.throwException = throwException;
+        this.logWarning = logWarning;
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        for (final Step<?, ?> step : traversal.getSteps()) {
+            if (step instanceof VertexStep && ((VertexStep) step).getEdgeLabels().length
== 0) {
+                final String msg = String.format(
+                        "The provided traversal contains a vertex step without any specified
edge label: %s\nAlways " +
+                                "specify edge labels which restrict traversal paths ensuring
optimal performance.", step);
+                if (logWarning) {
+                    LOGGER.warn(msg);
+                }
+                if (throwException) {
+                    throw new VerificationException(msg, traversal);
+                }
+            }
+        }
+    }
+
+    public static EdgeLabelVerificationStrategy create(final Configuration configuration)
{
+        return new EdgeLabelVerificationStrategy(
+                configuration.getBoolean(THROW_EXCEPTION, false),
+                configuration.getBoolean(LOG_WARNING, false));
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+        final Map<String, Object> m = new HashMap<>(2);
+        m.put(THROW_EXCEPTION, this.throwException);
+        m.put(LOG_WARNING, this.logWarning);
+        return new MapConfiguration(m);
+    }
+
+    public static EdgeLabelVerificationStrategy.Builder build() {
+        return new EdgeLabelVerificationStrategy.Builder();
+    }
+
+    public final static class Builder {
+
+        private boolean throwException;
+        private boolean logWarning;
+
+        private Builder() {
+        }
+
+        public EdgeLabelVerificationStrategy.Builder throwException() {
+            return this.throwException(true);
+        }
+
+        public EdgeLabelVerificationStrategy.Builder throwException(final boolean throwException)
{
+            this.throwException = throwException;
+            return this;
+        }
+
+        public EdgeLabelVerificationStrategy.Builder logWarning() {
+            return this.logWarning(true);
+        }
+
+        public EdgeLabelVerificationStrategy.Builder logWarning(final boolean logWarning)
{
+            this.logWarning = logWarning;
+            return this;
+        }
+
+        public EdgeLabelVerificationStrategy create() {
+            return new EdgeLabelVerificationStrategy(this.throwException, this.logWarning);
+        }
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index 1078a6b..3bbea66 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -54,6 +54,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.Path
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.StandardVerificationStrategy;
@@ -183,6 +184,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                             ReadOnlyStrategy.class,
                             StandardVerificationStrategy.class,
                             EarlyLimitStrategy.class,
+                            EdgeLabelVerificationStrategy.class,
                             //
                             GraphFilterStrategy.class,
                             VertexProgramStrategy.class
@@ -300,6 +302,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     ReadOnlyStrategy.class,
                     StandardVerificationStrategy.class,
                     EarlyLimitStrategy.class,
+                    EdgeLabelVerificationStrategy.class,
                     //
                     GraphFilterStrategy.class,
                     VertexProgramStrategy.class
@@ -400,6 +403,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                             ReadOnlyStrategy.class,
                             StandardVerificationStrategy.class,
                             EarlyLimitStrategy.class,
+                            EdgeLabelVerificationStrategy.class,
                             //
                             GraphFilterStrategy.class,
                             VertexProgramStrategy.class
@@ -509,6 +513,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     ReadOnlyStrategy.class,
                     StandardVerificationStrategy.class,
                     EarlyLimitStrategy.class,
+                    EdgeLabelVerificationStrategy.class,
                     //
                     GraphFilterStrategy.class,
                     VertexProgramStrategy.class
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index 7c1dd5a..974542d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -63,6 +63,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.Path
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_LP_O_P_S_SE_SL_Traverser;
@@ -336,9 +337,10 @@ public enum GryoVersion {
             add(GryoTypeReg.of(GraphFilterStrategy.class, 157));
             add(GryoTypeReg.of(LambdaRestrictionStrategy.class, 158));
             add(GryoTypeReg.of(ReadOnlyStrategy.class, 159));
-            add(GryoTypeReg.of(EarlyLimitStrategy.class, 188));   // ***LAST ID***
+            add(GryoTypeReg.of(EarlyLimitStrategy.class, 188));
             add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 164));
+            add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));   // ***LAST ID***
 
             add(GryoTypeReg.of(TraverserSet.class, 58));
             add(GryoTypeReg.of(Tree.class, 61));
@@ -555,9 +557,10 @@ public enum GryoVersion {
             add(GryoTypeReg.of(GraphFilterStrategy.class, 157));
             add(GryoTypeReg.of(LambdaRestrictionStrategy.class, 158));
             add(GryoTypeReg.of(ReadOnlyStrategy.class, 159));
-            add(GryoTypeReg.of(EarlyLimitStrategy.class, 188));   // ***LAST ID***
+            add(GryoTypeReg.of(EarlyLimitStrategy.class, 188));
             add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 167));
+            add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));   // ***LAST ID***
             // skip 171, 172 to sync with tp33
             add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173));
         }};
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
new file mode 100644
index 0000000..72a8841
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/EdgeLabelVerificationStrategyTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.process.traversal.strategy.verification;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+@RunWith(Parameterized.class)
+public class EdgeLabelVerificationStrategyTest {
+
+    private final static Predicate<String> MSG_PREDICATE = Pattern.compile(
+            "^The provided traversal contains a vertex step without any specified edge label:
VertexStep.*")
+            .asPredicate();
+
+    private TestLogAppender logAppender;
+    private Level previousLogLevel;
+
+    @Before
+    public void setupForEachTest() {
+        final org.apache.log4j.Logger strategyLogger = org.apache.log4j.Logger.getLogger(EdgeLabelVerificationStrategy.class);
+        previousLogLevel = strategyLogger.getLevel();
+        strategyLogger.setLevel(Level.WARN);
+        Logger.getRootLogger().addAppender(logAppender = new TestLogAppender());
+    }
+
+    @After
+    public void teardownForEachTest() {
+        final org.apache.log4j.Logger strategyLogger = org.apache.log4j.Logger.getLogger(EdgeLabelVerificationStrategy.class);
+        strategyLogger.setLevel(previousLogLevel);
+        Logger.getRootLogger().removeAppender(logAppender);
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {"__.inE()", __.inE(), false},
+                {"__.outE()", __.outE(), false},
+                {"__.bothE()", __.bothE(), false},
+                {"__.to(OUT)", __.to(Direction.OUT), false},
+                {"__.toE(IN)", __.toE(Direction.IN), false},
+                {"__.inE('knows')", __.inE("knows"), true},
+                {"__.outE('knows')", __.outE("knows"), true},
+                {"__.bothE('created','knows')", __.bothE("created", "knows"), true},
+                {"__.to(OUT,'created','knows')", __.to(Direction.OUT, "created", "knows"),
true},
+                {"__.toE(IN,'knows')", __.toE(Direction.IN, "knows"), true}
+        });
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String name;
+
+    @Parameterized.Parameter(value = 1)
+    public Traversal traversal;
+
+    @Parameterized.Parameter(value = 2)
+    public boolean allow;
+
+    @Test
+    public void shouldIgnore() {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(EdgeLabelVerificationStrategy.build().create());
+        final Traversal traversal = this.traversal.asAdmin().clone();
+        traversal.asAdmin().setStrategies(strategies);
+        traversal.asAdmin().applyStrategies();
+        assertTrue(logAppender.isEmpty());
+    }
+
+    @Test
+    public void shouldOnlyThrow() {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(EdgeLabelVerificationStrategy.build().throwException().create());
+        final Traversal traversal = this.traversal.asAdmin().clone();
+        traversal.asAdmin().setStrategies(strategies);
+        if (allow) {
+            traversal.asAdmin().applyStrategies();
+        } else {
+            try {
+                traversal.asAdmin().applyStrategies();
+                fail("The strategy should not allow vertex steps with unspecified edge labels:
" + this.traversal);
+            } catch (VerificationException ise) {
+                assertTrue(MSG_PREDICATE.test(ise.getMessage()));
+            }
+        }
+        assertTrue(logAppender.isEmpty());
+    }
+
+    @Test
+    public void shouldOnlyLog() {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(EdgeLabelVerificationStrategy.build().logWarning().create());
+        final Traversal traversal = this.traversal.asAdmin().clone();
+        traversal.asAdmin().setStrategies(strategies);
+        traversal.asAdmin().applyStrategies();
+        if (!allow) {
+            assertTrue(String.format("Expected log entry not found in %s", logAppender.messages),
+                    logAppender.messages().anyMatch(MSG_PREDICATE));
+        }
+    }
+
+    @Test
+    public void shouldThrowAndLog() {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(EdgeLabelVerificationStrategy.build().throwException().logWarning().create());
+        final Traversal traversal = this.traversal.asAdmin().clone();
+        traversal.asAdmin().setStrategies(strategies);
+        if (allow) {
+            traversal.asAdmin().applyStrategies();
+            assertTrue(logAppender.isEmpty());
+        } else {
+            try {
+                traversal.asAdmin().applyStrategies();
+                fail("The strategy should not allow vertex steps with unspecified edge labels:
" + this.traversal);
+            } catch (VerificationException ise) {
+                assertTrue(MSG_PREDICATE.test(ise.getMessage()));
+            }
+            assertTrue(String.format("Expected log entry not found in %s", logAppender.messages),
+                    logAppender.messages().anyMatch(MSG_PREDICATE));
+        }
+    }
+
+    class TestLogAppender extends AppenderSkeleton {
+
+        private List<String> messages = new ArrayList<>();
+
+        boolean isEmpty() {
+            return messages.isEmpty();
+        }
+
+        Stream<String> messages() {
+            return messages.stream();
+        }
+
+        @Override
+        protected void append(org.apache.log4j.spi.LoggingEvent loggingEvent) {
+            messages.add(loggingEvent.getMessage().toString());
+        }
+
+        @Override
+        public void close() {
+
+        }
+
+        @Override
+        public boolean requiresLayout() {
+            return false;
+        }
+    }
+}
\ No newline at end of file


Mime
View raw message