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":

Reply via email to