This is an automated email from the ASF dual-hosted git repository.
kenhuuu pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.8-dev by this push:
new 0e7c2c6a25 TINKERPOP-3201 Fix tail inside repeat (#3248)
0e7c2c6a25 is described below
commit 0e7c2c6a258d206e597aab02e4c88b692da841b7
Author: kenhuuu <[email protected]>
AuthorDate: Tue Oct 28 14:09:28 2025 -0700
TINKERPOP-3201 Fix tail inside repeat (#3248)
---
CHANGELOG.asciidoc | 1 +
.../traversal/step/filter/TailGlobalStep.java | 6 +-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 7 ++
gremlin-go/driver/cucumber/gremlin.go | 7 ++
.../gremlin-javascript/test/cucumber/gremlin.js | 7 ++
gremlin-python/src/main/python/radish/gremlin.py | 7 ++
.../gremlin/driver/remote/RemoteWorld.java | 5 +
.../gremlin/test/features/branch/Repeat.feature | 107 ++++++++++++++++++++-
.../spark/SparkGraphFeatureIntegrateTest.java | 5 +
.../tinkerpop/gremlin/tinkergraph/TinkerWorld.java | 5 +
10 files changed, 154 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 09559f25aa..0cfe3d5f26 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -41,6 +41,7 @@ This release also includes changes from <<release-3-7-XXX,
3.7.XXX>>.
* Added `DateTime` ontop of the existing 'datetime' grammar.
* Added `UUID()` and `UUID(value)` to grammar.
* Deprecated the `UnifiedChannelizer`.
+* Fixed bug that caused incorrect results when `tail()` used inside `repeat()`.
* Modified `TraversalStrategy` construction in Javascript where configurations
are now supplied as a `Map` of options.
* Fixed bug in GraphSON v2 and v3 where full round trip of `TraversalStrategy`
implementations was failing.
* Added missing strategies to the `TraversalStrategies` global cache as well
as `CoreImports` in `gremlin-groovy`.
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
index 420e3f02d4..a14bc64cc7 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
@@ -58,8 +58,10 @@ public final class TailGlobalStep<S> extends AbstractStep<S,
S> implements TailG
// If we are bypassing this step, let everything through.
return this.starts.next();
} else {
- // Pull everything available before we start delivering from the
tail buffer.
- if (this.starts.hasNext()) {
+ // Pull everything available before we start delivering from the
tail buffer. But only if the tail buffer is
+ // already empty, otherwise, there are more traversers to pass on
so hold off on modifying the tail buffer.
+ // This is most important when part of a repeat traversal as
traversers can be looped back as starts.
+ if (this.tail.isEmpty() && this.starts.hasNext()) {
this.starts.forEachRemaining(this::addTail);
}
// Pull the oldest traverser from the tail buffer.
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index e1f2a0c263..72a6e338a1 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -173,6 +173,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_withSackX0X_V_repeatXsackXsumX_byXageX_whereXsack_isXltX59XXXX_timesX2X",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.WithSack(0l).V().Repeat(__.Sack(Operator.Sum).By("age").Where(__.Sack<object>().Is(P.Lt(59)))).Times(2)}},
{"g_V_repeatXinjectXyXX_timesX2X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().Repeat(__.Inject("y")).Times(2)}},
{"g_V_repeatXunionXconstantXyX_limitX1X_identityXX_timesX3X",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V().Repeat(__.Union<object>(__.Constant<object>("y").Limit<object>(1),
__.Identity())).Times(2)}},
+
{"g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX1X_valuesXnameX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V(p["vid3"]).Repeat(__.Out().Order().By("performances").Tail<object>(2)).Times(1).Values<object>("name")}},
+
{"g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V(p["vid3"]).Repeat(__.Out().Order().By("performances").Tail<object>(2)).Times(2).Values<object>("name")}},
+
{"g_VX2X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX1X_valuesXnameX",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V(p["vid2"]).Repeat(__.Out().Local<object>(__.Order().By("performances").Tail<object>(1))).Times(1).Values<object>("name")}},
+
{"g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V(p["vid250"]).Repeat(__.Out().Local<object>(__.Order().By("performances").Tail<object>(1))).Times(2).Values<object>("name")}},
+
{"g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V(p["vid3"]).Repeat(__.Out().Order().By("performances").Tail<object>(3).Limit<object>(1)).Times(2).Values<object>("name")}},
+
{"g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V(p["vid3"]).Repeat(__.Out().Order().By("performances",
Order.Desc).Limit<object>(5).Tail<object>(1)).Times(2).Values<object>("name")}},
+
{"g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.V(p["vid3"]).Repeat(__.OutE().Order().By("weight").Tail<object>(2).InV()).Times(2).Values<object>("name")}},
{"g_unionXX", new List<Func<GraphTraversalSource,
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>()}},
{"g_unionXV_name", new List<Func<GraphTraversalSource,
IDictionary<string, object>, ITraversal>> {(g,p)
=>g.Union<object>(__.V().Values<object>("name"))}},
{"g_unionXVXv1X_VX4XX_name", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.Union<object>(__.V(p["vid1"]),
__.V(p["vid4"])).Values<object>("name")}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go
b/gremlin-go/driver/cucumber/gremlin.go
index 834875ff88..cb5dd3a53e 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -143,6 +143,13 @@ var translationMap = map[string][]func(g
*gremlingo.GraphTraversalSource, p map[
"g_withSackX0X_V_repeatXsackXsumX_byXageX_whereXsack_isXltX59XXXX_timesX2X":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.WithSack(int64(0)).V().Repeat(gremlingo.T__.Sack(gremlingo.Operator.Sum).By("age").Where(gremlingo.T__.Sack().Is(gremlingo.P.Lt(59)))).Times(2)}},
"g_V_repeatXinjectXyXX_timesX2X": {func(g *gremlingo.GraphTraversalSource,
p map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Repeat(gremlingo.T__.Inject("y")).Times(2)}},
"g_V_repeatXunionXconstantXyX_limitX1X_identityXX_timesX3X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().Repeat(gremlingo.T__.Union(gremlingo.T__.Constant("y").Limit(1),
gremlingo.T__.Identity())).Times(2)}},
+ "g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX1X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid3"]).Repeat(gremlingo.T__.Out().Order().By("performances").Tail(2)).Times(1).Values("name")}},
+ "g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid3"]).Repeat(gremlingo.T__.Out().Order().By("performances").Tail(2)).Times(2).Values("name")}},
+
"g_VX2X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX1X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid2"]).Repeat(gremlingo.T__.Out().Local(gremlingo.T__.Order().By("performances").Tail(1))).Times(1).Values("name")}},
+
"g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid250"]).Repeat(gremlingo.T__.Out().Local(gremlingo.T__.Order().By("performances").Tail(1))).Times(2).Values("name")}},
+
"g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid3"]).Repeat(gremlingo.T__.Out().Order().By("performances").Tail(3).Limit(1)).Times(2).Values("name")}},
+
"g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid3"]).Repeat(gremlingo.T__.Out().Order().By("performances",
gremlingo.Order.Desc).Limit(5).Tail(1)).Times(2).Values("name")}},
+ "g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V(p["vid3"]).Repeat(gremlingo.T__.OutE().Order().By("weight").Tail(2).InV()).Times(2).Values("name")}},
"g_unionXX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.Union()}},
"g_unionXV_name": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.Union(gremlingo.T__.V().Values("name"))}},
"g_unionXVXv1X_VX4XX_name": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.Union(gremlingo.T__.V(p["vid1"]),
gremlingo.T__.V(p["vid4"])).Values("name")}},
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index bc9f6ace25..90cb2c61bc 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -174,6 +174,13 @@ const gremlins = {
g_withSackX0X_V_repeatXsackXsumX_byXageX_whereXsack_isXltX59XXXX_timesX2X:
[function({g}) { return
g.withSack(0).V().repeat(__.sack(Operator.sum).by("age").where(__.sack().is(P.lt(59)))).times(2)
}],
g_V_repeatXinjectXyXX_timesX2X: [function({g}) { return
g.V().repeat(__.inject("y")).times(2) }],
g_V_repeatXunionXconstantXyX_limitX1X_identityXX_timesX3X: [function({g})
{ return g.V().repeat(__.union(__.constant("y").limit(1),
__.identity())).times(2) }],
+ g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX1X_valuesXnameX:
[function({g, vid3}) { return
g.V(vid3).repeat(__.out().order().by("performances").tail(2)).times(1).values("name")
}],
+ g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX:
[function({g, vid3}) { return
g.V(vid3).repeat(__.out().order().by("performances").tail(2)).times(2).values("name")
}],
+
g_VX2X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX1X_valuesXnameX:
[function({g, vid2}) { return
g.V(vid2).repeat(__.out().local(__.order().by("performances").tail(1))).times(1).values("name")
}],
+
g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX:
[function({g, vid250}) { return
g.V(vid250).repeat(__.out().local(__.order().by("performances").tail(1))).times(2).values("name")
}],
+
g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX:
[function({g, vid3}) { return
g.V(vid3).repeat(__.out().order().by("performances").tail(3).limit(1)).times(2).values("name")
}],
+
g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX:
[function({g, vid3}) { return
g.V(vid3).repeat(__.out().order().by("performances",
Order.desc).limit(5).tail(1)).times(2).values("name") }],
+ g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX:
[function({g, vid3}) { return
g.V(vid3).repeat(__.outE().order().by("weight").tail(2).inV()).times(2).values("name")
}],
g_unionXX: [function({g}) { return g.union() }],
g_unionXV_name: [function({g}) { return g.union(__.V().values("name")) }],
g_unionXVXv1X_VX4XX_name: [function({g, vid4, vid1}) { return
g.union(__.V(vid1), __.V(vid4)).values("name") }],
diff --git a/gremlin-python/src/main/python/radish/gremlin.py
b/gremlin-python/src/main/python/radish/gremlin.py
index 7d76bbc133..aeeee9e77d 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -146,6 +146,13 @@ world.gremlins = {
'g_withSackX0X_V_repeatXsackXsumX_byXageX_whereXsack_isXltX59XXXX_timesX2X':
[(lambda
g:g.with_sack(long(0)).V().repeat(__.sack(Operator.sum_).by('age').where(__.sack().is_(P.lt(59)))).times(2))],
'g_V_repeatXinjectXyXX_timesX2X': [(lambda
g:g.V().repeat(__.inject('y')).times(2))],
'g_V_repeatXunionXconstantXyX_limitX1X_identityXX_timesX3X': [(lambda
g:g.V().repeat(__.union(__.constant('y').limit(1), __.identity())).times(2))],
+ 'g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX1X_valuesXnameX':
[(lambda g,
vid3=None:g.V(vid3).repeat(__.out().order().by('performances').tail(2)).times(1).values('name'))],
+ 'g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX':
[(lambda g,
vid3=None:g.V(vid3).repeat(__.out().order().by('performances').tail(2)).times(2).values('name'))],
+
'g_VX2X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX1X_valuesXnameX':
[(lambda g,
vid2=None:g.V(vid2).repeat(__.out().local(__.order().by('performances').tail(1))).times(1).values('name'))],
+
'g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX':
[(lambda g,
vid250=None:g.V(vid250).repeat(__.out().local(__.order().by('performances').tail(1))).times(2).values('name'))],
+
'g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX':
[(lambda g,
vid3=None:g.V(vid3).repeat(__.out().order().by('performances').tail(3).limit(1)).times(2).values('name'))],
+
'g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX':
[(lambda g, vid3=None:g.V(vid3).repeat(__.out().order().by('performances',
Order.desc).limit(5).tail(1)).times(2).values('name'))],
+ 'g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX':
[(lambda g,
vid3=None:g.V(vid3).repeat(__.out_e().order().by('weight').tail(2).in_v()).times(2).values('name'))],
'g_unionXX': [(lambda g:g.union())],
'g_unionXV_name': [(lambda g:g.union(__.V().values('name')))],
'g_unionXVXv1X_VX4XX_name': [(lambda g,
vid4=None,vid1=None:g.union(__.V(vid1), __.V(vid4)).values('name'))],
diff --git
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/RemoteWorld.java
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/RemoteWorld.java
index f82e3e81da..4c0716fa1f 100644
---
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/RemoteWorld.java
+++
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/RemoteWorld.java
@@ -146,6 +146,11 @@ public abstract class RemoteWorld implements World {
case
"g_V_repeatXunionXoutXknowsX_order_byXnameX_inXcreatedX_order_byXnameXXX_timesX1X":
case
"g_V_repeatXboth_repeatXorder_byXnameXX_timesX1XX_timesX1X":
case
"g_V_order_byXname_descX_repeatXboth_simplePath_order_byXname_descXX_timesX2X_path":
+ case
"g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX":
+ case
"g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX":
+ case
"g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX":
+ case
"g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX":
+ case
"g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX":
throw new AssumptionViolatedException("GraphComputer
doesn't order within repeat");
// TINKERPOP-3209
case "g_V_localXgroupCountXaX_selectXaX_countXlocalXX":
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
index fab0d3e3d7..ae44d7e62a 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
@@ -711,4 +711,109 @@ Feature: Step - repeat()
| v[lop] |
| v[josh] |
| v[ripple] |
- | v[peter] |
\ No newline at end of file
+ | v[peter] |
+
+ # Test tail works in repeat with a single loop
+ Scenario:
g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX1X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+ And the traversal of
+ """
+
g.V(vid3).repeat(__.out().order().by("performances").tail(2)).times(1).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | ME AND MY UNCLE |
+ | DRUMS |
+
+ # Test tail runs per iteration in repeat with multiple iterations
+ Scenario:
g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+ And the traversal of
+ """
+
g.V(vid3).repeat(__.out().order().by("performances").tail(2)).times(2).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | THE OTHER ONE |
+ | SUGAR MAGNOLIA |
+
+ # Test object-local tail works in repeat with a single loop
+ Scenario:
g_VX2X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX1X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid2 defined as "v[IM A MAN].id"
+ And the traversal of
+ """
+
g.V(vid2).repeat(__.out().local(__.order().by("performances").tail(1))).times(1).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | JAM |
+ | JACK STRAW |
+
+ # Test object-local tail runs per iteration in repeat with multiple
iterations
+ Scenario:
g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid250 defined as "v[SIMPLE TWIST OF FATE].id"
+ And the traversal of
+ """
+
g.V(vid250).repeat(__.out().local(__.order().by("performances").tail(1))).times(2).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | STUCK INSIDE OF MOBILE |
+ | STUCK INSIDE OF MOBILE |
+ | WICKED MESSENGER |
+ | TANGLED UP IN BLUE |
+ | SHELTER FROM THE STORM |
+ | RAINY DAY WOMAN |
+ | CUMBERLAND BLUES |
+ | WHEN PUSH COMES TO SHOVE |
+ | JOHN BROWN |
+ | SIMPLE TWIST OF FATE |
+ | BABY BLUE |
+
+ # Test tail inside repeat can be followed by other range-based steps
+ Scenario:
g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+ And the traversal of
+ """
+
g.V(vid3).repeat(__.out().order().by("performances").tail(3).limit(1)).times(2).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | THE OTHER ONE |
+
+ # Test tail inside repeat can be preceded by other range-based steps
+ Scenario:
g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+ And the traversal of
+ """
+ g.V(vid3).repeat(__.out().order().by("performances",
Order.desc).limit(5).tail(1)).times(2).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | CHINA CAT SUNFLOWER |
+
+ # Test order on edge weight with tail in repeat leads to ordered walk
+ Scenario:
g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX
+ Given the grateful graph
+ And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+ And the traversal of
+ """
+
g.V(vid3).repeat(__.outE().order().by("weight").tail(2).inV()).times(2).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | SUGAR MAGNOLIA |
+ | AROUND AND AROUND |
diff --git
a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/SparkGraphFeatureIntegrateTest.java
b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/SparkGraphFeatureIntegrateTest.java
index 3492acb5ec..68f6f8db90 100644
---
a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/SparkGraphFeatureIntegrateTest.java
+++
b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/SparkGraphFeatureIntegrateTest.java
@@ -87,6 +87,11 @@ public class SparkGraphFeatureIntegrateTest {
add(Pair.with("g_V_repeatXunionXoutXknowsX_order_byXnameX_inXcreatedX_order_byXnameXXX_timesX1X",
skipReasonOrdering));
add(Pair.with("g_V_repeatXboth_repeatXorder_byXnameXX_timesX1XX_timesX1X",
skipReasonOrdering));
add(Pair.with("g_V_order_byXname_descX_repeatXboth_simplePath_order_byXname_descXX_timesX2X_path",
skipReasonOrdering));
+
add(Pair.with("g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX",
skipReasonOrdering));
+
add(Pair.with("g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX",
skipReasonOrdering));
+
add(Pair.with("g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX",
skipReasonOrdering));
+
add(Pair.with("g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX",
skipReasonOrdering));
+
add(Pair.with("g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX",
skipReasonOrdering));
add(Pair.with("g_V_localXgroupCountXaX_selectXaX_countXlocalXX",
skipReasonTINKERPOP3209));
add(Pair.with("g_V_localXgroupXaX_byXnameX_by_selectXaX_countXlocalXX",
skipReasonTINKERPOP3209));
add(Pair.with("g_V_out_order_byXnameX_localXtreeXaX_selectXaX_countXlocalXX",
skipReasonTINKERPOP3209));
diff --git
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
index e3c89e0e6e..851b5375fd 100644
---
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
+++
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
@@ -313,6 +313,11 @@ public abstract class TinkerWorld implements World {
case
"g_V_repeatXunionXoutXknowsX_order_byXnameX_inXcreatedX_order_byXnameXXX_timesX1X":
case
"g_V_repeatXboth_repeatXorder_byXnameXX_timesX1XX_timesX1X":
case
"g_V_order_byXname_descX_repeatXboth_simplePath_order_byXname_descXX_timesX2X_path":
+ case
"g_VX3X_repeatXoutE_order_byXweightX_tailX2X_inVX_timesX2X_valuesXnameX":
+ case
"g_VX3X_repeatXout_order_byXperformances_descX_limitX5X_tailX1XX_timesX2X_valuesXnameX":
+ case
"g_VX3X_repeatXout_order_byXperformancesX_tailX3X_limitX1XX_timesX2X_valuesXnameX":
+ case
"g_VX250X_repeatXout_localXorder_byXperformancesX_tailX1XXX_timesX2X_valuesXnameX":
+ case
"g_VX3X_repeatXout_order_byXperformancesX_tailX2XX_timesX2X_valuesXnameX":
throw new AssumptionViolatedException("GraphComputer
doesn't order within repeat");
// TINKERPOP-3209
case "g_V_localXgroupCountXaX_selectXaX_countXlocalXX":