This is an automated email from the ASF dual-hosted git repository. kenhuuu pushed a commit to branch TINKERPOP-2974 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit c1c9c2362fa2b15587d5b8a76a11792b8ebad2c8 Author: Ken Hu <106191785+kenh...@users.noreply.github.com> AuthorDate: Mon Apr 14 11:41:53 2025 -0700 allow feature test to assert traversal construction exception --- .../tinkerpop/gremlin/jsr223/JavaTranslator.java | 14 +++++++++++--- gremlin-go/driver/resultSet.go | 12 ++++++++---- gremlin-go/driver/resultSet_test.go | 20 ++++++++++++++++---- gremlin-go/driver/traversal.go | 17 ++++++++++++++--- .../tinkerpop/gremlin/features/StepDefinition.java | 8 ++++++++ 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java index 7689b7d60b..fa56a2cd4f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/JavaTranslator.java @@ -241,6 +241,7 @@ public final class JavaTranslator<S extends TraversalSource, T extends Traversal "Could not locate method", delegate, methodName, argumentsCopy)); } + boolean found = false; try { for (final ReflectedMethod methodx : methodCache.get(methodName)) { final Method method = methodx.method; @@ -248,7 +249,7 @@ public final class JavaTranslator<S extends TraversalSource, T extends Traversal final Parameter[] parameters = methodx.parameters; if (parameters.length == argumentsCopy.length || methodx.hasVarArgs) { final Object[] newArguments = new Object[parameters.length]; - boolean found = true; + found = true; for (int i = 0; i < parameters.length; i++) { if (parameters[i].isVarArgs()) { final Class<?> parameterClass = parameters[i].getType().getComponentType(); @@ -323,8 +324,15 @@ public final class JavaTranslator<S extends TraversalSource, T extends Traversal } } } catch (final Throwable e) { - throw new IllegalStateException(generateMethodNotFoundMessage( - e.getMessage(), null, methodName, argumentsCopy), e); + if (found && (e instanceof InvocationTargetException)) { + // get the target exception out for a better message, otherwise, it will be null. + final InvocationTargetException ite = (InvocationTargetException) e; + throw new IllegalStateException(generateMethodNotFoundMessage( + ite.getTargetException().getMessage(), null, methodName, argumentsCopy), ite.getTargetException()); + } else { + throw new IllegalStateException(generateMethodNotFoundMessage( + e.getMessage(), null, methodName, argumentsCopy), e); + } } // if it got down here then the method was in the cache but it was never called as it could not be found diff --git a/gremlin-go/driver/resultSet.go b/gremlin-go/driver/resultSet.go index 73269deddd..4450cdfb67 100644 --- a/gremlin-go/driver/resultSet.go +++ b/gremlin-go/driver/resultSet.go @@ -33,7 +33,7 @@ type ResultSet interface { setStatusAttributes(statusAttributes map[string]interface{}) GetStatusAttributes() map[string]interface{} GetRequestID() string - IsEmpty() bool + IsEmpty() (bool, error) Close() unlockedClose() Channel() chan *Result @@ -78,17 +78,21 @@ func (channelResultSet *channelResultSet) setError(err error) { } // IsEmpty returns true when the channelResultSet is empty. -func (channelResultSet *channelResultSet) IsEmpty() bool { +func (channelResultSet *channelResultSet) IsEmpty() (bool, error) { channelResultSet.channelMutex.Lock() // If our channel is empty and we have no data in it, wait for signal that the state has been updated. if len(channelResultSet.channel) != 0 { // Channel is not empty. channelResultSet.channelMutex.Unlock() - return false + return false, nil + } else if channelResultSet.err != nil { + // Channel has an error. + channelResultSet.channelMutex.Unlock() + return true, channelResultSet.err } else if channelResultSet.closed { // Channel is empty and closed. channelResultSet.channelMutex.Unlock() - return true + return true, nil } else { // Channel is empty and not closed. Need to wait for signal that state has changed, otherwise // we do not know if it is empty or not. diff --git a/gremlin-go/driver/resultSet_test.go b/gremlin-go/driver/resultSet_test.go index df9752cac8..7e4a81c728 100644 --- a/gremlin-go/driver/resultSet_test.go +++ b/gremlin-go/driver/resultSet_test.go @@ -123,28 +123,36 @@ func TestChannelResultSet(t *testing.T) { t.Run("Test ResultSet IsEmpty before signal.", func(t *testing.T) { channelResultSet := newChannelResultSet(mockID, getSyncMap()) go closeAfterTime(500, channelResultSet) - empty := channelResultSet.IsEmpty() + empty, _ := channelResultSet.IsEmpty() assert.True(t, empty) }) t.Run("Test ResultSet IsEmpty after signal.", func(t *testing.T) { channelResultSet := newChannelResultSet(mockID, getSyncMap()) channelResultSet.Close() - empty := channelResultSet.IsEmpty() + empty, _ := channelResultSet.IsEmpty() assert.True(t, empty) }) t.Run("Test ResultSet IsEmpty after close.", func(t *testing.T) { channelResultSet := newChannelResultSet(mockID, getSyncMap()) go addAfterTime(500, channelResultSet) - empty := channelResultSet.IsEmpty() + empty, _ := channelResultSet.IsEmpty() assert.False(t, empty) channelResultSet.One() go closeAfterTime(500, channelResultSet) - empty = channelResultSet.IsEmpty() + empty, _ = channelResultSet.IsEmpty() assert.True(t, empty) }) + t.Run("Test ResultSet IsEmpty handles error.", func(t *testing.T) { + channelResultSet := newChannelResultSet(mockID, getSyncMap()) + setError(channelResultSet, fmt.Errorf("injected %s error", "ResultSet")) + empty, err := channelResultSet.IsEmpty() + assert.True(t, empty) + assert.True(t, err != nil) + }) + t.Run("Test ResultSet removes self from container.", func(t *testing.T) { container := getSyncMap() assert.Equal(t, 0, container.size()) @@ -172,6 +180,10 @@ func AddResults(resultSet ResultSet, count int) { } } +func setError(resultSet ResultSet, resultError error) { + resultSet.setError(resultError) +} + func closeAfterTime(millisecondTicks time.Duration, resultSet ResultSet) { time.Sleep(millisecondTicks * time.Millisecond) resultSet.Close() diff --git a/gremlin-go/driver/traversal.go b/gremlin-go/driver/traversal.go index a6011eab53..037ea2f269 100644 --- a/gremlin-go/driver/traversal.go +++ b/gremlin-go/driver/traversal.go @@ -102,7 +102,13 @@ func (t *Traversal) HasNext() (bool, error) { if err != nil { return false, err } - return !results.IsEmpty(), nil + + isEmpty, emptyErr := results.IsEmpty() + if emptyErr != nil { + return false, emptyErr + } else { + return !isEmpty, nil + } } // Next returns next result. @@ -111,9 +117,14 @@ func (t *Traversal) Next() (*Result, error) { if err != nil { return nil, err } - if results.IsEmpty() { + + isEmpty, emptyErr := results.IsEmpty() + if emptyErr != nil { + return nil, emptyErr + } else if isEmpty { return nil, newError(err0903NextNoResultsLeftError) } + result, _, err := results.One() return result, err } @@ -718,7 +729,7 @@ func ParseBigDecimal(strValue string) *BigDecimal { } // resolve big int unscaled := new(big.Int) - unscaled, ok = unscaled.SetString(strings.Replace(bfVal.String(), ".", "",-1), 10) + unscaled, ok = unscaled.SetString(strings.Replace(bfVal.String(), ".", "", -1), 10) if !ok { return nil } diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java index 13c6debeac..f14a1a5235 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java @@ -307,6 +307,10 @@ public final class StepDefinition { @When("iterated to list") public void iteratedToList() { + if ((null == traversal) && (error != null)) { + return; // Error probably occurred during traversal construction. Skip to prevent NPE. + } + try { result = traversal.toList(); } catch (Exception ex) { @@ -316,6 +320,10 @@ public final class StepDefinition { @When("iterated next") public void iteratedNext() { + if ((null == traversal) && (error != null)) { + return; // Error probably occurred during traversal construction. Skip to prevent NPE. + } + try { result = traversal.next(); } catch (Exception ex) {