Merge pull request #2736
Adding a public getter for Repeat Loop Name
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..f151584
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,14 @@
+<!--
+Thanks for contributing! Reminders:
++ TARGET the earliest branch where you want the change
+ 3.6-dev -> 3.6.8 (bugs only)
+ 3.7-dev -> 3.7.3 (non-breaking)
+ master -> 4.0.0
++ Committers will MERGE the PR forward to newer versions
++ ADD entry to the CHANGELOG.asciidoc for the targeted version
+ Do not reference a JIRA number there
++ ADD JIRA number to title and link in description
++ PRs requires 3 +1s from committers OR
+ 1 +1 and 7 day wait to merge.
++ MORE details: https://s.apache.org/rtnal
+-->
\ No newline at end of file
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 2a10258..f70c1c1 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,9 +26,16 @@
This release also includes changes from <<release-3-6-8, 3.6.8>>.
* Refactored mutation events registration by moving reusable code from relevant steps to `EventUtil`
-* Open `NoOpBarrierStep` for extensibility (removed `final` keyword)
+* Open `NoOpBarrierStep` for extensibility (removed `final` keyword).
* Deprecated public constructor for `SeedStrategy` in favor of builder pattern to be consistent with other strategies.
-* Allow specifying a customized Spark app name
+* Allow specifying a customized Spark app name.
+* Added getter method to `CoinStep` for its probability field.
+* Attempted to detect JDK version for Gremlin Console to avoid problems with Java 17 if `neo4j-gremlin` is used.
+* Fixed so that `TrimGlobalStep` and `TrimLocalStep` have the same character control handling as `Ltrim` and `Rtrim`
+* Fix a bug in `MaxLocalStep`, `MinLocalStep`, `MeanLocalStep` and `SumLocalStep` that it throws `NoSuchElementException` when encounters an empty iterator as input.
+* Fix cases where Map keys of incomparable types could panic in `gremlin-go`.
+* Fixed an issue where missing necessary parameters for logging, resulting in '%!x(MISSING)' output in `gremlin-go`.
+* Added getter method to `ConcatStep`, `ConjoinStep`, `SplitGlobalStep` and `SplitLocalStep` for their private fields.
[[release-3-7-2]]
=== TinkerPop 3.7.2 (April 8, 2024)
@@ -98,7 +105,7 @@
* Moved some TinkerGraph specific transaction tests from `TransactionMultiThreadedTest` to `TinkerTransactionGraphTest`
* Fixed incorrect read operations in some cases for `TinkerTransactionGraph`.
* Updated JavaScript tests to check equality on only id and class when comparing elements for consistency with other GLVs.
-* Improved performance for Element comparison by comparing hashCode() prior to doing more expensive checks.
+* Improved performance for `Element` comparison by comparing hashCode() prior to doing more expensive checks.
==== Bugs
@@ -322,7 +329,12 @@
[[release-3-6-8]]
=== TinkerPop 3.6.8 (NOT OFFICIALLY RELEASED YET)
+* Fixed a bug in GremlinServer not properly propagating arguments when authentication is enabled.
* Fixed bug in Java driver where connection pool was not removing dead connections under certain error conditions.
+* Raised handshake exceptions for Java driver for `NoHostAvailableException` situations.
+* The default logging level for Gremlin Console in Windows is set to the same WARN level as for Linux.
+* Updated to Docker Compose V2 with `docker-compose` changed to `docker compose` in pom and script files.
+* Add command line option `-l` to change logging level for Gremlin Console in Windows.
[[release-3-6-7]]
=== TinkerPop 3.6.7 (April 8, 2024)
diff --git a/docker/build.sh b/docker/build.sh
index 1b299d5..d495ff5 100755
--- a/docker/build.sh
+++ b/docker/build.sh
@@ -106,7 +106,7 @@
function check_status {
status=$?
- [ "$1" == "down" ] && docker-compose down
+ [ "$1" == "down" ] && docker compose down
popd > /dev/null
[ $status -ne 0 ] && exit $status
}
@@ -128,7 +128,7 @@
check_status
if [ -n "${RUN_TESTS}" ]; then
- # If testing, then build base server which is required by the following docker-compose.
+ # If testing, then build base server which is required by the following docker compose.
pushd ${ABS_PROJECT_HOME}/gremlin-server > /dev/null
docker build -f ./Dockerfile --build-arg GREMLIN_SERVER_DIR=target/apache-tinkerpop-gremlin-server-${GREMLIN_SERVER}-standalone -t tinkerpop/gremlin-server:${GREMLIN_SERVER} .
check_status
@@ -136,7 +136,7 @@
if [ -n "${INCLUDE_GO}" ] && [ -n "${RUN_TESTS}" ]; then
pushd ${ABS_PROJECT_HOME}/gremlin-go > /dev/null
- docker-compose up --build --exit-code-from gremlin-go-integration-tests
+ docker compose up --build --exit-code-from gremlin-go-integration-tests
check_status "down"
fi
@@ -145,19 +145,19 @@
export BUILD_DIR=$(pwd)/target/python3/
mkdir -p ${BUILD_DIR}
cp -r ./src/main/python/* ${BUILD_DIR}
- docker-compose up --build --abort-on-container-exit gremlin-server-test-python gremlin-python-integration-tests
+ docker compose up --build --abort-on-container-exit gremlin-server-test-python gremlin-python-integration-tests
check_status "down"
fi
if [ -n "${INCLUDE_DOTNET}" ] && [ -n "${RUN_TESTS}" ]; then
pushd ${ABS_PROJECT_HOME}/gremlin-dotnet/test > /dev/null
- docker-compose up --build --exit-code-from gremlin-dotnet-integration-tests
+ docker compose up --build --exit-code-from gremlin-dotnet-integration-tests
check_status "down"
fi
if [ -n "${INCLUDE_JAVASCRIPT}" ] && [ -n "${RUN_TESTS}" ]; then
pushd ${ABS_PROJECT_HOME}/gremlin-javascript/src/main/javascript/gremlin-javascript > /dev/null
- docker-compose up --build --exit-code-from gremlin-js-integration-tests
+ docker compose up --build --exit-code-from gremlin-js-integration-tests
check_status "down"
fi
diff --git a/docs/src/dev/developer/development-environment.asciidoc b/docs/src/dev/developer/development-environment.asciidoc
index 3026abe..d9f8ab4 100644
--- a/docs/src/dev/developer/development-environment.asciidoc
+++ b/docs/src/dev/developer/development-environment.asciidoc
@@ -352,7 +352,7 @@
Docker allows you to test the driver without installing any dependencies. The following command can be used to run docker:
[source,text]
-docker-compose up --exit-code-from gremlin-go-integration-tests
+docker compose up --exit-code-from gremlin-go-integration-tests
See the <<release-environment,Release Environment>> section for more information on release manager configurations.
@@ -635,12 +635,12 @@
* Run Maven commands, e.g. `mvn clean install` inside of project folder e.g. `tinkerpop/gremlin-go`, or `mvn clean install -pl gremlin-go`
inside of `tinkerpop` (platform-agnostic - recommended)
-* Add `GREMLIN_SERVER=<server-image-version>` and `HOME=<user-home-directory>` to an `.env` file inside project folder and run `docker-compose up --exit-code-from gremlin-go-integration-tests` (Platform-agnostic).
-* Run `GREMLIN_SERVER=<server-image-version> docker-compose up --exit-code-from gremlin-go-integration-tests` in Unix/Linux.
-* Run `$env:GREMLIN_SERVER="<server-image-version>";$env:HOME=$env:USERPROFILE;docker-compose up --exit-code-from gremlin-go-integration-tests` in Windows PowerShell.
+* Add `GREMLIN_SERVER=<server-image-version>` and `HOME=<user-home-directory>` to an `.env` file inside project folder and run `docker compose up --exit-code-from gremlin-go-integration-tests` (Platform-agnostic).
+* Run `GREMLIN_SERVER=<server-image-version> docker compose up --exit-code-from gremlin-go-integration-tests` in Unix/Linux.
+* Run `$env:GREMLIN_SERVER="<server-image-version>";$env:HOME=$env:USERPROFILE;docker compose up --exit-code-from gremlin-go-integration-tests` in Windows PowerShell.
-You should see exit code 0 upon successful completion of the test suites. Run `docker-compose down` to remove the
-service containers (not needed if you executed Maven commands or `run.sh`), or `docker-compose down --rmi all` to
+You should see exit code 0 upon successful completion of the test suites. Run `docker compose down` to remove the
+service containers (not needed if you executed Maven commands or `run.sh`), or `docker compose down --rmi all` to
remove the service containers while deleting all used images.
Note for running docker with MacOS on ARM processors: Docker's performance is extremely poor on ARM Mac's in its
diff --git a/docs/src/dev/developer/release.asciidoc b/docs/src/dev/developer/release.asciidoc
index 6a5e525..9812c79 100644
--- a/docs/src/dev/developer/release.asciidoc
+++ b/docs/src/dev/developer/release.asciidoc
@@ -324,6 +324,7 @@
.. `bin/process-docs.sh` and validate the generated `SNAPSHOT` documentation locally and then `bin/publish-docs.sh <username>`
.. Commit and push the `SNAPSHOT` changes to git
. Examine the `future.asciidoc` and update the "Roadmap" as needed.
+. Update the version numbers in `pull_request_template.md`.
. Send email to advise that code freeze is lifted.
. Consider the changes made to Gremlin and determine if the community needs to organize a PR to [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/gremlin) to keep TypeScript up to date.
. Ensure that the GLV examples compile and run with the latest image and dependencies: `bin/run-examples.sh`.
diff --git a/docs/src/reference/implementations-neo4j.asciidoc b/docs/src/reference/implementations-neo4j.asciidoc
index e15b008..cf61846 100644
--- a/docs/src/reference/implementations-neo4j.asciidoc
+++ b/docs/src/reference/implementations-neo4j.asciidoc
@@ -23,6 +23,9 @@
be dropped from future versions of TinkerPop if compatibility cannot reasonably be maintained. Alternative TinkerPop
enabled graph providers can be found on the link:https://tinkerpop.apache.org/providers.html[TinkerPop site].
+WARNING: Neo4j-Gremlin can work with JDK17, but requires the use of the `--add-opens` flag to be provided to the JVM
+as follows: `--add-opens=java.base/sun.nio.ch=ALL-UNNAMED`.
+
[source,xml]
----
<dependency>
diff --git a/docs/src/upgrade/release-3.7.x.asciidoc b/docs/src/upgrade/release-3.7.x.asciidoc
index 9ddac7c..4dda8ba 100644
--- a/docs/src/upgrade/release-3.7.x.asciidoc
+++ b/docs/src/upgrade/release-3.7.x.asciidoc
@@ -30,7 +30,6 @@
=== Upgrading for Users
-
== TinkerPop 3.7.2
*Release Date: April 8, 2024*
@@ -38,18 +37,6 @@
Please see the link:https://github.com/apache/tinkerpop/blob/3.7.2/CHANGELOG.asciidoc#release-3-7-2[changelog] for a
complete list of all the modifications that are part of this release.
-=== Upgrading for Users
-
-==== Notice: Renaming `none()` step to `discard()` in 4.0.0
-`none()`, which is primarily used by `iterate()` to discard traversal results in remote contexts, will be renamed to
-`discard()` in release 4.0.0.
-
-=== Upgrading for Providers
-
-==== Notice: Renaming NoneStep to DiscardStep in 4.0.0
-NoneStep, which is primarily used by `iterate()` to discard traversal results in remote contexts, will be renamed to
-DiscardStep in release 4.0.0 to make room for a list filtering NoneStep.
-
== TinkerPop 3.7.1
*Release Date: November 20, 2023*
@@ -59,8 +46,9 @@
=== Upgrading for Users
==== String Manipulation Steps
-This version introduces the following new string manipulation steps `asString()`, `length()`, `toLower()`, `toUpper()`, `trim()`,
-`lTrim()`, `rTrim()`, `reverse()`, `replace()`, `split()`, `substring()`, and `format()`, as well as modifications to the `concat()` step introduced in 3.7.0.
+This version introduces the following new string manipulation steps `asString()`, `length()`, `toLower()`, `toUpper()`,
+`trim()`, `lTrim()`, `rTrim()`, `reverse()`, `replace()`, `split()`, `substring()`, and `format()`, as well as
+modifications to the `concat()` step introduced in 3.7.0.
===== Updates to String Step concat():
Concat has been modified to take traversal varargs instead of a single traversal. Users no longer have to chain
@@ -73,7 +61,10 @@
==>markoknowsjosh
----
-A notable breaking change from 3.7.0 is that we have output order of `inject()` as a child of `concat()` to be consistent with other parent steps. Any 3.7.0 uses of `concat(inject(X))` should change to `concat(constant(X))` to retain the old semantics.
+A notable breaking change from 3.7.0 is that we have output order of `inject()` as a child of `concat()` to be
+consistent with other parent steps. Any 3.7.0 uses of `concat(inject(X))` should change to `concat(constant(X))` to
+retain the old semantics.
+
[source,text]
----
// 3.7.0
diff --git a/gremlin-console/src/main/bin/gremlin-java8.bat b/gremlin-console/src/main/bin/gremlin-java8.bat
index a80aa6f..227633f 100644
--- a/gremlin-console/src/main/bin/gremlin-java8.bat
+++ b/gremlin-console/src/main/bin/gremlin-java8.bat
@@ -40,9 +40,20 @@
)
cd ..
+set GREMLIN_LOG_LEVEL=WARN
+
+:: Process options
+
+:parse
+IF "%~1"=="" GOTO endparse
+IF "%~1"=="-l" set GREMLIN_LOG_LEVEL=%~2
+SHIFT
+GOTO parse
+:endparse
+
:: workaround for https://issues.apache.org/jira/browse/GROOVY-6453
set JAVA_OPTIONS=-Xms32m -Xmx512m -Djline.terminal=none
:: Launch the application
-java %JAVA_OPTIONS% %JAVA_ARGS% -cp "%CONSOLE_JARS%" org.apache.tinkerpop.gremlin.console.Console %*
+java %JAVA_OPTIONS% %JAVA_ARGS% -cp "%CONSOLE_JARS%" "-Dlogback.configurationFile=conf/logback.xml" "-Dgremlin.logback.level=%GREMLIN_LOG_LEVEL%" org.apache.tinkerpop.gremlin.console.Console %*
diff --git a/gremlin-console/src/main/bin/gremlin.bat b/gremlin-console/src/main/bin/gremlin.bat
index 021e37b..739635e 100644
--- a/gremlin-console/src/main/bin/gremlin.bat
+++ b/gremlin-console/src/main/bin/gremlin.bat
@@ -34,11 +34,22 @@
cd ..
+set GREMLIN_LOG_LEVEL=WARN
+
+:: Process options
+
+:parse
+IF "%~1"=="" GOTO endparse
+IF "%~1"=="-l" set GREMLIN_LOG_LEVEL=%~2
+SHIFT
+GOTO parse
+:endparse
+
:: workaround for https://issues.apache.org/jira/browse/GROOVY-6453
set JAVA_OPTIONS=-Xms32m -Xmx512m -Djline.terminal=none
:: Launch the application
-java %JAVA_OPTIONS% %JAVA_ARGS% -cp "%LIBDIR%\*;%EXTDIR%;" org.apache.tinkerpop.gremlin.console.Console %*
+java %JAVA_OPTIONS% %JAVA_ARGS% -cp "%LIBDIR%\*;%EXTDIR%;" "-Dlogback.configurationFile=conf/logback.xml" "-Dgremlin.logback.level=%GREMLIN_LOG_LEVEL%" org.apache.tinkerpop.gremlin.console.Console %*
set CLASSPATH=%OLD_CLASSPATH%
\ No newline at end of file
diff --git a/gremlin-console/src/main/bin/gremlin.sh b/gremlin-console/src/main/bin/gremlin.sh
index 9fbd8a0..36dcb4d 100755
--- a/gremlin-console/src/main/bin/gremlin.sh
+++ b/gremlin-console/src/main/bin/gremlin.sh
@@ -108,6 +108,12 @@
set -x
fi
+# Try to detect JDK version and add specific flag for JDK 17 to allow use of neo4j-gremlin
+JAVA_VERSION=$($JAVA -version 2>&1 | awk -F '"' '/version/ {print $2}')
+if [[ "$JAVA_VERSION" == 17* ]]; then
+ JVM_OPTS+=( "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" )
+fi
+
# Start the JVM, execute the application, and return its exit code
# shellcheck disable=SC2068
exec $JAVA ${JVM_OPTS[@]} org.apache.tinkerpop.gremlin.console.Console "$@"
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
index a7d86cb..e4a44ab 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
@@ -46,6 +46,10 @@
random.setSeed(seed);
}
+ public double getProbability() {
+ return this.probability;
+ }
+
@Override
protected boolean filter(final Traverser.Admin<S> traverser) {
long newBulk = 0l;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConcatStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConcatStep.java
index 04811d8..86d737f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConcatStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConcatStep.java
@@ -120,6 +120,14 @@
return this.isNullString? null : sb.toString();
}
+ public List<String> getConcatStrings() {
+ return this.concatStrings;
+ }
+
+ public String getStringArgsResult() {
+ return this.stringArgsResult;
+ }
+
@Override
public Set<TraverserRequirement> getRequirements() {
return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
index 0f38739..ce6818b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
@@ -66,6 +66,10 @@
}
}
+ public String getDelimiter() {
+ return this.delimiter;
+ }
+
@Override
public Set<TraverserRequirement> getRequirements() { return Collections.singleton(TraverserRequirement.OBJECT); }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimGlobalStep.java
index 84dbd5c..8ce2104 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimGlobalStep.java
@@ -25,6 +25,8 @@
import java.util.Collections;
import java.util.Set;
+import static org.apache.tinkerpop.gremlin.process.traversal.step.util.StringLocalStep.getTrimmedString;
+
/**
* Reference implementation for lTrim() step, a mid-traversal step which returns a string with leading
* whitespace removed. Null values are not processed and remain as null when returned.
@@ -49,15 +51,7 @@
}
// we will pass null values to next step
- if (null == item)
- return null;
-
- int i = 0;
- while (i < ((String) item).length() && Character.isWhitespace(((String) item).charAt(i))) {
- i++;
- }
-
- return (E) ((String) item).substring(i);
+ return (E) getTrimmedString((String) item, true, false);
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimLocalStep.java
index 1592067..db12f62 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimLocalStep.java
@@ -51,18 +51,9 @@
@Override
protected E applyStringOperation(String item) {
- return (E) item.substring(getIdx(item));
+ return (E) getTrimmedString(item, true, false);
}
@Override
public String getStepName() { return "lTrim(local)"; }
-
- private int getIdx(final String str) {
- int idx = 0;
- while (idx < str.length() && Character.isWhitespace(str.charAt(idx))) {
- idx++;
- }
- return idx;
- }
-
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
index e4ad8b4..93b95e4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
@@ -21,11 +21,11 @@
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import java.util.Collections;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import java.util.Set;
import static org.apache.tinkerpop.gremlin.util.NumberHelper.max;
@@ -34,23 +34,26 @@
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Daniel Kuppitz (http://gremlin.guru)
*/
-public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> extends ScalarMapStep<S, E> {
+public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> extends MapStep<S, E> {
public MaxLocalStep(final Traversal.Admin traversal) {
super(traversal);
}
@Override
- protected E map(final Traverser.Admin<S> traverser) {
- final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
- if (iterator.hasNext()) {
- Comparable result = iterator.next();
- while (iterator.hasNext()) {
- result = max(iterator.next(), result);
+ protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
+ while (true) {
+ final Traverser.Admin<S> traverser = this.starts.next();
+ final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
+
+ if (iterator.hasNext()) {
+ Comparable result = iterator.next();
+ while (iterator.hasNext()) {
+ result = max(iterator.next(), result);
+ }
+ return traverser.split((E) result, this);
}
- return (E) result;
}
- throw FastNoSuchElementException.instance();
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
index 7a5abe7..d6e30e3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
@@ -18,44 +18,49 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal.step.map;
-import org.apache.tinkerpop.gremlin.util.NumberHelper;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import java.util.Collections;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import java.util.Set;
+import static org.apache.tinkerpop.gremlin.util.NumberHelper.add;
+import static org.apache.tinkerpop.gremlin.util.NumberHelper.div;
+
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Daniel Kuppitz (http://gremlin.guru)
*/
-public final class MeanLocalStep<E extends Number, S extends Iterable<E>> extends ScalarMapStep<S, Number> {
+public final class MeanLocalStep<E extends Number, S extends Iterable<E>> extends MapStep<S, E> {
public MeanLocalStep(final Traversal.Admin traversal) {
super(traversal);
}
@Override
- protected Number map(final Traverser.Admin<S> traverser) {
- final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
- if (iterator.hasNext()) {
- // forward the iterator to the first non-null or return null
- E result = untilNonNull(iterator);
- Long counter = 1L;
- while (iterator.hasNext()) {
- final Number n = iterator.next();
- if (n != null) {
- result = (E) NumberHelper.add(result, n);
- counter++;
+ protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
+ while (true) {
+ final Traverser.Admin<S> traverser = this.starts.next();
+ final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
+
+ if (iterator.hasNext()) {
+ // forward the iterator to the first non-null or return null
+ E result = untilNonNull(iterator);
+ Long counter = 1L;
+ while (iterator.hasNext()) {
+ final Number n = iterator.next();
+ if (n != null) {
+ result = (E) add(result, n);
+ counter++;
+ }
}
+ return traverser.split((E) div(result, counter, true), this);
}
- return NumberHelper.div(result, counter, true);
}
- throw FastNoSuchElementException.instance();
}
private E untilNonNull(final Iterator<E> itty) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
index 0781d4a..cf29a73 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
@@ -21,11 +21,11 @@
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import java.util.Collections;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import java.util.Set;
import static org.apache.tinkerpop.gremlin.util.NumberHelper.min;
@@ -34,23 +34,26 @@
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Daniel Kuppitz (http://gremlin.guru)
*/
-public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> extends ScalarMapStep<S, E> {
+public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> extends MapStep<S, E> {
public MinLocalStep(final Traversal.Admin traversal) {
super(traversal);
}
@Override
- protected E map(final Traverser.Admin<S> traverser) {
- final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
- if (iterator.hasNext()) {
- Comparable result = iterator.next();
- while (iterator.hasNext()) {
- result = min(iterator.next(), result);
+ protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
+ while (true) {
+ final Traverser.Admin<S> traverser = this.starts.next();
+ final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
+
+ if (iterator.hasNext()) {
+ Comparable result = iterator.next();
+ while (iterator.hasNext()) {
+ result = min(iterator.next(), result);
+ }
+ return traverser.split((E) result, this);
}
- return (E) result;
}
- throw FastNoSuchElementException.instance();
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimGlobalStep.java
index aae0c50..3e52446 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimGlobalStep.java
@@ -25,6 +25,8 @@
import java.util.Collections;
import java.util.Set;
+import static org.apache.tinkerpop.gremlin.process.traversal.step.util.StringLocalStep.getTrimmedString;
+
/**
* Reference implementation for rTrim() step, a mid-traversal step which a string with trailing
* whitespace removed. Null values are not processed and remain as null when returned.
@@ -49,15 +51,7 @@
}
// we will pass null values to next step
- if (null == item)
- return null;
-
- int i = ((String) item).length() - 1;
- while (i >= 0 && Character.isWhitespace(((String) item).charAt(i))) {
- i--;
- }
-
- return (E) ((String) item).substring(0,i+1);
+ return (E) getTrimmedString((String) item, false, true);
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimLocalStep.java
index 1b1182d..ee7c39c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimLocalStep.java
@@ -37,18 +37,9 @@
@Override
protected E applyStringOperation(String item) {
- return (E) item.substring(0,getEndIdx(item)+1);
+ return (E) getTrimmedString(item, false, true);
}
@Override
public String getStepName() { return "rTrim(local)"; }
-
- private int getEndIdx(final String str) {
- int idx = str.length() - 1;
- while (idx >= 0 && Character.isWhitespace(str.charAt(idx))) {
- idx--;
- }
- return idx;
- }
-
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitGlobalStep.java
index 2465e72..14e886e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitGlobalStep.java
@@ -60,6 +60,10 @@
return null == item? null : (E) Arrays.asList(StringUtils.splitByWholeSeparator((String) item, this.separator));
}
+ public String getSeparator() {
+ return this.separator;
+ }
+
@Override
public Set<TraverserRequirement> getRequirements() {
return Collections.singleton(TraverserRequirement.OBJECT);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java
index 61a9901..5d638c7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java
@@ -56,6 +56,10 @@
@Override
public String getStepName() { return "split(local)"; }
+ public String getSeparator() {
+ return this.separator;
+ }
+
@Override
public int hashCode() {
int result = super.hashCode();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
index 92b9796..69fd944 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
@@ -18,39 +18,47 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal.step.map;
-import org.apache.tinkerpop.gremlin.util.NumberHelper;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import java.util.Collections;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import java.util.Set;
+import static org.apache.tinkerpop.gremlin.util.NumberHelper.add;
+
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Daniel Kuppitz (http://gremlin.guru)
*/
-public final class SumLocalStep<E extends Number, S extends Iterable<E>> extends ScalarMapStep<S, E> {
+public final class SumLocalStep<E extends Number, S extends Iterable<E>> extends MapStep<S, E> {
public SumLocalStep(final Traversal.Admin traversal) {
super(traversal);
}
@Override
- protected E map(final Traverser.Admin<S> traverser) {
- final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
- if (iterator.hasNext()) {
- // forward the iterator to the first non-null or return null
- Number result = untilNonNull(iterator);
- while (iterator.hasNext()) {
- result = NumberHelper.add(result, iterator.next());
+ protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
+ while (true) {
+ final Traverser.Admin<S> traverser = this.starts.next();
+ final Iterator<E> iterator = IteratorUtils.asIterator(traverser.get());
+
+ if (iterator.hasNext()) {
+ // forward the iterator to the first non-null or return null
+ E result = untilNonNull(iterator);
+ while (iterator.hasNext()) {
+ final Number n = iterator.next();
+ if (n != null) {
+ result = (E) add(result, n);
+ }
+ }
+ return traverser.split(result, this);
}
- return (E) result;
+
}
- throw FastNoSuchElementException.instance();
}
private E untilNonNull(final Iterator<E> itty) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimGlobalStep.java
index 72f2a41..a543e2b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimGlobalStep.java
@@ -25,6 +25,8 @@
import java.util.Collections;
import java.util.Set;
+import static org.apache.tinkerpop.gremlin.process.traversal.step.util.StringLocalStep.getTrimmedString;
+
/**
* Reference implementation for trim() step, a mid-traversal step which returns a string with leading and trailing
* whitespace removed. Null values are not processed and remain as null when returned.
@@ -47,9 +49,7 @@
throw new IllegalArgumentException(
String.format("The trim() step can only take string as argument, encountered %s", item.getClass()));
}
-
- // we will pass null values to next step
- return null == item? null : (E) ((String) item).trim();
+ return (E) getTrimmedString((String) item, true, true);
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimLocalStep.java
index dd6752f..4b35734 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimLocalStep.java
@@ -37,7 +37,7 @@
@Override
protected E applyStringOperation(String item) {
- return (E) item.trim();
+ return (E) getTrimmedString(item, true, true);
}
@Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/FailStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/FailStep.java
index 48741f8..1eb3f4b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/FailStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/FailStep.java
@@ -48,6 +48,10 @@
this.metadata = metadata;
}
+ public String getMessage() {
+ return message;
+ }
+
@Override
protected void sideEffect(final Traverser.Admin<S> traverser) {
throw new FailException(traversal, traverser, message, metadata);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StringLocalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StringLocalStep.java
index d27a454..37f4a69 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StringLocalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StringLocalStep.java
@@ -72,6 +72,27 @@
return Collections.singleton(TraverserRequirement.OBJECT);
}
+ public static String getTrimmedString(final String s, final boolean lTrim, final boolean rTrim) {
+ if (s == null) {
+ return null;
+ }
+
+ int start = 0;
+ if (lTrim) {
+ while (start < s.length() && Character.isWhitespace(s.charAt(start))) {
+ start++;
+ }
+ }
+
+ int end = s.length() - 1;
+ if (rTrim) {
+ while (end >= start && Character.isWhitespace(s.charAt(end))) {
+ end--;
+ }
+ }
+ return s.substring(start, end + 1);
+ }
+
protected abstract E applyStringOperation(final String item);
protected abstract String getStepName();
diff --git a/gremlin-dotnet/docker-compose.yml b/gremlin-dotnet/docker-compose.yml
index 7c84aa0..7f5efab 100644
--- a/gremlin-dotnet/docker-compose.yml
+++ b/gremlin-dotnet/docker-compose.yml
@@ -15,8 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-version: "3.8"
-
services:
gremlin-server-test-dotnet:
diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
index 2efe138..2ba0c61 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
+++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
@@ -74,8 +74,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
- <PackageReference Include="System.Text.Json" Version="8.0.3" />
- <PackageReference Include="Polly" Version="8.4.0" />
+ <PackageReference Include="System.Text.Json" Version="8.0.4" />
+ <PackageReference Include="Polly" Version="8.4.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index b10a2db..4be4287 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -749,7 +749,8 @@
{"g_injectXa_null_bX_intersectXa_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Intersect(p["xx2"])}},
{"g_injectXa_null_bX_intersectXa_null_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Intersect(p["xx2"])}},
{"g_injectX3_threeX_intersectXfive_three_7X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Intersect(p["xx2"])}},
- {"g_injectX__feature___test__nullX_lTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(" feature"," one test",null,""," ").LTrim()}},
+ {"g_injectX__feature___test__nullX_lTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(" feature"," one test",null,""," ","\u3000abc","abc\u3000","\u3000abc\u3000","\u3000\u3000").LTrim()}},
+ {"g_injectX__feature___test__nullX_lTrimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(new List<object> {" feature ", " one test ", null, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"}).LTrim<object>(Scope.Local)}},
{"g_injectX__feature__X_lTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(" feature ").LTrim()}},
{"g_injectXListXa_bXX_lTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).LTrim()}},
{"g_injectXListX1_2XX_lTrimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).LTrim<object>(Scope.Local)}},
@@ -834,6 +835,7 @@
{"g_V_repeatXbothX_timesX5X_age_max", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat(__.Both()).Times(5).Values<object>("age").Max<object>()}},
{"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Group<object,object>().By("name").By(__.BothE().Values<object>("weight").Max<object>())}},
{"g_VX1X_valuesXageX_maxXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Values<object>("age").Max<object>(Scope.Local)}},
+ {"g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_maxXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Union<object>(__.Values<object>("age"),__.OutE().Values<object>("weight")).Fold()).Max<object>(Scope.Local)}},
{"g_V_age_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Mean<object>()}},
{"g_V_foo_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Mean<object>()}},
{"g_V_age_fold_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Fold().Mean<object>(Scope.Local)}},
@@ -850,6 +852,7 @@
{"g_injectXnull_10_20_nullX_mean", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null,p["xx1"],p["xx2"],null).Mean<object>()}},
{"g_injectXlistXnull_10_20_nullXX_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Mean<object>(Scope.Local)}},
{"g_VX1X_valuesXageX_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Values<object>("age").Mean<object>(Scope.Local)}},
+ {"g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_meanXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Union<object>(__.Values<object>("age"),__.OutE().Values<object>("weight")).Fold()).Mean<object>(Scope.Local)}},
{"g_injectXnullX_mergeXinjectX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Merge(__.Inject(1))}},
{"g_V_valuesXnameX_mergeXV_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Merge(__.V().Fold())}},
{"g_V_fold_mergeXconstantXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold().Merge(__.Constant<object>(null))}},
@@ -995,6 +998,7 @@
{"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").Group<object,object>().By("name").By(__.BothE().Values<object>("weight").Min<object>())}},
{"g_V_foo_injectX9999999999X_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Inject(p["xx1"]).Min<object>()}},
{"g_VX1X_valuesXageX_minXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Values<object>("age").Min<object>(Scope.Local)}},
+ {"g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_minXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Union<object>(__.Values<object>("age"),__.OutE().Values<object>("weight")).Fold()).Min<object>(Scope.Local)}},
{"g_V_name_order", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order()}},
{"g_V_name_order_byXa1_b1X_byXb2_a2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().By((IComparator) p["c1"]).By((IComparator) p["c2"])}},
{"g_V_order_byXname_ascX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By("name",Order.Asc).Values<object>("name")}},
@@ -1075,7 +1079,8 @@
{"g_V_hasXageX_propertiesXage_nameX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("age","name").Value<object>()}},
{"g_V_propertiesXname_age_nullX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>("name","age",null).Value<object>()}},
{"g_V_valuesXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name","age",null)}},
- {"g_injectX__feature___test__nullX_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("feature ","one test ",null,""," ").RTrim()}},
+ {"g_injectX__feature___test__nullX_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("feature ","one test ",null,""," ","\u3000abc","abc\u3000","\u3000abc\u3000","\u3000\u3000").RTrim()}},
+ {"g_injectX__feature___test__nullX_rTrimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(new List<object> {" feature ", " one test ", null, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"}).RTrim<object>(Scope.Local)}},
{"g_injectX__feature__X_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(" feature ").RTrim()}},
{"g_injectXListXa_bXX_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).RTrim()}},
{"g_injectXListX1_2XX_rTrimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).RTrim<object>(Scope.Local)}},
@@ -1212,6 +1217,7 @@
{"g_injectXnull_10_5_nullX_sum", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null,p["xx1"],p["xx2"],null).Sum<object>()}},
{"g_injectXlistXnull_10_5_nullXX_sumXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Sum<object>(Scope.Local)}},
{"g_VX1X_valuesXageX_sumXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Values<object>("age").Sum<object>(Scope.Local)}},
+ {"g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_sumXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Union<object>(__.Values<object>("age"),__.OutE().Values<object>("weight")).Fold()).Sum<object>(Scope.Local)}},
{"g_injectXfeature_test_nullX_toLower", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("FEATURE","tESt",null).ToLower()}},
{"g_injectXfeature_test_nullX_toLowerXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).ToLower<object>(Scope.Local)}},
{"g_injectXListXa_bXX_toLower", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).ToLower()}},
@@ -1225,7 +1231,8 @@
{"g_V_valuesXnameX_toUpper", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").ToUpper()}},
{"g_V_valuesXnameX_toUpperXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").ToUpper<object>(Scope.Local)}},
{"g_V_valuesXnameX_order_fold_toUpperXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Fold().ToUpper<object>(Scope.Local)}},
- {"g_injectX__feature___test__nullX_trim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(" feature "," one test ",null,""," ").Trim()}},
+ {"g_injectX__feature___test__nullX_trim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(" feature "," one test ",null,""," ","\u3000abc","abc\u3000","\u3000abc\u3000","\u3000\u3000").Trim()}},
+ {"g_injectX__feature___test__nullX_trimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(new List<object> {" feature ", " one test ", null, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"}).Trim<object>(Scope.Local)}},
{"g_injectXListXa_bXX_trim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Trim()}},
{"g_injectXListX1_2XX_trimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Trim<object>(Scope.Local)}},
{"g_V_valuesXnameX_trim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name"," marko ").Property("age",29).As("marko").AddV("person").Property("name"," vadas ").Property("age",27).As("vadas").AddV("software").Property("name"," lop").Property("lang","java").As("lop").AddV("person").Property("name","josh ").Property("age",32).As("josh").AddV("software").Property("name"," ripple ").Property("lang","java").As("ripple").AddV("person").Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight",0.5).AddE("knows").From("marko").To("josh").Property("weight",1.0).AddE("created").From("marko").To("lop").Property("weight",0.4).AddE("created").From("josh").To("ripple").Property("weight",1.0).AddE("created").From("josh").To("lop").Property("weight",0.4).AddE("created").From("peter").To("lop").Property("weight",0.2), (g,p) =>g.V().Values<object>("name").Trim()}},
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
index b867b67..4e923b7 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
@@ -19,8 +19,8 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.8.1" />
- <PackageReference Include="xunit" Version="2.8.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
+ <PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="YamlDotNet" Version="12.2.0" />
</ItemGroup>
diff --git a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj
index afb832b..6e6013d 100644
--- a/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj
+++ b/gremlin-dotnet/test/Gremlin.Net.Template.IntegrationTest/Gremlin.Net.Template.IntegrationTest.csproj
@@ -7,8 +7,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
- <PackageReference Include="xunit" Version="2.8.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.8.1" />
+ <PackageReference Include="xunit" Version="2.9.0" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<ItemGroup>
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj
index d919ac8..4681f19 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Gremlin.Net.UnitTest.csproj
@@ -15,8 +15,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.8.1" />
- <PackageReference Include="xunit" Version="2.8.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
+ <PackageReference Include="xunit" Version="2.9.0" />
</ItemGroup>
<ItemGroup>
diff --git a/gremlin-dotnet/test/pom.xml b/gremlin-dotnet/test/pom.xml
index cc12323..e36e893 100644
--- a/gremlin-dotnet/test/pom.xml
+++ b/gremlin-dotnet/test/pom.xml
@@ -102,8 +102,9 @@
<!-- setting this env variable is needed to be cross-platform compatible -->
<HOME>${user.home}</HOME>
</environmentVariables>
- <executable>docker-compose</executable>
+ <executable>docker</executable>
<arguments>
+ <argument>compose</argument>
<argument>up</argument>
<argument>--build</argument>
<argument>--exit-code-from</argument>
@@ -120,8 +121,9 @@
<configuration>
<skip>${skipTests}</skip>
<!-- don't need to set env variables for container tear down -->
- <executable>docker-compose</executable>
+ <executable>docker</executable>
<arguments>
+ <argument>compose</argument>
<argument>down</argument>
</arguments>
</configuration>
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index 7ce5c40..b53f1cd 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
@@ -18,6 +18,7 @@
*/
package org.apache.tinkerpop.gremlin.driver;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakeException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.tinkerpop.gremlin.util.Tokens;
import org.slf4j.Logger;
@@ -557,7 +558,8 @@
private void throwNoHostAvailableException() {
final Throwable rootCause = ExceptionUtils.getRootCause(initializationFailure);
// allow the certain exceptions to propagate as a cause
- if (rootCause instanceof SSLException || rootCause instanceof ConnectException) {
+ if (rootCause instanceof SSLException || rootCause instanceof ConnectException ||
+ rootCause instanceof WebSocketClientHandshakeException) {
throw new NoHostAvailableException(initializationFailure);
} else {
throw new NoHostAvailableException();
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
index 4259e25..898f3b1 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
@@ -30,7 +30,9 @@
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
+import java.util.Iterator;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
@@ -48,7 +50,7 @@
*/
public class ProfilingApplication {
- private static final Random random = new Random();
+ private static final Random random = new Random(0); // Same seed to ensure consistent test runs.
private static final String[] scripts = new String[]{
"g.V()",
"g.V(1).out('knows')",
@@ -87,7 +89,7 @@
this.exercise = exercise;
}
- public long execute() throws Exception {
+ public long executeThroughput() throws Exception {
final AtomicInteger tooSlow = new AtomicInteger(0);
final Client client = cluster.connect();
@@ -130,16 +132,51 @@
}
}
+ public double executeLatency() throws Exception {
+ final Client client = cluster.connect();
+ final String executionId = "[" + executionName + "]";
+ try {
+ client.init();
+
+ final long start = System.nanoTime();
+ int size = 0;
+ final Iterator itr = client.submitAsync(script).get().iterator();
+ try {
+ while (true) {
+ itr.next();
+ size++;
+ }
+ } catch (NoSuchElementException nsee) {
+ ; // Expected as hasNext() not called to increase performance.
+ }
+ final long end = System.nanoTime();
+ final long total = (end - start);
+
+
+ final double totalSeconds = total / 1000000000d;
+ System.out.println(String.format(StringUtils.rightPad(executionId, 10) + "time: %s, result count: %s", StringUtils.rightPad(String.valueOf(totalSeconds), 7), StringUtils.rightPad(String.valueOf(size), 10)));
+ return totalSeconds;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ throw new RuntimeException(ex);
+ } finally {
+ client.close();
+ }
+ }
+
private String chooseScript() {
return scripts[random.nextInt(scripts.length - 1)];
}
+ public enum TestType { LATENCY, THROUGHPUT };
+
public static void main(final String[] args) {
final Map<String,Object> options = ElementHelper.asMap(args);
final boolean noExit = Boolean.parseBoolean(options.getOrDefault("noExit", "false").toString());
final int parallelism = Integer.parseInt(options.getOrDefault("parallelism", "16").toString());
final BasicThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern("profiler-%d").build();
final ExecutorService executor = Executors.newFixedThreadPool(parallelism, threadFactory);
+ final TestType testType = TestType.values()[(Integer.parseInt(options.getOrDefault("testType", "1").toString()) % TestType.values().length)];
final String host = options.getOrDefault("host", "localhost").toString();
final int minExpectedRps = Integer.parseInt(options.getOrDefault("minExpectedRps", "1000").toString());
@@ -155,7 +192,7 @@
final int maxInProcessPerConnection = Integer.parseInt(options.getOrDefault("maxInProcessPerConnection", "64").toString());
final int minInProcessPerConnection = Integer.parseInt(options.getOrDefault("minInProcessPerConnection", "16").toString());
final int maxWaitForConnection = Integer.parseInt(options.getOrDefault("maxWaitForConnection", "3000").toString());
- final int workerPoolSize = Integer.parseInt(options.getOrDefault("workerPoolSize", "2").toString());
+ final int workerPoolSize = Integer.parseInt(options.getOrDefault("workerPoolSize", Runtime.getRuntime().availableProcessors() * 2).toString());
final int tooSlowThreshold = Integer.parseInt(options.getOrDefault("tooSlowThreshold", "125").toString());
final String channelizer = options.getOrDefault("channelizer", Channelizer.WebSocketChannelizer.class.getName()).toString();
final String serializer = options.getOrDefault("serializer", Serializers.GRAPHBINARY_V1.name()).toString();
@@ -177,6 +214,12 @@
.workerPoolSize(workerPoolSize).create();
try {
+ if (TestType.LATENCY == testType) {
+ System.out.println("-----------------------LATENCY TEST SELECTED----------------------");
+ } else {
+ System.out.println("---------------------THROUGHPUT TEST SELECTED---------------------");
+ }
+
if (exercise) {
System.out.println("--------------------------INITIALIZATION--------------------------");
final Client client = cluster.connect();
@@ -189,43 +232,72 @@
System.out.println("Modern graph loaded");
}
- final Object fileName = options.get("store");
- final File f = null == fileName ? null : new File(fileName.toString());
- if (f != null && f.length() == 0) {
- try (final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(f, true)))) {
- writer.println("parallelism\tnioPoolSize\tminConnectionPoolSize\tmaxConnectionPoolSize\tminSimultaneousUsagePerConnection\tmaxSimultaneousUsagePerConnection\tminInProcessPerConnection\tmaxInProcessPerConnection\tworkerPoolSize\trequestPerSecond");
+ if (TestType.THROUGHPUT == testType) {
+ final Object fileName = options.get("store");
+ final File f = null == fileName ? null : new File(fileName.toString());
+ if (f != null && f.length() == 0) {
+ try (final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(f, true)))) {
+ writer.println("parallelism\tnioPoolSize\tminConnectionPoolSize\tmaxConnectionPoolSize\tminSimultaneousUsagePerConnection\tmaxSimultaneousUsagePerConnection\tminInProcessPerConnection\tmaxInProcessPerConnection\tworkerPoolSize\trequestPerSecond");
+ }
}
- }
- // not much point to continuing with a line of tests if we can't get at least minExpectedRps.
- final AtomicBoolean meetsRpsExpectation = new AtomicBoolean(true);
- System.out.println("---------------------------WARMUP CYCLE---------------------------");
- for (int ix = 0; ix < warmups && meetsRpsExpectation.get(); ix++) {
- final long averageRequestsPerSecond = new ProfilingApplication("warmup-" + (ix + 1), cluster, 1000, executor, script, tooSlowThreshold, exercise).execute();
- meetsRpsExpectation.set(averageRequestsPerSecond > minExpectedRps);
- TimeUnit.SECONDS.sleep(1); // pause between executions
- }
-
- final AtomicBoolean exceededTimeout = new AtomicBoolean(false);
- long totalRequestsPerSecond = 0;
-
- // no need to execute this if we didn't pass the basic expectation in the warmups
- if (exercise || meetsRpsExpectation.get()) {
- final long start = System.nanoTime();
- System.out.println("----------------------------TEST CYCLE----------------------------");
- for (int ix = 0; ix < executions && !exceededTimeout.get(); ix++) {
- totalRequestsPerSecond += new ProfilingApplication("test-" + (ix + 1), cluster, requests, executor, script, tooSlowThreshold, exercise).execute();
- exceededTimeout.set((System.nanoTime() - start) > TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS));
+ // not much point to continuing with a line of tests if we can't get at least minExpectedRps.
+ final AtomicBoolean meetsRpsExpectation = new AtomicBoolean(true);
+ System.out.println("---------------------------WARMUP CYCLE---------------------------");
+ for (int ix = 0; ix < warmups && meetsRpsExpectation.get(); ix++) {
+ final long averageRequestsPerSecond = new ProfilingApplication("warmup-" + (ix + 1), cluster, 1000, executor, script, tooSlowThreshold, exercise).executeThroughput();
+ meetsRpsExpectation.set(averageRequestsPerSecond > minExpectedRps);
TimeUnit.SECONDS.sleep(1); // pause between executions
}
- }
- final int averageRequestPerSecond = !meetsRpsExpectation.get() || exceededTimeout.get() ? 0 : Math.round(totalRequestsPerSecond / executions);
- System.out.println(String.format("avg req/sec: %s", averageRequestPerSecond));
- if (f != null) {
- try (final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(f, true)))) {
- writer.println(String.join("\t", String.valueOf(parallelism), String.valueOf(nioPoolSize), String.valueOf(minConnectionPoolSize), String.valueOf(maxConnectionPoolSize), String.valueOf(minSimultaneousUsagePerConnection), String.valueOf(maxSimultaneousUsagePerConnection), String.valueOf(minInProcessPerConnection), String.valueOf(maxInProcessPerConnection), String.valueOf(workerPoolSize), String.valueOf(averageRequestPerSecond)));
+ final AtomicBoolean exceededTimeout = new AtomicBoolean(false);
+ long totalRequestsPerSecond = 0;
+
+ // no need to execute this if we didn't pass the basic expectation in the warmups
+ if (exercise || meetsRpsExpectation.get()) {
+ final long start = System.nanoTime();
+ System.out.println("----------------------------TEST CYCLE----------------------------");
+ for (int ix = 0; ix < executions && !exceededTimeout.get(); ix++) {
+ totalRequestsPerSecond += new ProfilingApplication("test-" + (ix + 1), cluster, requests, executor, script, tooSlowThreshold, exercise).executeThroughput();
+ exceededTimeout.set((System.nanoTime() - start) > TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS));
+ TimeUnit.SECONDS.sleep(1); // pause between executions
+ }
}
+
+ final int averageRequestPerSecond = !meetsRpsExpectation.get() || exceededTimeout.get() ? 0 : Math.round(totalRequestsPerSecond / executions);
+ System.out.println(String.format("avg req/sec: %s", averageRequestPerSecond));
+ if (f != null) {
+ try (final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(f, true)))) {
+ writer.println(String.join("\t", String.valueOf(parallelism), String.valueOf(nioPoolSize), String.valueOf(minConnectionPoolSize), String.valueOf(maxConnectionPoolSize), String.valueOf(minSimultaneousUsagePerConnection), String.valueOf(maxSimultaneousUsagePerConnection), String.valueOf(minInProcessPerConnection), String.valueOf(maxInProcessPerConnection), String.valueOf(workerPoolSize), String.valueOf(averageRequestPerSecond)));
+ }
+ }
+ } else if (TestType.LATENCY == testType) {
+ final AtomicBoolean meetsTimeoutExpectation = new AtomicBoolean(true);
+ System.out.println("---------------------------WARMUP CYCLE---------------------------");
+ for (int ix = 0; ix < warmups && meetsTimeoutExpectation.get(); ix++) {
+ final double latency = new ProfilingApplication("warmup-" + (ix + 1), cluster, 1000, executor, script, tooSlowThreshold, exercise).executeLatency();
+ meetsTimeoutExpectation.set(latency < timeout);
+ TimeUnit.SECONDS.sleep(1); // pause between executions
+ }
+
+ final AtomicBoolean exceededTimeout = new AtomicBoolean(false);
+ double totalTime = 0;
+
+ // no need to execute this if we didn't pass the basic expectation in the warmups
+ if (exercise || meetsTimeoutExpectation.get()) {
+ final long start = System.nanoTime();
+ System.out.println("----------------------------TEST CYCLE----------------------------");
+ for (int ix = 0; ix < executions && !exceededTimeout.get(); ix++) {
+ totalTime += new ProfilingApplication("test-" + (ix + 1), cluster, requests, executor, script, tooSlowThreshold, exercise).executeLatency();
+ exceededTimeout.set((System.nanoTime() - start) > TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS));
+ TimeUnit.SECONDS.sleep(1); // pause between executions
+ }
+ }
+
+ final double averageLatency = !meetsTimeoutExpectation.get() || exceededTimeout.get() ? 0 : (totalTime / executions);
+ System.out.println(String.format("avg latency (sec/req): %s", averageLatency));
+ } else {
+ System.out.println("Encountered unknown testType. Please enter a valid value and try again.");
}
if (!noExit) System.exit(0);
diff --git a/gremlin-go/docker-compose.yml b/gremlin-go/docker-compose.yml
index a12e4f2..07c49a7 100644
--- a/gremlin-go/docker-compose.yml
+++ b/gremlin-go/docker-compose.yml
@@ -15,8 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-version: "3.8"
-
services:
gremlin-server-test:
diff --git a/gremlin-go/driver/README.md b/gremlin-go/driver/README.md
index bbae31e..6524328 100644
--- a/gremlin-go/driver/README.md
+++ b/gremlin-go/driver/README.md
@@ -132,11 +132,11 @@
There are different ways to launch the test suite and set the `GREMLIN_SERVER` environment variable depending on your Platform:
- Run Maven commands, e.g. `mvn clean install` inside of `tinkerpop/gremlin-go`, or `mvn clean install -pl gremlin-go` inside of `tinkerpop` (platform-agnostic - recommended)
- Run the `run.sh` script, which sets `GREMLIN_SERVER` by default. Run `./run.sh -h` for usage information (Unix/Linux - recommended).
-- Add `GREMLIN_SERVER=<server-image-version>` and `HOME=<user-home-directory>` to an `.env` file inside `gremlin-go` and run `docker-compose up --exit-code-from gremlin-go-integration-tests` (Platform-agnostic).
-- Run `GREMLIN_SERVER=<server-image-version> docker-compose up --exit-code-from gremlin-go-integration-tests` in Unix/Linux.
-- Run `$env:GREMLIN_SERVER="<server-image-version>";$env:HOME=$env:USERPROFILE;docker-compose up --exit-code-from gremlin-go-integration-tests` in Windows PowerShell.
+- Add `GREMLIN_SERVER=<server-image-version>` and `HOME=<user-home-directory>` to an `.env` file inside `gremlin-go` and run `docker compose up --exit-code-from gremlin-go-integration-tests` (Platform-agnostic).
+- Run `GREMLIN_SERVER=<server-image-version> docker compose up --exit-code-from gremlin-go-integration-tests` in Unix/Linux.
+- Run `$env:GREMLIN_SERVER="<server-image-version>";$env:HOME=$env:USERPROFILE;docker compose up --exit-code-from gremlin-go-integration-tests` in Windows PowerShell.
-You should see exit code 0 upon successful completion of the test suites. Run `docker-compose down` to remove the service containers (not needed if you executed Maven commands or `run.sh`), or `docker-compose down --rmi all` to remove the service containers while deleting all used images.
+You should see exit code 0 upon successful completion of the test suites. Run `docker compose down` to remove the service containers (not needed if you executed Maven commands or `run.sh`), or `docker compose down --rmi all` to remove the service containers while deleting all used images.
[go]: https://go.dev/dl/
[gomods]: https://go.dev/blog/using-go-modules
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 677a4dd..0bd7ba6 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -720,7 +720,8 @@
"g_injectXa_null_bX_intersectXa_cX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Intersect(p["xx2"])}},
"g_injectXa_null_bX_intersectXa_null_cX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Intersect(p["xx2"])}},
"g_injectX3_threeX_intersectXfive_three_7X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Intersect(p["xx2"])}},
- "g_injectX__feature___test__nullX_lTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature", " one test", nil, "", " ").LTrim()}},
+ "g_injectX__feature___test__nullX_lTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature", " one test", nil, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000").LTrim()}},
+ "g_injectX__feature___test__nullX_lTrimXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{" feature ", " one test ", nil, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"}).LTrim(gremlingo.Scope.Local)}},
"g_injectX__feature__X_lTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature ").LTrim()}},
"g_injectXListXa_bXX_lTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).LTrim()}},
"g_injectXListX1_2XX_lTrimXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).LTrim(gremlingo.Scope.Local)}},
@@ -805,6 +806,7 @@
"g_V_repeatXbothX_timesX5X_age_max": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Repeat(gremlingo.T__.Both()).Times(5).Values("age").Max()}},
"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").Group().By("name").By(gremlingo.T__.BothE().Values("weight").Max())}},
"g_VX1X_valuesXageX_maxXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Values("age").Max(gremlingo.Scope.Local)}},
+ "g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_maxXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.Union(gremlingo.T__.Values("age"), gremlingo.T__.OutE().Values("weight")).Fold()).Max(gremlingo.Scope.Local)}},
"g_V_age_mean": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Mean()}},
"g_V_foo_mean": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("foo").Mean()}},
"g_V_age_fold_meanXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Fold().Mean(gremlingo.Scope.Local)}},
@@ -821,6 +823,7 @@
"g_injectXnull_10_20_nullX_mean": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil, p["xx1"], p["xx2"], nil).Mean()}},
"g_injectXlistXnull_10_20_nullXX_meanXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Mean(gremlingo.Scope.Local)}},
"g_VX1X_valuesXageX_meanXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Values("age").Mean(gremlingo.Scope.Local)}},
+ "g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_meanXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.Union(gremlingo.T__.Values("age"), gremlingo.T__.OutE().Values("weight")).Fold()).Mean(gremlingo.Scope.Local)}},
"g_injectXnullX_mergeXinjectX1XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).Merge(gremlingo.T__.Inject(1))}},
"g_V_valuesXnameX_mergeXV_foldX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Merge(gremlingo.T__.V().Fold())}},
"g_V_fold_mergeXconstantXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Fold().Merge(gremlingo.T__.Constant(nil))}},
@@ -966,6 +969,7 @@
"g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").Group().By("name").By(gremlingo.T__.BothE().Values("weight").Min())}},
"g_V_foo_injectX9999999999X_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("foo").Inject(p["xx1"]).Min()}},
"g_VX1X_valuesXageX_minXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Values("age").Min(gremlingo.Scope.Local)}},
+ "g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_minXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.Union(gremlingo.T__.Values("age"), gremlingo.T__.OutE().Values("weight")).Fold()).Min(gremlingo.Scope.Local)}},
"g_V_name_order": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Order()}},
"g_V_name_order_byXa1_b1X_byXb2_a2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Order().By(p["c1"]).By(p["c2"])}},
"g_V_order_byXname_ascX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Order().By("name", gremlingo.Order.Asc).Values("name")}},
@@ -1046,7 +1050,8 @@
"g_V_hasXageX_propertiesXage_nameX_value": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age").Properties("age", "name").Value()}},
"g_V_propertiesXname_age_nullX_value": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties("name", "age", nil).Value()}},
"g_V_valuesXname_age_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name", "age", nil)}},
- "g_injectX__feature___test__nullX_rTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("feature ", "one test ", nil, "", " ").RTrim()}},
+ "g_injectX__feature___test__nullX_rTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("feature ", "one test ", nil, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000").RTrim()}},
+ "g_injectX__feature___test__nullX_rTrimXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{" feature ", " one test ", nil, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"}).RTrim(gremlingo.Scope.Local)}},
"g_injectX__feature__X_rTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature ").RTrim()}},
"g_injectXListXa_bXX_rTrim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).RTrim()}},
"g_injectXListX1_2XX_rTrimXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).RTrim(gremlingo.Scope.Local)}},
@@ -1183,6 +1188,7 @@
"g_injectXnull_10_5_nullX_sum": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil, p["xx1"], p["xx2"], nil).Sum()}},
"g_injectXlistXnull_10_5_nullXX_sumXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Sum(gremlingo.Scope.Local)}},
"g_VX1X_valuesXageX_sumXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Values("age").Sum(gremlingo.Scope.Local)}},
+ "g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_sumXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.Union(gremlingo.T__.Values("age"), gremlingo.T__.OutE().Values("weight")).Fold()).Sum(gremlingo.Scope.Local)}},
"g_injectXfeature_test_nullX_toLower": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("FEATURE", "tESt", nil).ToLower()}},
"g_injectXfeature_test_nullX_toLowerXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).ToLower(gremlingo.Scope.Local)}},
"g_injectXListXa_bXX_toLower": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).ToLower()}},
@@ -1196,7 +1202,8 @@
"g_V_valuesXnameX_toUpper": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").ToUpper()}},
"g_V_valuesXnameX_toUpperXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").ToUpper(gremlingo.Scope.Local)}},
"g_V_valuesXnameX_order_fold_toUpperXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Order().Fold().ToUpper(gremlingo.Scope.Local)}},
- "g_injectX__feature___test__nullX_trim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature ", " one test ", nil, "", " ").Trim()}},
+ "g_injectX__feature___test__nullX_trim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature ", " one test ", nil, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000").Trim()}},
+ "g_injectX__feature___test__nullX_trimXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{" feature ", " one test ", nil, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"}).Trim(gremlingo.Scope.Local)}},
"g_injectXListXa_bXX_trim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Trim()}},
"g_injectXListX1_2XX_trimXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Trim(gremlingo.Scope.Local)}},
"g_V_valuesXnameX_trim": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", " marko ").Property("age", 29).As("marko").AddV("person").Property("name", " vadas ").Property("age", 27).As("vadas").AddV("software").Property("name", " lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh ").Property("age", 32).As("josh").AddV("software").Property("name", " ripple ").Property("lang", "java").As("ripple").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property("weight", 1.0).AddE("created").From("marko").To("lop").Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property("weight", 1.0).AddE("created").From("josh").To("lop").Property("weight", 0.4).AddE("created").From("peter").To("lop").Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Trim()}},
diff --git a/gremlin-go/driver/graphBinary.go b/gremlin-go/driver/graphBinary.go
index f9eb548..839a891 100644
--- a/gremlin-go/driver/graphBinary.go
+++ b/gremlin-go/driver/graphBinary.go
@@ -989,14 +989,14 @@
}
if k == nil {
mapData[nil] = v
+ } else if reflect.TypeOf(k).Comparable() {
+ mapData[k] = v
} else {
switch reflect.TypeOf(k).Kind() {
case reflect.Map:
mapData[&k] = v
- case reflect.Slice:
- mapData[fmt.Sprint(k)] = v
default:
- mapData[k] = v
+ mapData[fmt.Sprint(k)] = v
}
}
}
@@ -1009,7 +1009,7 @@
for j := uint32(0); j < sz; j++ {
keyDataType := readDataType(data, i)
if keyDataType != stringType {
- return nil, newError(err0703ReadMapNonStringKeyError)
+ return nil, newError(err0703ReadMapNonStringKeyError, keyDataType)
}
// Skip nullable, key must be present
diff --git a/gremlin-go/driver/graphBinary_test.go b/gremlin-go/driver/graphBinary_test.go
index 5bfcf68..d8c66d2 100644
--- a/gremlin-go/driver/graphBinary_test.go
+++ b/gremlin-go/driver/graphBinary_test.go
@@ -232,6 +232,76 @@
assert.Nil(t, err)
assert.Equal(t, fmt.Sprintf("%v", source), fmt.Sprintf("%v", res))
})
+ t.Run("read incomparable map: a map value as the key", func(t *testing.T) {
+ // prepare test data
+ var buf = &bytes.Buffer{}
+ typeSerializer := &graphBinaryTypeSerializer{}
+ // write the size of map
+ err := binary.Write(buf, binary.BigEndian, uint32(1))
+ if err != nil {
+ t.Fatalf("Failed to write data: %v", err)
+ }
+ // write a map value as the key
+ k1 := map[string]string{"key": "value"}
+ _, err = typeSerializer.write(reflect.ValueOf(k1).Interface(), buf)
+ if err != nil {
+ t.Fatalf("Failed to encode data: %v", err)
+ }
+ v1 := "value1"
+ _, err = typeSerializer.write(reflect.ValueOf(v1).Interface(), buf)
+ if err != nil {
+ t.Fatalf("Failed to encode data: %v", err)
+ }
+
+ data := buf.Bytes()
+ i := 0
+ result, err := readMap(&data, &i)
+ if err != nil {
+ t.Fatalf("readMap failed: %v", err)
+ }
+ mResult, ok := result.(map[interface{}]interface{})
+ if !ok {
+ t.Fatalf("readMap result not map[interface{}]interface{}")
+ }
+ for k, v := range mResult {
+ assert.Equal(t, reflect.Ptr, reflect.TypeOf(k).Kind())
+ assert.Equal(t, "value1", v)
+ }
+ })
+ t.Run("read incomparable map: a slice value as the key", func(t *testing.T) {
+ // prepare test data
+ var buf = &bytes.Buffer{}
+ typeSerializer := &graphBinaryTypeSerializer{}
+ // write the size of map
+ err := binary.Write(buf, binary.BigEndian, uint32(1))
+ if err != nil {
+ t.Fatalf("Failed to write data: %v", err)
+ }
+ // write a slice value as the key
+ k2 := []int{1, 2, 3}
+ _, err = typeSerializer.write(reflect.ValueOf(k2).Interface(), buf)
+ if err != nil {
+ t.Fatalf("Failed to encode data: %v", err)
+ }
+ v2 := "value2"
+ _, err = typeSerializer.write(reflect.ValueOf(v2).Interface(), buf)
+ if err != nil {
+ t.Fatalf("Failed to encode data: %v", err)
+ }
+
+ data := buf.Bytes()
+ i := 0
+ result, err := readMap(&data, &i)
+ if err != nil {
+ t.Fatalf("readMap failed: %v", err)
+ }
+ expected := map[interface{}]interface{}{
+ "[1 2 3]": "value2",
+ }
+ if !reflect.DeepEqual(result, expected) {
+ t.Errorf("Expected %v, but got %v", expected, result)
+ }
+ })
t.Run("read-write time", func(t *testing.T) {
pos := 0
var buffer bytes.Buffer
@@ -250,7 +320,7 @@
buff := []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01}
m, err := readMapUnqualified(&buff, &i)
assert.Nil(t, m)
- assert.Equal(t, newError(err0703ReadMapNonStringKeyError), err)
+ assert.Equal(t, newError(err0703ReadMapNonStringKeyError, intType), err)
})
})
}
diff --git a/gremlin-go/pom.xml b/gremlin-go/pom.xml
index aaf75d0..e7a2a64 100644
--- a/gremlin-go/pom.xml
+++ b/gremlin-go/pom.xml
@@ -113,8 +113,9 @@
<!-- setting this env variable is needed to be cross-platform compatible -->
<HOME>${user.home}</HOME>
</environmentVariables>
- <executable>docker-compose</executable>
+ <executable>docker</executable>
<arguments>
+ <argument>compose</argument>
<argument>up</argument>
<argument>--build</argument>
<argument>--exit-code-from</argument>
@@ -131,8 +132,9 @@
<configuration>
<skip>${skipTests}</skip>
<!-- don't need to set env variables for container tear down -->
- <executable>docker-compose</executable>
+ <executable>docker</executable>
<arguments>
+ <argument>compose</argument>
<argument>down</argument>
</arguments>
</configuration>
diff --git a/gremlin-go/run.sh b/gremlin-go/run.sh
index 5f62072..23a3763 100755
--- a/gremlin-go/run.sh
+++ b/gremlin-go/run.sh
@@ -48,8 +48,8 @@
export ABS_PROJECT_HOME
# Passes current gremlin server version into docker compose as environment variable
-docker-compose up --build --exit-code-from gremlin-go-integration-tests
+docker compose up --build --exit-code-from gremlin-go-integration-tests
EXIT_CODE=$?
# Removes all service containers
-docker-compose down
+docker compose down
exit $EXIT_CODE
diff --git a/gremlin-javascript/pom.xml b/gremlin-javascript/pom.xml
index d2af8f0..21bcc40 100644
--- a/gremlin-javascript/pom.xml
+++ b/gremlin-javascript/pom.xml
@@ -256,8 +256,9 @@
<!-- setting this env variable is needed to be cross-platform compatible -->
<HOME>${user.home}</HOME>
</environmentVariables>
- <executable>docker-compose</executable>
+ <executable>docker</executable>
<arguments>
+ <argument>compose</argument>
<argument>up</argument>
<argument>--build</argument>
<argument>--exit-code-from</argument>
@@ -275,8 +276,9 @@
<configuration>
<skip>${skipTests}</skip>
<!-- don't need to set env variables for container tear down -->
- <executable>docker-compose</executable>
+ <executable>docker</executable>
<arguments>
+ <argument>compose</argument>
<argument>down</argument>
</arguments>
<workingDirectory>./src/main/javascript/gremlin-javascript</workingDirectory>
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/docker-compose.yml b/gremlin-javascript/src/main/javascript/gremlin-javascript/docker-compose.yml
index 65fc675..54b8392 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/docker-compose.yml
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/docker-compose.yml
@@ -15,8 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-version: "3.8"
-
services:
gremlin-server-test-js:
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 fe3804f..c666394 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
@@ -740,7 +740,8 @@
g_injectXa_null_bX_intersectXa_cX: [function({g, xx1, xx2}) { return g.inject(xx1).intersect(xx2) }],
g_injectXa_null_bX_intersectXa_null_cX: [function({g, xx1, xx2}) { return g.inject(xx1).intersect(xx2) }],
g_injectX3_threeX_intersectXfive_three_7X: [function({g, xx1, xx2}) { return g.inject(xx1).intersect(xx2) }],
- g_injectX__feature___test__nullX_lTrim: [function({g}) { return g.inject(" feature"," one test",null,""," ").lTrim() }],
+ g_injectX__feature___test__nullX_lTrim: [function({g}) { return g.inject(" feature"," one test",null,""," ","\u3000abc","abc\u3000","\u3000abc\u3000","\u3000\u3000").lTrim() }],
+ g_injectX__feature___test__nullX_lTrimXlocalX: [function({g}) { return g.inject([" feature ", " one test ", null, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"]).lTrim(Scope.local) }],
g_injectX__feature__X_lTrim: [function({g}) { return g.inject(" feature ").lTrim() }],
g_injectXListXa_bXX_lTrim: [function({g, xx1}) { return g.inject(xx1).lTrim() }],
g_injectXListX1_2XX_lTrimXlocalX: [function({g, xx1}) { return g.inject(xx1).lTrim(Scope.local) }],
@@ -825,6 +826,7 @@
g_V_repeatXbothX_timesX5X_age_max: [function({g}) { return g.V().repeat(__.both()).times(5).values("age").max() }],
g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").max()) }],
g_VX1X_valuesXageX_maxXlocalX: [function({g, vid1}) { return g.V(vid1).values("age").max(Scope.local) }],
+ g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_maxXlocalX: [function({g}) { return g.V().local(__.union(__.values("age"),__.outE().values("weight")).fold()).max(Scope.local) }],
g_V_age_mean: [function({g}) { return g.V().values("age").mean() }],
g_V_foo_mean: [function({g}) { return g.V().values("foo").mean() }],
g_V_age_fold_meanXlocalX: [function({g}) { return g.V().values("age").fold().mean(Scope.local) }],
@@ -841,6 +843,7 @@
g_injectXnull_10_20_nullX_mean: [function({g, xx1, xx2}) { return g.inject(null,xx1,xx2,null).mean() }],
g_injectXlistXnull_10_20_nullXX_meanXlocalX: [function({g, xx1}) { return g.inject(xx1).mean(Scope.local) }],
g_VX1X_valuesXageX_meanXlocalX: [function({g, vid1}) { return g.V(vid1).values("age").mean(Scope.local) }],
+ g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_meanXlocalX: [function({g}) { return g.V().local(__.union(__.values("age"),__.outE().values("weight")).fold()).mean(Scope.local) }],
g_injectXnullX_mergeXinjectX1XX: [function({g}) { return g.inject(null).merge(__.inject(1)) }],
g_V_valuesXnameX_mergeXV_foldX: [function({g}) { return g.V().values("name").merge(__.V().fold()) }],
g_V_fold_mergeXconstantXnullXX: [function({g}) { return g.V().fold().merge(__.constant(null)) }],
@@ -986,6 +989,7 @@
g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").min()) }],
g_V_foo_injectX9999999999X_min: [function({g, xx1}) { return g.V().values("foo").inject(xx1).min() }],
g_VX1X_valuesXageX_minXlocalX: [function({g, vid1}) { return g.V(vid1).values("age").min(Scope.local) }],
+ g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_minXlocalX: [function({g}) { return g.V().local(__.union(__.values("age"),__.outE().values("weight")).fold()).min(Scope.local) }],
g_V_name_order: [function({g}) { return g.V().values("name").order() }],
g_V_name_order_byXa1_b1X_byXb2_a2X: [function({g, c1, c2}) { return g.V().values("name").order().by(c1).by(c2) }],
g_V_order_byXname_ascX_name: [function({g}) { return g.V().order().by("name",Order.asc).values("name") }],
@@ -1066,7 +1070,8 @@
g_V_hasXageX_propertiesXage_nameX_value: [function({g}) { return g.V().has("age").properties("age","name").value() }],
g_V_propertiesXname_age_nullX_value: [function({g}) { return g.V().properties("name","age",null).value() }],
g_V_valuesXname_age_nullX: [function({g}) { return g.V().values("name","age",null) }],
- g_injectX__feature___test__nullX_rTrim: [function({g}) { return g.inject("feature ","one test ",null,""," ").rTrim() }],
+ g_injectX__feature___test__nullX_rTrim: [function({g}) { return g.inject("feature ","one test ",null,""," ","\u3000abc","abc\u3000","\u3000abc\u3000","\u3000\u3000").rTrim() }],
+ g_injectX__feature___test__nullX_rTrimXlocalX: [function({g}) { return g.inject([" feature ", " one test ", null, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"]).rTrim(Scope.local) }],
g_injectX__feature__X_rTrim: [function({g}) { return g.inject(" feature ").rTrim() }],
g_injectXListXa_bXX_rTrim: [function({g, xx1}) { return g.inject(xx1).rTrim() }],
g_injectXListX1_2XX_rTrimXlocalX: [function({g, xx1}) { return g.inject(xx1).rTrim(Scope.local) }],
@@ -1203,6 +1208,7 @@
g_injectXnull_10_5_nullX_sum: [function({g, xx1, xx2}) { return g.inject(null,xx1,xx2,null).sum() }],
g_injectXlistXnull_10_5_nullXX_sumXlocalX: [function({g, xx1}) { return g.inject(xx1).sum(Scope.local) }],
g_VX1X_valuesXageX_sumXlocalX: [function({g, vid1}) { return g.V(vid1).values("age").sum(Scope.local) }],
+ g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_sumXlocalX: [function({g}) { return g.V().local(__.union(__.values("age"),__.outE().values("weight")).fold()).sum(Scope.local) }],
g_injectXfeature_test_nullX_toLower: [function({g}) { return g.inject("FEATURE","tESt",null).toLower() }],
g_injectXfeature_test_nullX_toLowerXlocalX: [function({g, xx1}) { return g.inject(xx1).toLower(Scope.local) }],
g_injectXListXa_bXX_toLower: [function({g, xx1}) { return g.inject(xx1).toLower() }],
@@ -1216,7 +1222,8 @@
g_V_valuesXnameX_toUpper: [function({g}) { return g.V().values("name").toUpper() }],
g_V_valuesXnameX_toUpperXlocalX: [function({g}) { return g.V().values("name").toUpper(Scope.local) }],
g_V_valuesXnameX_order_fold_toUpperXlocalX: [function({g}) { return g.V().values("name").order().fold().toUpper(Scope.local) }],
- g_injectX__feature___test__nullX_trim: [function({g}) { return g.inject(" feature "," one test ",null,""," ").trim() }],
+ g_injectX__feature___test__nullX_trim: [function({g}) { return g.inject(" feature "," one test ",null,""," ","\u3000abc","abc\u3000","\u3000abc\u3000","\u3000\u3000").trim() }],
+ g_injectX__feature___test__nullX_trimXlocalX: [function({g}) { return g.inject([" feature ", " one test ", null, "", " ", "\u3000abc", "abc\u3000", "\u3000abc\u3000", "\u3000\u3000"]).trim(Scope.local) }],
g_injectXListXa_bXX_trim: [function({g, xx1}) { return g.inject(xx1).trim() }],
g_injectXListX1_2XX_trimXlocalX: [function({g, xx1}) { return g.inject(xx1).trim(Scope.local) }],
g_V_valuesXnameX_trim: [function({g}) { return g.addV("person").property("name"," marko ").property("age",29).as("marko").addV("person").property("name"," vadas ").property("age",27).as("vadas").addV("software").property("name"," lop").property("lang","java").as("lop").addV("person").property("name","josh ").property("age",32).as("josh").addV("software").property("name"," ripple ").property("lang","java").as("ripple").addV("person").property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property("weight",0.5).addE("knows").from_("marko").to("josh").property("weight",1.0).addE("created").from_("marko").to("lop").property("weight",0.4).addE("created").from_("josh").to("ripple").property("weight",1.0).addE("created").from_("josh").to("lop").property("weight",0.4).addE("created").from_("peter").to("lop").property("weight",0.2) }, function({g}) { return g.V().values("name").trim() }],
diff --git a/gremlin-python/docker-compose.yml b/gremlin-python/docker-compose.yml
index 5f9ef5d..b03ec9c 100644
--- a/gremlin-python/docker-compose.yml
+++ b/gremlin-python/docker-compose.yml
@@ -15,8 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-version: "3.8"
-
services:
gremlin-server-test-python:
@@ -72,7 +70,7 @@
bash -c "apt-get update && apt-get -y install libkrb5-dev krb5-user
&& echo 'password' | kinit stephen
&& klist
- && pip install wheel radish-bdd PyHamcrest aenum isodate kerberos six
+ && pip install wheel radish-bdd PyHamcrest aenum isodate kerberos
&& python3 ./setup.py build
&& python3 ./setup.py test
&& python3 ./setup.py install
diff --git a/gremlin-python/pom.xml b/gremlin-python/pom.xml
index 3dc2296..5299cf5 100644
--- a/gremlin-python/pom.xml
+++ b/gremlin-python/pom.xml
@@ -135,16 +135,16 @@
</goals>
<configuration>
<target>
- <exec executable="docker-compose" failonerror="true">
+ <exec executable="docker" failonerror="true">
<env key="PACKAGE_DIR" value="${project.build.directory}/python-packaged"/>
<env key="VERSION" value="${project.version}"/>
<env key="PYTHONPATH" value=""/>
- <arg line="up --build --abort-on-container-exit gremlin-python-package"/>
+ <arg line="compose up --build --abort-on-container-exit gremlin-python-package"/>
</exec>
- <exec executable="docker-compose" failonerror="true">
+ <exec executable="docker" failonerror="true">
<env key="PYTHONPATH" value=""/>
<env key="PACKAGE_DIR" value="${project.build.directory}/python-packaged"/>
- <arg line="down"/>
+ <arg line="compose down"/>
</exec>
<exec executable="docker" failonerror="true">
<env key="PYTHONPATH" value=""/>
@@ -156,7 +156,7 @@
</execution>
<!--
- use docker-compose to run unit tests, radish, and integration tests.
+ use docker compose to run unit tests, radish, and integration tests.
-->
<execution>
<id>python-tests</id>
@@ -167,18 +167,18 @@
<configuration>
<skip>${skipTests}</skip>
<target>
- <exec executable="docker-compose" failonerror="true">
+ <exec executable="docker" failonerror="true">
<env key="VERSION" value="${project.version}"/>
<env key="PYTHONPATH" value=""/>
<env key="GREMLIN_SERVER" value="${project.version}"/>
<env key="ABS_PROJECT_HOME" value="${project.basedir}/../"/>
<env key="BUILD_DIR" value="${project.build.directory}/python3"/>
- <arg line="up --build --abort-on-container-exit gremlin-server-test-python gremlin-python-integration-tests"/>
+ <arg line="compose up --build --abort-on-container-exit gremlin-server-test-python gremlin-python-integration-tests"/>
</exec>
- <exec executable="docker-compose" failonerror="true">
+ <exec executable="docker" failonerror="true">
<env key="PYTHONPATH" value=""/>
<env key="BUILD_DIR" value="${project.build.directory}/python3"/>
- <arg line="down"/>
+ <arg line="compose down"/>
</exec>
<exec executable="docker" failonerror="true">
<env key="PYTHONPATH" value=""/>
diff --git a/gremlin-python/src/main/python/examples/requirements.txt b/gremlin-python/src/main/python/examples/requirements.txt
index fb17e70..d4399ec 100644
--- a/gremlin-python/src/main/python/examples/requirements.txt
+++ b/gremlin-python/src/main/python/examples/requirements.txt
@@ -25,5 +25,4 @@
idna==3.6
isodate==0.6.1
multidict==6.0.5
-six==1.16.0
yarl==1.9.4
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 70c1751..8696202 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -722,7 +722,8 @@
'g_injectXa_null_bX_intersectXa_cX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).intersect(xx2))],
'g_injectXa_null_bX_intersectXa_null_cX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).intersect(xx2))],
'g_injectX3_threeX_intersectXfive_three_7X': [(lambda g, xx1=None,xx2=None:g.inject(xx1).intersect(xx2))],
- 'g_injectX__feature___test__nullX_lTrim': [(lambda g:g.inject(' feature',' one test',None,'',' ').lTrim())],
+ 'g_injectX__feature___test__nullX_lTrim': [(lambda g:g.inject(' feature',' one test',None,'',' ',' abc','abc ',' abc ',' ').lTrim())],
+ 'g_injectX__feature___test__nullX_lTrimXlocalX': [(lambda g:g.inject([' feature ',' one test ',None,'',' ',' abc','abc ',' abc ',' ']).lTrim(Scope.local))],
'g_injectX__feature__X_lTrim': [(lambda g:g.inject(' feature ').lTrim())],
'g_injectXListXa_bXX_lTrim': [(lambda g, xx1=None:g.inject(xx1).lTrim())],
'g_injectXListX1_2XX_lTrimXlocalX': [(lambda g, xx1=None:g.inject(xx1).lTrim(Scope.local))],
@@ -807,6 +808,7 @@
'g_V_repeatXbothX_timesX5X_age_max': [(lambda g:g.V().repeat(__.both()).times(5).age.max_())],
'g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_maxX': [(lambda g:g.V().hasLabel('software').group().by('name').by(__.bothE().weight.max_()))],
'g_VX1X_valuesXageX_maxXlocalX': [(lambda g, vid1=None:g.V(vid1).age.max_(Scope.local))],
+ 'g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_maxXlocalX': [(lambda g:g.V().local(__.union(__.age,__.outE().weight).fold()).max_(Scope.local))],
'g_V_age_mean': [(lambda g:g.V().age.mean())],
'g_V_foo_mean': [(lambda g:g.V().foo.mean())],
'g_V_age_fold_meanXlocalX': [(lambda g:g.V().age.fold().mean(Scope.local))],
@@ -823,6 +825,7 @@
'g_injectXnull_10_20_nullX_mean': [(lambda g, xx1=None,xx2=None:g.inject(None,xx1,xx2,None).mean())],
'g_injectXlistXnull_10_20_nullXX_meanXlocalX': [(lambda g, xx1=None:g.inject(xx1).mean(Scope.local))],
'g_VX1X_valuesXageX_meanXlocalX': [(lambda g, vid1=None:g.V(vid1).age.mean(Scope.local))],
+ 'g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_meanXlocalX': [(lambda g:g.V().local(__.union(__.age,__.outE().weight).fold()).mean(Scope.local))],
'g_injectXnullX_mergeXinjectX1XX': [(lambda g:g.inject(None).merge(__.inject(1)))],
'g_V_valuesXnameX_mergeXV_foldX': [(lambda g:g.V().name.merge(__.V().fold()))],
'g_V_fold_mergeXconstantXnullXX': [(lambda g:g.V().fold().merge(__.constant(None)))],
@@ -968,6 +971,7 @@
'g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX': [(lambda g:g.V().hasLabel('software').group().by('name').by(__.bothE().weight.min_()))],
'g_V_foo_injectX9999999999X_min': [(lambda g, xx1=None:g.V().foo.inject(xx1).min_())],
'g_VX1X_valuesXageX_minXlocalX': [(lambda g, vid1=None:g.V(vid1).age.min_(Scope.local))],
+ 'g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_minXlocalX': [(lambda g:g.V().local(__.union(__.age,__.outE().weight).fold()).min_(Scope.local))],
'g_V_name_order': [(lambda g:g.V().name.order())],
'g_V_name_order_byXa1_b1X_byXb2_a2X': [(lambda g, c1=None,c2=None:g.V().name.order().by(c1).by(c2))],
'g_V_order_byXname_ascX_name': [(lambda g:g.V().order().by('name',Order.asc).name)],
@@ -1048,7 +1052,8 @@
'g_V_hasXageX_propertiesXage_nameX_value': [(lambda g:g.V().has('age').properties('age','name').value())],
'g_V_propertiesXname_age_nullX_value': [(lambda g:g.V().properties('name','age',None).value())],
'g_V_valuesXname_age_nullX': [(lambda g:g.V().values('name','age',None))],
- 'g_injectX__feature___test__nullX_rTrim': [(lambda g:g.inject('feature ','one test ',None,'',' ').rTrim())],
+ 'g_injectX__feature___test__nullX_rTrim': [(lambda g:g.inject('feature ','one test ',None,'',' ',' abc','abc ',' abc ',' ').rTrim())],
+ 'g_injectX__feature___test__nullX_rTrimXlocalX': [(lambda g:g.inject([' feature ',' one test ',None,'',' ',' abc','abc ',' abc ',' ']).rTrim(Scope.local))],
'g_injectX__feature__X_rTrim': [(lambda g:g.inject(' feature ').rTrim())],
'g_injectXListXa_bXX_rTrim': [(lambda g, xx1=None:g.inject(xx1).rTrim())],
'g_injectXListX1_2XX_rTrimXlocalX': [(lambda g, xx1=None:g.inject(xx1).rTrim(Scope.local))],
@@ -1185,6 +1190,7 @@
'g_injectXnull_10_5_nullX_sum': [(lambda g, xx1=None,xx2=None:g.inject(None,xx1,xx2,None).sum_())],
'g_injectXlistXnull_10_5_nullXX_sumXlocalX': [(lambda g, xx1=None:g.inject(xx1).sum_(Scope.local))],
'g_VX1X_valuesXageX_sumXlocalX': [(lambda g, vid1=None:g.V(vid1).age.sum_(Scope.local))],
+ 'g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_sumXlocalX': [(lambda g:g.V().local(__.union(__.age,__.outE().weight).fold()).sum_(Scope.local))],
'g_injectXfeature_test_nullX_toLower': [(lambda g:g.inject('FEATURE','tESt',None).to_lower())],
'g_injectXfeature_test_nullX_toLowerXlocalX': [(lambda g, xx1=None:g.inject(xx1).to_lower(Scope.local))],
'g_injectXListXa_bXX_toLower': [(lambda g, xx1=None:g.inject(xx1).to_lower())],
@@ -1198,7 +1204,8 @@
'g_V_valuesXnameX_toUpper': [(lambda g:g.V().name.to_upper())],
'g_V_valuesXnameX_toUpperXlocalX': [(lambda g:g.V().name.to_upper(Scope.local))],
'g_V_valuesXnameX_order_fold_toUpperXlocalX': [(lambda g:g.V().name.order().fold().to_upper(Scope.local))],
- 'g_injectX__feature___test__nullX_trim': [(lambda g:g.inject(' feature ',' one test ',None,'',' ').trim())],
+ 'g_injectX__feature___test__nullX_trim': [(lambda g:g.inject(' feature ',' one test ',None,'',' ',' abc','abc ',' abc ',' ').trim())],
+ 'g_injectX__feature___test__nullX_trimXlocalX': [(lambda g:g.inject([' feature ',' one test ',None,'',' ',' abc','abc ',' abc ',' ']).trim(Scope.local))],
'g_injectXListXa_bXX_trim': [(lambda g, xx1=None:g.inject(xx1).trim())],
'g_injectXListX1_2XX_trimXlocalX': [(lambda g, xx1=None:g.inject(xx1).trim(Scope.local))],
'g_V_valuesXnameX_trim': [(lambda g:g.addV('person').property('name',' marko ').property('age',29).as_('marko').addV('person').property('name',' vadas ').property('age',27).as_('vadas').addV('software').property('name',' lop').property('lang','java').as_('lop').addV('person').property('name','josh ').property('age',32).as_('josh').addV('software').property('name',' ripple ').property('lang','java').as_('ripple').addV('person').property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property('weight',float(1.0)).addE('created').from_('marko').to('lop').property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property('weight',float(1.0)).addE('created').from_('josh').to('lop').property('weight',float(0.4)).addE('created').from_('peter').to('lop').property('weight',float(0.2))), (lambda g:g.V().name.trim())],
diff --git a/gremlin-python/src/main/python/setup.cfg b/gremlin-python/src/main/python/setup.cfg
index a4a55e0..d63f2e1 100644
--- a/gremlin-python/src/main/python/setup.cfg
+++ b/gremlin-python/src/main/python/setup.cfg
@@ -14,9 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-[bdist_wheel]
-universal=1
-
[aliases]
test=pytest
diff --git a/gremlin-python/src/main/python/setup.py b/gremlin-python/src/main/python/setup.py
index 2ca7e9a..88d4d8c 100644
--- a/gremlin-python/src/main/python/setup.py
+++ b/gremlin-python/src/main/python/setup.py
@@ -48,13 +48,9 @@
'nest_asyncio',
'aiohttp>=3.8.0,<4.0.0',
'aenum>=1.4.5,<4.0.0',
- 'six>=1.10.0,<2.0.0',
'isodate>=0.6.0,<1.0.0'
]
-if sys.version_info < (3, 5):
- install_requires += ['pyparsing>=2.4.7,<3.0.0']
-
setup(
name='gremlinpython',
version=version,
@@ -62,7 +58,7 @@
'gremlin_python.driver.aiohttp', 'gremlin_python.process',
'gremlin_python.structure', 'gremlin_python.structure.io'],
license='Apache 2',
- url='http://tinkerpop.apache.org',
+ url='https://tinkerpop.apache.org',
description='Gremlin-Python for Apache TinkerPop',
long_description=codecs.open("README.rst", "r", "UTF-8").read(),
long_description_content_type='text/x-rst',
@@ -74,7 +70,6 @@
],
tests_require=[
'pytest>=4.6.4,<7.2.0',
- 'mock>=3.0.5,<5.0.0',
'radish-bdd==0.13.4',
'PyHamcrest>=1.9.0,<3.0.0',
'PyYAML>=5.3'
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
index f89c84c..4860350 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
@@ -26,7 +26,7 @@
import math
from decimal import *
-from mock import Mock
+from unittest.mock import Mock
from gremlin_python.statics import *
from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path
@@ -37,7 +37,7 @@
from gremlin_python.process.graph_traversal import __
-class TestGraphSONReader(object):
+class TestGraphSONReader:
graphson_reader = GraphSONReader()
def test_number_input(self):
@@ -216,7 +216,7 @@
def test_custom_mapping(self):
# extended mapping
- class X(object):
+ class X:
pass
type_string = "test:Xtype"
@@ -298,7 +298,7 @@
assert c is None
-class TestGraphSONWriter(object):
+class TestGraphSONWriter:
graphson_writer = GraphSONWriter()
graphson_reader = GraphSONReader()
@@ -418,7 +418,7 @@
def test_custom_mapping(self):
# extended mapping
- class X(object):
+ class X:
pass
serdes = Mock()
@@ -489,7 +489,7 @@
assert expected == output
-class TestFunctionalGraphSONIO(object):
+class TestFunctionalGraphSONIO:
"""Functional IO tests"""
def test_timestamp(self, remote_connection_graphsonV2):
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
index 6b852fb..a6a65a8 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
@@ -26,7 +26,7 @@
import math
from decimal import *
-from mock import Mock
+from unittest.mock import Mock
from gremlin_python.statics import *
from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Path
@@ -37,7 +37,7 @@
from gremlin_python.process.graph_traversal import __
-class TestGraphSONReader(object):
+class TestGraphSONReader:
graphson_reader = GraphSONReader()
def test_collections(self):
@@ -57,7 +57,7 @@
"3"]}))
# return a set as normal
assert isinstance(x, set)
- assert x == set([1, 2, "3"])
+ assert x == {1, 2, "3"}
x = self.graphson_reader.read_object(
json.dumps({"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
@@ -261,7 +261,7 @@
def test_custom_mapping(self):
# extended mapping
- class X(object):
+ class X:
pass
type_string = "test:Xtype"
@@ -344,7 +344,7 @@
assert c is None
-class TestGraphSONWriter(object):
+class TestGraphSONWriter:
graphson_writer = GraphSONWriter()
graphson_reader = GraphSONReader()
@@ -356,7 +356,7 @@
assert {"@type": "g:Set", "@value": [{"@type": "g:Int32", "@value": 1},
{"@type": "g:Int32", "@value": 2},
{"@type": "g:Int32", "@value": 3}]} == json.loads(
- self.graphson_writer.write_object(set([1, 2, 3, 3])))
+ self.graphson_writer.write_object({1, 2, 3, 3}))
assert {"@type": "g:Map",
"@value": ['a', {"@type": "g:Int32", "@value": 1}]} == json.loads(
self.graphson_writer.write_object({'a': 1}))
@@ -484,7 +484,7 @@
def test_custom_mapping(self):
# extended mapping
- class X(object):
+ class X:
pass
serdes = Mock()
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java
index 4b8e6f9..1220bce 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/WebSocketAuthorizationHandler.java
@@ -68,11 +68,9 @@
final Bytecode bytecode = (Bytecode) requestMessage.getArgs().get(Tokens.ARGS_GREMLIN);
final Map<String, String> aliases = (Map<String, String>) requestMessage.getArgs().get(Tokens.ARGS_ALIASES);
final Bytecode restrictedBytecode = authorizer.authorize(user, bytecode, aliases);
- final RequestMessage restrictedMsg = RequestMessage.build(Tokens.OPS_BYTECODE).
- overrideRequestId(requestMessage.getRequestId()).
- processor("traversal").
- addArg(Tokens.ARGS_GREMLIN, restrictedBytecode).
- addArg(Tokens.ARGS_ALIASES, aliases).create();
+ final RequestMessage restrictedMsg = RequestMessage.from(requestMessage)
+ .addArg(Tokens.ARGS_GREMLIN, restrictedBytecode)
+ .addArg(Tokens.ARGS_ALIASES, aliases).create();
ctx.fireChannelRead(restrictedMsg);
break;
case Tokens.OPS_EVAL:
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
index 871ce4f..f461380 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
@@ -31,7 +31,7 @@
import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.AbstractWarningVerificationStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
import org.apache.tinkerpop.gremlin.server.authz.AllowListAuthorizer;
@@ -42,13 +42,16 @@
import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.time.Instant;
import java.util.Base64;
import java.util.HashMap;
import java.util.Objects;
+import java.util.concurrent.CompletionException;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
@@ -62,6 +65,7 @@
* @author Marc de Lignie
*/
public class GremlinServerAuthzIntegrateTest extends AbstractGremlinServerIntegrationTest {
+ private static final Long DEFAULT_EVALUATION_TIMEOUT = 2000L;
private static LogCaptor logCaptor;
private final ObjectMapper mapper = new ObjectMapper();
@@ -107,6 +111,7 @@
settings.authentication = authSettings;
settings.authorization = authzSettings;
settings.enableAuditLog = true;
+ settings.evaluationTimeout = DEFAULT_EVALUATION_TIMEOUT;
final String nameOfTest = name.getMethodName();
switch (nameOfTest) {
@@ -387,4 +392,23 @@
assertEquals(6, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).intValue());
}
}
+
+ @Test
+ public void shouldRespectTimeoutWithAuth() {
+ final Cluster cluster = TestClientFactory.build().credentials("stephen", "password").create();
+ final GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(
+ DriverRemoteConnection.using(cluster, "gmodern"));
+ final Instant instant = Instant.now();
+ try {
+ g.with("evaluationTimeout", DEFAULT_EVALUATION_TIMEOUT / 20).
+ V().
+ repeat(__.both()).
+ until(__.count().is(0)).
+ toList();
+ } catch (final CompletionException e) {
+ Assert.assertTrue(Instant.now().toEpochMilli() - instant.toEpochMilli() < DEFAULT_EVALUATION_TIMEOUT / 2);
+ } finally {
+ cluster.close();
+ }
+ }
}
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/LTrim.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/LTrim.feature
index 4ca4915..67b664c 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/LTrim.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/LTrim.feature
@@ -19,11 +19,12 @@
Feature: Step - lTrim()
@GraphComputerVerificationInjectionNotSupported
+ # This verifies both ASCII control space and ideographic space character \u3000 are property trimmed.
Scenario: g_injectX__feature___test__nullX_lTrim
Given the empty graph
And the traversal of
"""
- g.inject(" feature", " one test", null, "", " ").lTrim()
+ g.inject(" feature", " one test", null, "", " ", " abc", "abc ", " abc ", " ").lTrim()
"""
When iterated to list
Then the result should be unordered
@@ -33,6 +34,23 @@
| null |
| str[] |
| str[] |
+ | str[abc] |
+ | str[abc ] |
+ | str[abc ] |
+ | str[] |
+
+ @GraphComputerVerificationInjectionNotSupported
+ # This verifies both ASCII control space and ideographic space character \u3000 are property trimmed.
+ Scenario: g_injectX__feature___test__nullX_lTrimXlocalX
+ Given the empty graph
+ And the traversal of
+ """
+ g.inject([" feature ", " one test ", null, "", " ", " abc", "abc ", " abc ", " "]).lTrim(Scope.local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | l[str[feature ],str[one test ],null,str[],str[],str[abc],str[abc ],str[abc ],str[]] |
@GraphComputerVerificationInjectionNotSupported
Scenario: g_injectX__feature__X_lTrim
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Max.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Max.feature
index 1603370..75caa6a 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Max.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Max.feature
@@ -201,3 +201,18 @@
Then the result should be unordered
| result |
| d[29].i |
+
+ # It verifies if empty lists are filtered out as expected
+ Scenario: g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_maxXlocalX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().local(union(values("age"), outE().values("weight")).fold()).max(local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].d |
+ | d[27].i |
+ | d[32].d |
+ | d[35].d |
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Mean.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Mean.feature
index 75fc132..fed1a0c 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Mean.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Mean.feature
@@ -202,4 +202,19 @@
When iterated to list
Then the result should be unordered
| result |
- | d[29.0].d |
\ No newline at end of file
+ | d[29.0].d |
+
+ # It verifies if empty lists are filtered out as expected
+ Scenario: g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_meanXlocalX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().local(union(values("age"), outE().values("weight")).fold()).mean(local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[7.725].d |
+ | d[27.0].d |
+ | d[11.133333333333333].d |
+ | d[17.6].d |
\ No newline at end of file
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Min.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Min.feature
index 0b8c4af..cff82d8 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Min.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Min.feature
@@ -214,3 +214,18 @@
Then the result should be unordered
| result |
| d[29].i |
+
+ # It verifies if empty lists are filtered out as expected
+ Scenario: g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_minXlocalX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().local(union(values("age"), outE().values("weight")).fold()).min(local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[0.4].d |
+ | d[27].i |
+ | d[0.4].d |
+ | d[0.2].d |
\ No newline at end of file
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/RTrim.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/RTrim.feature
index 23df32f..4b171b8 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/RTrim.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/RTrim.feature
@@ -19,11 +19,12 @@
Feature: Step - rTrim()
@GraphComputerVerificationInjectionNotSupported
+ # This verifies both ASCII control space and ideographic space character \u3000 are property trimmed.
Scenario: g_injectX__feature___test__nullX_rTrim
Given the empty graph
And the traversal of
"""
- g.inject("feature ", "one test ", null, "", " ").rTrim()
+ g.inject("feature ", "one test ", null, "", " ", " abc", "abc ", " abc ", " ").rTrim()
"""
When iterated to list
Then the result should be unordered
@@ -33,6 +34,23 @@
| null |
| str[] |
| str[] |
+ | str[ abc] |
+ | str[abc] |
+ | str[ abc] |
+ | str[] |
+
+ @GraphComputerVerificationInjectionNotSupported
+ # This verifies both ASCII control space and ideographic space character \u3000 are property trimmed.
+ Scenario: g_injectX__feature___test__nullX_rTrimXlocalX
+ Given the empty graph
+ And the traversal of
+ """
+ g.inject([" feature ", " one test ", null, "", " ", " abc", "abc ", " abc ", " "]).rTrim(Scope.local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | l[str[ feature],str[ one test],null,str[],str[],str[ abc],str[abc],str[ abc],str[]] |
@GraphComputerVerificationInjectionNotSupported
Scenario: g_injectX__feature__X_rTrim
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Sum.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Sum.feature
index e0e7345..c5a475f 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Sum.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Sum.feature
@@ -201,4 +201,19 @@
When iterated to list
Then the result should be unordered
| result |
- | d[29].i |
\ No newline at end of file
+ | d[29].i |
+
+ # It verifies if empty lists are filtered out as expected
+ Scenario: g_V_localXunionXvaluesXageX_outE_valuesXweightXX_foldX_sumXlocalX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().local(union(values("age"), outE().values("weight")).fold()).sum(local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[30.9].d |
+ | d[27].i |
+ | d[33.4].d |
+ | d[35.2].d |
\ No newline at end of file
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Trim.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Trim.feature
index feda185..6279ca4 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Trim.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Trim.feature
@@ -19,11 +19,12 @@
Feature: Step - trim()
@GraphComputerVerificationInjectionNotSupported
+ # This verifies both ASCII control space and ideographic space character \u3000 are property trimmed.
Scenario: g_injectX__feature___test__nullX_trim
Given the empty graph
And the traversal of
"""
- g.inject(" feature ", " one test ", null, "", " ").trim()
+ g.inject(" feature ", " one test ", null, "", " ", " abc", "abc ", " abc ", " ").trim()
"""
When iterated to list
Then the result should be unordered
@@ -33,6 +34,23 @@
| null |
| str[] |
| str[] |
+ | str[abc] |
+ | str[abc] |
+ | str[abc] |
+ | str[] |
+
+ @GraphComputerVerificationInjectionNotSupported
+ # This verifies both ASCII control space and ideographic space character \u3000 are property trimmed.
+ Scenario: g_injectX__feature___test__nullX_trimXlocalX
+ Given the empty graph
+ And the traversal of
+ """
+ g.inject([" feature ", " one test ", null, "", " ", " abc", "abc ", " abc ", " "]).trim(Scope.local)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | l[str[feature],str[one test],null,str[],str[],str[abc],str[abc],str[abc],str[]] |
@GraphComputerVerificationInjectionNotSupported
Scenario: g_injectXListXa_bXX_trim