This is an automated email from the ASF dual-hosted git repository. colegreer pushed a commit to branch graph-binary-4-JS-HTTP in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 0a042edb9f8b73e10ae695978872ff5538799e7e Author: Cole Greer <[email protected]> AuthorDate: Mon Mar 16 09:45:57 2026 -0700 Fix integration and feature tests Remove SASL, rework strategies to use simple names instead of FQCN. --- .github/workflows/build-test.yml | 168 +++++++-------- gremlin-javascript/examples/node/basic-gremlin.js | 2 +- gremlin-javascript/pom.xml | 3 +- .../gremlin-javascript/docker-compose.yml | 15 +- .../driver/auth/mechanisms/sasl-mechanism-base.ts | 49 ----- .../driver/auth/mechanisms/sasl-mechanism-plain.ts | 105 --------- .../driver/auth/plain-text-sasl-authenticator.ts | 51 ----- .../lib/driver/auth/sasl-authenticator.ts | 50 ----- .../gremlin-javascript/lib/driver/client.ts | 9 +- .../gremlin-javascript/lib/driver/connection.ts | 18 +- .../lib/driver/remote-connection.ts | 11 +- .../javascript/gremlin-javascript/lib/index.ts | 2 - .../lib/process/graph-traversal.ts | 28 +-- .../gremlin-javascript/lib/process/gremlin-lang.ts | 2 +- .../lib/process/traversal-strategy.ts | 129 ++++++----- .../gremlin-javascript/lib/process/traversal.ts | 32 +-- .../io/binary/internals/GraphBinaryReader.js | 2 +- .../io/binary/internals/GraphBinaryWriter.js | 56 ++++- .../lib/structure/io/type-serializers.ts | 2 +- .../javascript/gremlin-javascript/package.json | 13 +- .../test/cucumber/feature-steps.js | 26 ++- .../javascript/gremlin-javascript/test/helper.js | 31 +-- .../test/integration/client-behavior-tests.js | 76 ------- .../test/integration/client-tests.js | 125 ++--------- .../test/integration/remote-connection-tests.js | 29 +-- .../test/integration/sasl-authentication-tests.js | 102 --------- .../test/integration/socket-connection-tests.js | 86 ++------ .../test/integration/traversal-test.js | 239 ++++++++++----------- .../unit/graphbinary/GraphBinaryReader-test.js | 34 +-- .../unit/graphbinary/GraphBinaryWriter-test.js | 16 +- .../test/unit/traversal-strategy-test.js | 2 +- .../gremlin-javascript/test/unit/traversal-test.js | 12 +- 32 files changed, 492 insertions(+), 1033 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 3d6eb331cd..d8db010e3a 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -233,90 +233,90 @@ jobs: run: | mvn clean install -pl $EXCLUDE_MODULES -q -DskipTests -Dci mvn verify -pl gremlin-driver -DskipIntegrationTests=false -# javascript-node20: -# name: javascript-all-node20 -# timeout-minutes: 15 -# needs: cache-gremlin-server-docker-image -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v6 -# - name: Set up JDK 11 -# uses: actions/setup-java@v5 -# with: -# java-version: '11' -# distribution: 'temurin' -# - name: Get Cached Server Base Image -# uses: actions/cache@v5 -# id: gremlin-server-test-docker-image -# with: -# path: | -# ./gremlin-server/* -# ~/.m2/repository/org/apache/tinkerpop/* -# key: ${{ github.sha }} -# - name: Load Docker Image -# working-directory: ./gremlin-server -# run: docker load --input gremlin-server.tar -# - name: Build with Maven -# run: | -# EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV" -# mvn clean install -pl $EXCLUDE -q -DskipTests -Dci -# mvn verify -pl :gremlin-javascript,:gremlint,:gremlin-mcp -Dnode.test.version=20 -# javascript-node22: -# name: javascript-glv-node22 -# timeout-minutes: 15 -# needs: cache-gremlin-server-docker-image -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v6 -# - name: Set up JDK 11 -# uses: actions/setup-java@v5 -# with: -# java-version: '11' -# distribution: 'temurin' -# - name: Get Cached Server Base Image -# uses: actions/cache@v5 -# id: gremlin-server-test-docker-image -# with: -# path: | -# ./gremlin-server/* -# ~/.m2/repository/org/apache/tinkerpop/* -# key: ${{ github.sha }} -# - name: Load Docker Image -# working-directory: ./gremlin-server -# run: docker load --input gremlin-server.tar -# - name: Build with Maven -# run: | -# EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV" -# mvn clean install -pl $EXCLUDE -q -DskipTests -Dci -# mvn verify -pl :gremlin-javascript -Dnode.test.version=22 -# javascript-node24: -# name: javascript-glv-node24 -# timeout-minutes: 15 -# needs: cache-gremlin-server-docker-image -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v6 -# - name: Set up JDK 11 -# uses: actions/setup-java@v5 -# with: -# java-version: '11' -# distribution: 'temurin' -# - name: Get Cached Server Base Image -# uses: actions/cache@v5 -# id: gremlin-server-test-docker-image -# with: -# path: | -# ./gremlin-server/* -# ~/.m2/repository/org/apache/tinkerpop/* -# key: ${{ github.sha }} -# - name: Load Docker Image -# working-directory: ./gremlin-server -# run: docker load --input gremlin-server.tar -# - name: Build with Maven -# run: | -# EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV" -# mvn clean install -pl $EXCLUDE -q -DskipTests -Dci -# mvn verify -pl :gremlin-javascript -Dnode.test.version=24 + javascript-node20: + name: javascript-all-node20 + timeout-minutes: 15 + needs: cache-gremlin-server-docker-image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Set up JDK 11 + uses: actions/setup-java@v5 + with: + java-version: '11' + distribution: 'temurin' + - name: Get Cached Server Base Image + uses: actions/cache@v5 + id: gremlin-server-test-docker-image + with: + path: | + ./gremlin-server/* + ~/.m2/repository/org/apache/tinkerpop/* + key: ${{ github.sha }} + - name: Load Docker Image + working-directory: ./gremlin-server + run: docker load --input gremlin-server.tar + - name: Build with Maven + run: | + EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV" + mvn clean install -pl $EXCLUDE -q -DskipTests -Dci + mvn verify -pl :gremlin-javascript,:gremlint,:gremlin-mcp -Dnode.test.version=20 + javascript-node22: + name: javascript-glv-node22 + timeout-minutes: 15 + needs: cache-gremlin-server-docker-image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Set up JDK 11 + uses: actions/setup-java@v5 + with: + java-version: '11' + distribution: 'temurin' + - name: Get Cached Server Base Image + uses: actions/cache@v5 + id: gremlin-server-test-docker-image + with: + path: | + ./gremlin-server/* + ~/.m2/repository/org/apache/tinkerpop/* + key: ${{ github.sha }} + - name: Load Docker Image + working-directory: ./gremlin-server + run: docker load --input gremlin-server.tar + - name: Build with Maven + run: | + EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV" + mvn clean install -pl $EXCLUDE -q -DskipTests -Dci + mvn verify -pl :gremlin-javascript -Dnode.test.version=22 + javascript-node24: + name: javascript-glv-node24 + timeout-minutes: 15 + needs: cache-gremlin-server-docker-image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Set up JDK 11 + uses: actions/setup-java@v5 + with: + java-version: '11' + distribution: 'temurin' + - name: Get Cached Server Base Image + uses: actions/cache@v5 + id: gremlin-server-test-docker-image + with: + path: | + ./gremlin-server/* + ~/.m2/repository/org/apache/tinkerpop/* + key: ${{ github.sha }} + - name: Load Docker Image + working-directory: ./gremlin-server + run: docker load --input gremlin-server.tar + - name: Build with Maven + run: | + EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV" + mvn clean install -pl $EXCLUDE -q -DskipTests -Dci + mvn verify -pl :gremlin-javascript -Dnode.test.version=24 python: name: python timeout-minutes: 20 diff --git a/gremlin-javascript/examples/node/basic-gremlin.js b/gremlin-javascript/examples/node/basic-gremlin.js index 98a5c33285..b5d2dfd8d8 100644 --- a/gremlin-javascript/examples/node/basic-gremlin.js +++ b/gremlin-javascript/examples/node/basic-gremlin.js @@ -21,7 +21,7 @@ const gremlin = require('gremlin'); const traversal = gremlin.process.AnonymousTraversalSource.traversal; const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection; -const serverUrl = process.env.GREMLIN_SERVER_URL || 'ws://localhost:8182/gremlin'; +const serverUrl = process.env.GREMLIN_SERVER_URL || 'http://localhost:8182/gremlin'; const vertexLabel = process.env.VERTEX_LABEL || 'person'; async function main() { diff --git a/gremlin-javascript/pom.xml b/gremlin-javascript/pom.xml index ab8aa45cce..4f3ff38987 100644 --- a/gremlin-javascript/pom.xml +++ b/gremlin-javascript/pom.xml @@ -236,9 +236,8 @@ limitations under the License. <!-- Test gremlin-javascript in Docker --> <profile> <id>glv-js</id> - <!-- TODO re-enable after gremlin-js is implemented --> <activation> - <activeByDefault>false</activeByDefault> + <activeByDefault>true</activeByDefault> </activation> <build> <finalName>${project.artifactId}-${project.version}</finalName> 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 81e786bf77..c8d75dd0a5 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/docker-compose.yml +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/docker-compose.yml @@ -53,7 +53,7 @@ services: - ../../../..:/gremlin-javascript environment: - DOCKER_ENVIRONMENT=true - - GREMLIN_SERVER_URL=ws://gremlin-server-test-js:45940/gremlin + - GREMLIN_SERVER_URL=http://gremlin-server-test-js:45940/gremlin - VERTEX_LABEL=javascript-example - IO_TEST_DIRECTORY=/js_app/gremlin-test/graphbinary/ working_dir: /js_app @@ -61,12 +61,13 @@ services: bash -c "npm config set cache /tmp --global && npm ci && npm run test && npm run features-docker && echo 'Running examples' - && cd /gremlin-javascript/src/main/javascript/gremlin-javascript && npm ci - && cd /gremlin-javascript/examples/node && npm ci - && node basic-gremlin.js - && node connections.js - && node modern-traversals.js - && echo 'All examples completed successfully'" + && cd /gremlin-javascript/src/main/javascript/gremlin-javascript && npm ci" +# TODO:: re-enable example running +# && cd /gremlin-javascript/examples/node && npm ci +# && node basic-gremlin.js +# && node connections.js +# && node modern-traversals.js +# && echo 'All examples completed successfully'" depends_on: gremlin-server-test-js: condition: service_healthy diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/mechanisms/sasl-mechanism-base.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/mechanisms/sasl-mechanism-base.ts deleted file mode 100644 index e23642ef6c..0000000000 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/mechanisms/sasl-mechanism-base.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AuthenticatorOptions } from '../authenticator.js'; - -export type SaslMechanismBaseOptions = AuthenticatorOptions & { authzid?: string }; - -export default abstract class SaslMechanismBase { - constructor(protected options: SaslMechanismBaseOptions) { - this.setopts(options); - } - - /** - * Returns the name of the mechanism - */ - get name(): string | null { - return null; - } - - /** - * Set the options for the mechanism - * @param {object} options Options specific to the mechanism - */ - setopts(options: SaslMechanismBaseOptions) { - this.options = options; - } - - /** - * Evaluates the challenge from the server and returns appropriate response - * @param {String} challenge Challenge string presented by the server - */ - abstract evaluateChallenge(challenge: String): any; -} diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/mechanisms/sasl-mechanism-plain.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/mechanisms/sasl-mechanism-plain.ts deleted file mode 100644 index f80cf4dd56..0000000000 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/mechanisms/sasl-mechanism-plain.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Buffer } from 'buffer'; -import SaslMechanismBase, { SaslMechanismBaseOptions } from './sasl-mechanism-base.js'; - -export type SaslMechanismPlainOptions = SaslMechanismBaseOptions & {}; - -export default class SaslMechanismPlain extends SaslMechanismBase { - /** - * Creates a new instance of SaslMechanismPlain. - * @param {Object} [options] The mechanism options. - * @param {String} [options.authzid] The identity of the client. - * @param {String} [options.username] The identity of user with access to server. - * @param {String} [options.password] The password of user with access to server. - * @constructor - */ - constructor(options: SaslMechanismPlainOptions) { - super(options); - - if ( - this.options?.username === undefined || - this.options.username === null || - this.options.username.length === 0 || - this.options.password === undefined || - this.options.password === null || - this.options.password.length === 0 - ) { - throw new Error('Missing credentials for SASL PLAIN mechanism'); - } - } - - /** - * Returns the name of the mechanism - */ - get name() { - return 'PLAIN'; - } - - /** - * Evaluates the challenge from the server and returns appropriate response. - * @param {String} challenge Challenge string presented by the server. - * @return {Object} A Promise that resolves to a valid sasl response object. - */ - evaluateChallenge(challenge: string) { - if (this._hasInitialResponse(challenge)) { - return Promise.resolve({ - saslMechanism: this.name, - sasl: this._saslArgument(this.options!.authzid!, this.options!.username!, this.options!.password!), - }); - } - - return Promise.resolve({ - sasl: this._saslArgument(this.options!.authzid!, this.options!.username!, this.options!.password!), - }); - } - - /** - * Generates a base64 encoded sasl argument based on the given parameters. - * @param {String} authzid Identitiy of the client. - * @param {String} username The identity of user with access to server. - * @param {String} password The password of user with access to server. - */ - _saslArgument(authzid: string, username: String, password: string) { - if (authzid === undefined || authzid === null) { - authzid = ''; - } - if (username === undefined || username === null) { - username = ''; - } - if (password === undefined || password.length === null) { - password = ''; - } - - return Buffer.from(`${authzid}\0${username}\0${password}`).toString('base64'); - } - - /** - * Checks challenge to see if we have the initial sasl response from the server. - * @param {String} challenge The challenge string from the server. - * @return {Boolean} - */ - _hasInitialResponse(challenge: string) { - if (challenge === undefined || challenge === null) { - return false; - } - return true; - } -} diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/plain-text-sasl-authenticator.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/plain-text-sasl-authenticator.ts deleted file mode 100644 index 9a45f21982..0000000000 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/plain-text-sasl-authenticator.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import Authenticator from './authenticator.js'; -import SaslMechanismPlain from './mechanisms/sasl-mechanism-plain.js'; - -export default class PlainTextSaslAuthenticator extends Authenticator { - /** - * Creates a new instance of PlainTextSaslAuthenticator. - * @param {string} username Username to log into the server. - * @param {string} password Password for the user. - * @param {string} [authzid] Optional id - * @constructor - */ - constructor(username: string, password: string, authzid?: string) { - const options = { - mechanism: new SaslMechanismPlain({ - username: username, - password: password, - authzid: authzid, - }), - }; - - super(options); - } - - /** - * Evaluates the challenge from the server and returns appropriate response. - * @param {String} challenge Challenge string presented by the server. - * @return {Object} A Promise that resolves to a valid sasl response object. - */ - evaluateChallenge(challenge: string): any { - return this.options.mechanism.evaluateChallenge(challenge); - } -} diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/sasl-authenticator.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/sasl-authenticator.ts deleted file mode 100644 index af5877f5bb..0000000000 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/auth/sasl-authenticator.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -import Authenticator, { AuthenticatorOptions } from './authenticator.js'; - -export type SaslAuthenticatorOptions = AuthenticatorOptions & { - mechanism?: any; -}; - -export default class SaslAuthenticator extends Authenticator { - /** - * Creates a new instance of SaslAuthenticator. - * @param {Object} [options] The authentication options. - * @param {Object} [options.mechanism] The mechanism to be used for authentication. - * @constructor - */ - constructor(options: SaslAuthenticatorOptions) { - super(options); - - if (options.mechanism === null || options.mechanism === undefined) { - throw new Error('No Sasl Mechanism Specified'); - } - } - - /** - * Evaluates the challenge from the server and returns appropriate response. - * @param {String} challenge Challenge string presented by the server. - * @return {Object} A Promise that resolves to a valid sasl response object. - */ - evaluateChallenge(challenge: string) { - return this.options.mechanism.evaluateChallenge(challenge); - } -} diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts index 943c47d45b..542f3ad54b 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.ts @@ -22,7 +22,6 @@ import { Readable } from 'stream'; import {RequestMessage} from "./request-message.js"; export type RequestOptions = { - requestId?: string; bindings?: any; language?: string; accept?: string; @@ -105,7 +104,7 @@ export default class Client { submit(message: string, bindings: any | null, requestOptions?: RequestOptions): Promise<any> { const requestBuilder = RequestMessage.build(message) .addG(this.options.traversalSource || 'g') - .addLanguage('gremlin-lang'); + .addLanguage(requestOptions?.language || 'gremlin-lang'); if (requestOptions?.bindings) { requestBuilder.addBindings(requestOptions.bindings); @@ -113,6 +112,12 @@ export default class Client { if (bindings) { requestBuilder.addBindings(bindings); } + if (requestOptions?.materializeProperties) { + requestBuilder.addMaterializeProperties(requestOptions.materializeProperties) + } + if (requestOptions?.evaluationTimeout) { + requestBuilder.addTimeoutMillis(requestOptions.evaluationTimeout) + } return this._connection.submit(requestBuilder.create()); } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts index 59b07469b7..d2f03b1f63 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.ts @@ -210,10 +210,15 @@ export default class Connection extends EventEmitter { try { if (reader) { const deserialized = reader.readResponse(buffer); + const attributes = new Map(); + if (deserialized.status.exception) { + attributes.set('exceptions', deserialized.status.exception); + attributes.set('stackTrace', deserialized.status.exception); + } throw new ResponseError(errorMessage, { code: deserialized.status.code, message: deserialized.status.message || response.statusText, - attributes: deserialized.status.attributes || new Map(), + attributes: attributes, }); } else if (contentType === 'application/json') { const errorBody = JSON.parse(buffer.toString()); @@ -243,17 +248,22 @@ export default class Connection extends EventEmitter { const deserialized = reader.readResponse(buffer); if (deserialized.status.code && deserialized.status.code !== 200 && deserialized.status.code !== 204 && deserialized.status.code !== 206) { + const attributes = new Map(); + if (deserialized.status.exception) { + attributes.set('exceptions', deserialized.status.exception); + attributes.set('stackTrace', deserialized.status.exception); + } throw new ResponseError( - `Server returned status ${deserialized.status.code}: ${deserialized.status.message || 'Unknown error'}`, + `Server error: ${deserialized.status.message || 'Unknown error'} (${deserialized.status.code})`, { code: deserialized.status.code, message: deserialized.status.message || '', - attributes: deserialized.status.attributes || new Map(), + attributes: attributes, } ); } - return new ResultSet(deserialized.result.data, deserialized.result.meta || new Map()); + return new ResultSet(deserialized.result.data, new Map()); } /** diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.ts index 396dc18c2f..0be87ed420 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.ts @@ -101,7 +101,7 @@ export abstract class RemoteConnection { */ export class RemoteTraversal extends Traversal { constructor( - public traversers: Traverser<any>[], + public results: Traverser<any>[], public sideEffects?: any[], ) { super(null, null); @@ -114,21 +114,18 @@ export class RemoteStrategy extends TraversalStrategy { * @param {RemoteConnection} connection */ constructor(public connection: RemoteConnection) { - // gave this a fqcn that has a local "js:" prefix since this strategy isn't sent to the server. - // this is a sort of local-only strategy that actually executes client side. not sure if this prefix is the - // right way to name this or not, but it should have a name to identify it. - super('js:RemoteStrategy'); + super(); } /** @override */ apply(traversal: Traversal) { - if (traversal.traversers) { + if (traversal.results) { return Promise.resolve(); } return this.connection.submit(traversal.getGremlinLang()).then(function (remoteTraversal: RemoteTraversal) { traversal.sideEffects = remoteTraversal.sideEffects; - traversal.traversers = remoteTraversal.traversers; + traversal.results = remoteTraversal.results; }); } } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts index 507265b02f..75fb4989e3 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/index.ts @@ -34,7 +34,6 @@ import ResponseError from './driver/response-error.js'; import Client from './driver/client.js'; import ResultSet from './driver/result-set.js'; import Authenticator from './driver/auth/authenticator.js'; -import PlainTextSaslAuthenticator from './driver/auth/plain-text-sasl-authenticator.js'; import AnonymousTraversalSource from './process/anonymous-traversal.js'; export const driver = { @@ -47,7 +46,6 @@ export const driver = { ResultSet, auth: { Authenticator, - PlainTextSaslAuthenticator, }, }; diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.ts index 4d657797ce..3d5dd6274a 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.ts @@ -49,7 +49,7 @@ export class GraphTraversalSource { public graphTraversalSourceClass: typeof GraphTraversalSource = GraphTraversalSource, public graphTraversalClass: typeof GraphTraversal = GraphTraversal, ) { - const strat = traversalStrategies.strategies.find((ts) => ts.fqcn === 'js:RemoteStrategy'); + const strat = traversalStrategies.strategies.find((ts) => ts.strategyName === 'RemoteStrategy'); this.remoteConnection = strat !== undefined ? strat.connection : undefined; } @@ -278,14 +278,6 @@ export class GraphTraversalSource { * @returns {GraphTraversal} */ mergeE(...args: any[]): GraphTraversal { - if (args && args[0]) { - if (args[0].get(direction.out) instanceof Vertex) { - args[0].set(direction.out, args[0].get(direction.out).id); - } - if (args[0].get(direction.in) instanceof Vertex) { - args[0].set(direction.in, args[0].get(direction.in).id); - } - } const gl = new GremlinLang(this.gremlinLang).addStep('mergeE', args); return new this.graphTraversalClass(this.graph, new TraversalStrategies(this.traversalStrategies), gl); } @@ -461,6 +453,16 @@ export class GraphTraversal extends Traversal { return this; } + /** + * Graph traversal asBool method. + * @param {...Object} args + * @returns {GraphTraversal} + */ + asBool(...args: any[]): this { + this.gremlinLang.addStep('asBool', args); + return this; + } + /** * Graph traversal asDate method. * @param {...Object} args @@ -1140,14 +1142,6 @@ export class GraphTraversal extends Traversal { * @returns {GraphTraversal} */ mergeE(...args: any[]): this { - if (args && args[0]) { - if (args[0].get(direction.out) instanceof Vertex) { - args[0].set(direction.out, args[0].get(direction.out).id); - } - if (args[0].get(direction.in) instanceof Vertex) { - args[0].set(direction.in, args[0].get(direction.in).id); - } - } this.gremlinLang.addStep('mergeE', args); return this; } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/gremlin-lang.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/gremlin-lang.ts index da8483f1f5..c75e742a2d 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/gremlin-lang.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/gremlin-lang.ts @@ -94,7 +94,7 @@ export default class GremlinLang { return arg.toString(); } if (arg instanceof TraversalStrategy && !(arg instanceof OptionsStrategy)) { - const simpleName = arg.fqcn.split('.').pop() || arg.fqcn; + const simpleName = arg.strategyName; const configEntries = Object.entries(arg.configuration); if (configEntries.length === 0) { return simpleName; diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal-strategy.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal-strategy.ts index 139c07f345..912e01a8dd 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal-strategy.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal-strategy.ts @@ -48,7 +48,7 @@ export class TraversalStrategies { /** @param {TraversalStrategy} strategy */ removeStrategy(strategy: TraversalStrategy) { - const idx = this.strategies.findIndex((s) => s.fqcn === strategy.fqcn); + const idx = this.strategies.findIndex((s) => s.strategyName === strategy.strategyName); if (idx !== -1) { return this.strategies.splice(idx, 1)[0]; } @@ -73,15 +73,16 @@ export type TraversalStrategyConfiguration = any; export abstract class TraversalStrategy { connection?: RemoteConnection; + public strategyName: string; /** - * @param {String} fqcn fully qualified class name in Java of the strategy * @param {TraversalStrategyConfiguration} configuration for the strategy */ constructor( - public fqcn: string, public configuration: TraversalStrategyConfiguration = {}, - ) {} + ) { + this.strategyName = this.constructor.name; + } /** * @abstract @@ -93,13 +94,13 @@ export abstract class TraversalStrategy { export class ConnectiveStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy'); + super(); } } export class ElementIdStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategy'); + super(); } } @@ -107,23 +108,20 @@ export class HaltedTraverserStrategy extends TraversalStrategy { /** * @param {String} haltedTraverserFactory full qualified class name in Java of a {@code HaltedTraverserFactory} implementation */ - constructor(haltedTraverserFactory: string) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy'); - if (haltedTraverserFactory !== undefined) { - this.configuration['haltedTraverserFactory'] = haltedTraverserFactory; - } + constructor({haltedTraverserFactory = ""}) { + super({haltedTraverserFactory: haltedTraverserFactory}); } } export class MessagePassingReductionStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimization.MessagePassingReductionStrategy'); - } + constructor() { + super(); + } } export class OptionsStrategy extends TraversalStrategy { constructor(options: TraversalStrategyConfiguration) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy', options); + super(options); } } @@ -136,14 +134,14 @@ export class PartitionStrategy extends TraversalStrategy { * @param {boolean} [options.includeMetaProperties] determines if meta-properties should be included in partitioning defaulting to false */ constructor(options: TraversalStrategyConfiguration) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy', options); + super(options); } } export class ProfileStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ProfileStrategy'); - } + constructor() { + super(); + } } export class SubgraphStrategy extends TraversalStrategy { @@ -155,7 +153,7 @@ export class SubgraphStrategy extends TraversalStrategy { * @param {boolean} [options.checkAdjacentVertices] enables the strategy to apply the {@code vertices} filter to the adjacent vertices of an edge. */ constructor(options: TraversalStrategyConfiguration) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy', options); + super(options); if (this.configuration.vertices instanceof Traversal) { this.configuration.vertices = this.configuration.vertices.gremlinLang; } @@ -174,19 +172,19 @@ export class ProductiveByStrategy extends TraversalStrategy { * @param {Array<String>} [options.productiveKeys] set of keys that will always be productive */ constructor(options: TraversalStrategyConfiguration) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ProductiveByStrategy', options); + super(options); } } export class ReferenceElementStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ReferenceElementStrategy'); - } + constructor() { + super(); + } } export class VertexProgramStrategy extends TraversalStrategy { constructor(options: TraversalStrategyConfiguration) { - super('org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy', options); + super(options); } } @@ -194,125 +192,122 @@ export class MatchAlgorithmStrategy extends TraversalStrategy { /** * @param matchAlgorithm */ - constructor(matchAlgorithm: string) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy'); - if (matchAlgorithm !== undefined) { - this.configuration['matchAlgorithm'] = matchAlgorithm; - } + constructor({matchAlgorithm = ""}) { + super({matchAlgorithm: matchAlgorithm}); } } export class ComputerFinalizationStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.finalization.ComputerFinalizationStrategy'); - } + constructor() { + super(); + } } export class AdjacentToIncidentStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy'); + super(); } } export class FilterRankingStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy'); + super(); } } export class ByModulatorOptimizationStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ByModulatorOptimizationStrategy'); - } + constructor() { + super(); + } } export class IdentityRemovalStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy'); + super(); } } export class IncidentToAdjacentStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategy'); + super(); } } export class InlineFilterStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.InlineFilterStrategy'); + super(); } } export class LazyBarrierStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.LazyBarrierStrategy'); + super(); } } export class MatchPredicateStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.MatchPredicateStrategy'); + super(); } } export class OrderLimitStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.OrderLimitStrategy'); + super(); } } export class PathProcessorStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathProcessorStrategy'); + super(); } } export class PathRetractionStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy'); + super(); } } export class CountStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy'); + super(); } } export class RepeatUnrollStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy'); + super(); } } export class GraphFilterStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimization.GraphFilterStrategy'); + super(); } } export class EarlyLimitStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy'); + super(); } } export class ComputerVerificationStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy'); - } + constructor() { + super(); + } } export class LambdaRestrictionStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy'); + super(); } } export class ReadOnlyStrategy extends TraversalStrategy { constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy'); + super(); } } @@ -321,8 +316,8 @@ export class EdgeLabelVerificationStrategy extends TraversalStrategy { * @param {boolean} logWarnings determines if warnings should be written to the logger when verification fails * @param {boolean} throwException determines if exceptions should be thrown when verifications fails */ - constructor(logWarnings = false, throwException = false) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy', { + constructor({logWarnings = false, throwException = false} = {}) { + super({ logWarnings: logWarnings, throwException: throwException, }); @@ -335,8 +330,8 @@ export class ReservedKeysVerificationStrategy extends TraversalStrategy { * @param {boolean} throwException determines if exceptions should be thrown when verifications fails * @param {Array<String>} keys the list of reserved keys to verify */ - constructor(logWarnings = false, throwException = false, keys = ['id', 'label']) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReservedKeysVerificationStrategy', { + constructor({ logWarnings = false, throwException = false, keys = ['id', 'label'] } = {}) { + super({ logWarnings: logWarnings, throwException: throwException, keys: keys, @@ -345,17 +340,15 @@ export class ReservedKeysVerificationStrategy extends TraversalStrategy { } export class VertexProgramRestrictionStrategy extends TraversalStrategy { - constructor() { - super( - 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy', - ); - } + constructor() { + super(); + } } export class StandardVerificationStrategy extends TraversalStrategy { - constructor() { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.StandardVerificationStrategy'); - } + constructor() { + super(); + } } export type SeedStrategyOptions = { seed: number }; @@ -366,7 +359,7 @@ export class SeedStrategy extends TraversalStrategy { * @param {number} [options.seed] the seed to provide to the random number generator for the traversal */ constructor(options: SeedStrategyOptions) { - super('org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SeedStrategy', { + super({ seed: options.seed, }); } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.ts index 9f9e04c042..6813911fa7 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.ts @@ -29,10 +29,10 @@ const itemDone = Object.freeze({ value: null, done: true }); const asyncIteratorSymbol = Symbol.asyncIterator || Symbol('@@asyncIterator'); export class Traversal { - traversers: Traverser<any>[] | null = null; + results: any[] | null = null; sideEffects?: any = null; private _traversalStrategiesPromise: Promise<void> | null = null; - private _traversersIteratorIndex = 0; + private _resultsIteratorIndex = 0; constructor( public graph: Graph | null, @@ -74,10 +74,10 @@ export class Traversal { hasNext() { return this._applyStrategies().then( () => - this.traversers && - this.traversers.length > 0 && - this._traversersIteratorIndex < this.traversers.length && - this.traversers[this._traversersIteratorIndex].bulk > 0, + this.results && + this.results.length > 0 && + this._resultsIteratorIndex < this.results.length && + this.results[this._resultsIteratorIndex] instanceof Traverser ? this.results[this._resultsIteratorIndex].bulk > 0 : true, ); } @@ -109,13 +109,21 @@ export class Traversal { * @private */ _getNext<T>(): IteratorResult<T, null> { - while (this.traversers && this._traversersIteratorIndex < this.traversers.length) { - const traverser = this.traversers[this._traversersIteratorIndex]; - if (traverser.bulk > 0) { - traverser.bulk--; - return { value: traverser.object, done: false }; + while (this.results && this._resultsIteratorIndex < this.results.length) { + const next = this.results[this._resultsIteratorIndex]; + + if (next instanceof Traverser) { + if (next.bulk > 0) { + next.bulk--; + return { value: next.object, done: false }; + } + } + + this._resultsIteratorIndex++; + + if (!(next instanceof Traverser)) { + return { value: next, done: false }; } - this._traversersIteratorIndex++; } return itemDone; } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js index 001c4a19fa..b64245ea45 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryReader.js @@ -47,7 +47,7 @@ export default class GraphBinaryReader { // {version} is a Byte representing the protocol version const version = cursor[0]; - if (version !== 0x84) { + if (version !== 0x81) { throw new Error(`Unsupported version '${version}'.`); } cursor = cursor.slice(1); // skip version diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js index af427e504d..87ba1f5e21 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/GraphBinaryWriter.js @@ -31,14 +31,56 @@ export default class GraphBinaryWriter { this.ioc = ioc; } - writeRequest({ gremlin, fields }) { + writeRequest(requestMessage) { + const fields = new Map(); + + // Extract fields from RequestMessage if it has getter methods + if (typeof requestMessage.getLanguage === 'function') { + const language = requestMessage.getLanguage(); + if (language) { + fields.set('language', language); + } + const g = requestMessage.getG(); + if (g) { + fields.set('g', g); + } + const bindings = requestMessage.getBindings(); + if (bindings && Object.keys(bindings).length > 0) { + fields.set('bindings', bindings); + } + const timeoutMs = requestMessage.getTimeoutMs(); + if (timeoutMs !== undefined) { + fields.set('timeoutMs', timeoutMs); + } + const materializeProperties = requestMessage.getMaterializeProperties(); + if (materializeProperties) { + fields.set('materializeProperties', materializeProperties); + } + const bulkResults = requestMessage.getBulkResults(); + if (bulkResults !== undefined) { + fields.set('bulkResults', bulkResults); + } + + // Add any custom fields + const customFields = requestMessage.getFields(); + if (customFields) { + customFields.forEach((v, k) => fields.set(k, v)); + } + + const gremlin = requestMessage.getGremlin(); + const bufs = [ + Buffer.from([0x81]), + this.ioc.mapSerializer.serialize(fields, false), + this.ioc.stringSerializer.serialize(gremlin, false), + ]; + return Buffer.concat(bufs); + } + + // Legacy path: plain object with { gremlin, fields } const bufs = [ - // {version} 1 byte - Buffer.from([0x84]), - // {fields} Map bare - this.ioc.mapSerializer.serialize(fields || new Map(), false), - // {gremlin} String bare - this.ioc.stringSerializer.serialize(gremlin, false), + Buffer.from([0x81]), + this.ioc.mapSerializer.serialize(requestMessage.fields || new Map(), false), + this.ioc.stringSerializer.serialize(requestMessage.gremlin, false), ]; return Buffer.concat(bufs); } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.ts b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.ts index 352c13582b..63e8695fcf 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.ts +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.ts @@ -253,7 +253,7 @@ export class TraversalStrategySerializer extends TypeSerializer<ts.TraversalStra return { [typeKey]: 'g:' + item.constructor.name, - [valueKey]: { ['fqcn']: item.fqcn, ['conf']: conf }, + [valueKey]: { ['strategyName']: item.strategyName, ['conf']: conf }, }; } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json index 72f6eab5b7..b8cbb3fae3 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json @@ -68,16 +68,13 @@ "prepare": "npm run build", "test": "npm run unit-test && npm run integration-test", "unit-test": "cross-env TS_NODE_PROJECT='tsconfig.test.json' mocha 'test/unit/**/*-test.{js,ts}'", - "integration-test": "npm run integration-test-graphson30 && npm run integration-test-graphbinary", - "integration-test-graphson30": "cross-env TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.gremlin-v3.0+json' ./node_modules/mocha/bin/mocha.js test/integration -t 5000", + "integration-test": "npm run integration-test-graphbinary", "integration-test-graphbinary": "cross-env TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.graphbinary-v4.0' ./node_modules/mocha/bin/mocha.js test/integration -t 5000", "TODO": "# test other mime types like graphbinary stringd", - "features": "npm run features-graphson30 && npm run features-graphbinary", - "features-graphson30": "cross-env NODE_OPTIONS='--loader ts-node/esm' TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.gremlin-v3.0+json' cucumber-js --tags \"not @DataUUID and not @DataLong\" --import test/cucumber ../../../../../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/", - "features-graphbinary": "cross-env NODE_OPTIONS='--loader ts-node/esm' TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.graphbinary-v4.0' cucumber-js --tags \"not @DataBigDecimal and not @DataBigInt and not @DataUUID and not @DataLong\" --import test/cucumber ../../../../../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/", - "features-docker": "npm run features-graphson30-docker && npm run features-graphbinary-docker", - "features-graphson30-docker": "cross-env NODE_OPTIONS='--loader ts-node/esm' TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.gremlin-v3.0+json' cucumber-js --tags \"not @DataUUID and not @DataLong\" --import test/cucumber ../gremlin-test/", - "features-graphbinary-docker": "cross-env NODE_OPTIONS='--loader ts-node/esm' TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.graphbinary-v4.0' cucumber-js --tags \"not @DataBigDecimal and not @DataBigInt and not @DataUUID and not @DataLong\" --import test/cucumber ../gremlin-test/", + "features": "npm run features-graphbinary", + "features-graphbinary": "cross-env NODE_OPTIONS='--loader ts-node/esm' TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.graphbinary-v4.0' cucumber-js --tags \"not @DataBigDecimal and not @DataBigInt and not @DataUUID and not @DataLong and not @StepWrite\" --import test/cucumber ../../../../../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/", + "features-docker": "npm run features-graphbinary-docker", + "features-graphbinary-docker": "cross-env NODE_OPTIONS='--loader ts-node/esm' TS_NODE_PROJECT='tsconfig.test.json' CLIENT_MIMETYPE='application/vnd.graphbinary-v4.0' cucumber-js --tags \"not @DataBigDecimal and not @DataBigInt and not @DataUUID and not @DataLong and not @StepWrite\" --import test/cucumber ../gremlin-test/", "lint": "eslint --ext .js ." }, "engines": { diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js index a570effcf0..25c935b61b 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js @@ -29,16 +29,18 @@ import { use, expect } from 'chai'; use(chaiString); import { inspect, format, inherits } from 'util'; import { gremlin } from './gremlin.js'; -import { Path, Vertex, Edge } from '../../lib/structure/graph.js'; +import { Path, Vertex, Edge, Property } from '../../lib/structure/graph.js'; import { statics } from '../../lib/process/graph-traversal.js'; import { t, P, direction, merge, barrier, cardinality, column, order, TextP, IO, pick, pop, scope, operator, withOptions } from '../../lib/process/traversal.js'; import { toLong } from '../../lib/utils.js'; import anon from '../../lib/process/anonymous-traversal.js'; const __ = statics; import { deepMembersById } from './element-comparison.js'; +import GremlinLang from "../../lib/process/gremlin-lang.js"; const parsers = [ [ 'str\\[(.*)\\]', (stringValue) => stringValue ], //returns the string value as is [ 'vp\\[(.+)\\]', toVertexProperty ], + [ 'prop\\[(.+)\\]', toProperty ], [ 'dt\\[(.+)\\]', toDateTime ], [ 'uuid\\[(.+)\\]', toUuid ], [ 'd\\[(.*)\\]\\.[bsilfdmn]', toNumeric ], @@ -68,6 +70,7 @@ const ignoreReason = { classNotSupported: "Javascript does not support the class type in GraphBinary", nullKeysInMapNotSupportedWell: "Javascript does not nicely support 'null' as a key in Map instances", floatingPointIssues: "Javascript floating point numbers not working in this case", + uuidSerializationIssues: "Javascript does not serialize to a UUID object, which complicates test assertions", subgraphStepNotSupported: "Javascript does not yet support subgraph()", treeStepNotSupported: "Javascript does not yet support tree()", needsFurtherInvestigation: '', @@ -96,6 +99,15 @@ const ignoredScenarios = { // floating point issues 'g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack': new IgnoreError(ignoreReason.floatingPointIssues), 'g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack': new IgnoreError(ignoreReason.floatingPointIssues), + // uuid issues + 'g_inject_order_byXdescX': new IgnoreError(ignoreReason.uuidSerializationIssues), + 'g_inject_order': new IgnoreError(ignoreReason.uuidSerializationIssues), + // GremlinLang converts number to "integer" which is unparseable with floatLiteral in grammar + 'g_V_coinX1X': new IgnoreError(ignoreReason.floatingPointIssues), + 'g_V_coinX0X': new IgnoreError(ignoreReason.floatingPointIssues), + 'g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX': new IgnoreError(ignoreReason.floatingPointIssues), + 'g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankX_withXedges_inEX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX': new IgnoreError(ignoreReason.floatingPointIssues), + 'g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_byXrankX_withXedges_outEXknowsX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X': new IgnoreError(ignoreReason.floatingPointIssues), }; Given(/^the (.+) graph$/, function (graphName) { @@ -129,9 +141,12 @@ Given('the traversal of', function (traversalText) { const p = Object.assign({}, this.parameters); p.g = this.g; this.traversal = gremlin[this.scenario].shift()(p); + const sideEffectLang = new GremlinLang(); for (const key in this.sideEffects) { - this.traversal.getBytecode().addSource('withSideEffect', [key, this.sideEffects[key]]); + sideEffectLang.addSource('withSideEffect', [key, this.sideEffects[key]]); } + // prepend the side effects to the query + this.traversal.getGremlinLang().gremlin = sideEffectLang.gremlin + this.traversal.getGremlinLang().gremlin; }); Given(/^using the parameter (.+) defined as "(.+)"$/, function (paramName, stringValue) { @@ -397,6 +412,13 @@ function toVertexProperty(name) { return vp; } +function toProperty(value) { + const commaIdx = value.indexOf(','); + const key = value.substring(0, commaIdx); + const val = parseValue.call(this, value.substring(commaIdx + 1)); + return new Property(key, val); +} + function toPath(value) { const parts = value.split(','); return new Path(new Array(0), parts.map(x => parseValue.call(this, x))); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js index 09026dddc1..657b47beb7 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js @@ -21,10 +21,8 @@ * @author Jorge Bay Gondra */ -import * as utilsJs from '../lib/utils.js'; import DriverRemoteConnection from '../lib/driver/driver-remote-connection.js'; import Client from '../lib/driver/client.js'; -import PlainTextSaslAuthenticator from '../lib/driver/auth/plain-text-sasl-authenticator.js'; import jsYaml from 'js-yaml'; import fs from 'fs'; @@ -50,43 +48,16 @@ export function getConnection(traversalSource) { return new DriverRemoteConnection(serverUrl, { traversalSource, mimeType: process.env.CLIENT_MIMETYPE }); } -export function getSecureConnectionWithPlainTextSaslAuthenticator(traversalSource, username, password) { - const authenticator = new PlainTextSaslAuthenticator(username, password); - return new DriverRemoteConnection(serverAuthUrl, { - traversalSource, - authenticator, - rejectUnauthorized: false, - mimeType: process.env.CLIENT_MIMETYPE, - }); -} - export function getDriverRemoteConnection(url, options) { return new DriverRemoteConnection(url, { ...options, mimeType: process.env.CLIENT_MIMETYPE }); } -export function getDriverRemoteConnectionGraphSON(traversalSource) { - return new DriverRemoteConnection(serverUrl, { traversalSource, mimeType: 'application/vnd.gremlin-v3.0+json' }); -} - export function getClient(traversalSource) { return new Client(serverUrl, { traversalSource, mimeType: process.env.CLIENT_MIMETYPE }); } function getMimeTypeFromSocketServerSettings(socketServerSettings) { - let mimeType; - switch(socketServerSettings.SERIALIZER) { - case "GraphSONV2": - mimeType = 'application/vnd.gremlin-v2.0+json'; - break; - case "GraphSONV3": - mimeType = 'application/vnd.gremlin-v3.0+json'; - break; - case "GraphBinaryV1": - default: - mimeType = 'application/vnd.graphbinary-v4.0'; - break; - } - return mimeType; + return 'application/vnd.graphbinary-v4.0'; } export function getGremlinSocketServerClient(traversalSource) { diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js deleted file mode 100644 index 6ce1fb7727..0000000000 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import assert from 'assert'; -import { getGremlinSocketServerClient, getGremlinSocketServerSettings, getGremlinSocketServerClientNoUserAgent } from '../helper.js'; -import { getUserAgent } from "../../lib/utils.js"; - -let client; -let settings; - -describe('Client', function () { - before(function () { - client = getGremlinSocketServerClient('gmodern'); - settings = getGremlinSocketServerSettings(); - return client.open(); - }); - after(function () { - return client.close(); - }); - describe('#submit()', function () { - it('should reconnect after server closes connection', async function () { - let connectionClosed = false; - await client.submit('1', null, {requestId: settings.CLOSE_CONNECTION_REQUEST_ID}) - .catch(function(error){ - assert.equal(error.toString(), 'Error: Connection has been closed.'); - connectionClosed = true; - }); - - assert.equal(connectionClosed, true); - - let result = await client.submit('1', null, {requestId: settings.SINGLE_VERTEX_REQUEST_ID}) - assert.ok(result); - }); - it('should include user agent in handshake request', async function () { - let result = await client.submit('1', null, {requestId: settings.USER_AGENT_REQUEST_ID}); - - assert.strictEqual(result.first(), await getUserAgent()); - }); - it('should not include user agent in handshake request if disabled', async function () { - let noUserAgentClient = getGremlinSocketServerClientNoUserAgent('gmodern'); - let result = await noUserAgentClient.submit('1', null, - {requestId: settings.USER_AGENT_REQUEST_ID}); - - assert.ok(result.first() === "" || result.first() === "node"); // The default node websocket library may use a default user-agent of "node" if none is specified - - await noUserAgentClient.close(); - }); - it('should send per request settings to server', async function () { - const resultSet = await client.submit('1', null, { - requestId: settings.PER_REQUEST_SETTINGS_REQUEST_ID, - evaluationTimeout: 1234, - batchSize: 12, - userAgent: 'helloWorld', - materializeProperties: 'tokens' - }) - const expectedResult = `requestId=${settings.PER_REQUEST_SETTINGS_REQUEST_ID} evaluationTimeout=1234, batchSize=12, userAgent=helloWorld, materializeProperties=tokens`; - assert.equal(expectedResult, resultSet.first()); - }); - }); -}); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js index c050f37d7e..d197b627d1 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-tests.js @@ -26,7 +26,7 @@ let client, clientCrew; describe('Client', function () { before(function () { - client = getClient('g'); + client = getClient('gmodern'); clientCrew = getClient('gcrew') return client.open(); }); @@ -50,28 +50,20 @@ describe('Client', function () { assert.strictEqual(result.first(), 29); }); }); - it('should send and parse a script with non-native javascript bindings', function () { - return client.submit('card.class.simpleName + ":" + card', { card: cardinality.set }) - .then(function (result) { - assert.ok(result); - assert.strictEqual(result.first(), 'Cardinality:set'); - }); - }); it('should retrieve the attributes', () => { return client.submit("g.V().tail()") .then(rs => { assert.ok(rs.attributes instanceof Map); - assert.ok(rs.attributes.get('host')); }); }); it('should skip Vertex properties for request with tokens', function () { - return client.submit("g.V(1)", null, {'materializeProperties': 'tokens'}) + return client.submit('g.with("materializeProperties", "tokens").V(1)') .then(function (result) { assert.ok(result); assert.strictEqual(result.length, 1); - const vertex = result.first().object; + const vertex = result.first(); assert.ok(vertex instanceof Vertex); assert.ok(vertex.properties.length === 0); }); @@ -152,105 +144,18 @@ describe('Client', function () { await crewClient.close(); }); - it('should be able to stream results from the gremlin server', (done) => { - const output = []; - let calls = 0; - const readable = client.stream('g.V().limit(3)', {}, { batchSize: 2 }); - - readable.on('data', (data) => { - calls += 1; - data.toArray().forEach(v => output.push(v)) - }) - - readable.on('end', () => { - assert.strictEqual(calls, 2); // limit of 3 with batchSize of 2 should be two function calls - assert.strictEqual(output.length, 3); - assert.ok(output[0] instanceof Vertex); - done(); - }) - }); - - it("should be able to iterate stream results async", async () => { - const output = []; - let calls = 0; - const readable = client.stream("g.V().limit(3)", {}, { batchSize: 2 }); - - for await (const result of readable) { - calls += 1; - result.toArray().forEach((v) => output.push(v)); - } - - assert.strictEqual(calls, 2); // limit of 3 with batchSize of 2 should be two function calls - assert.strictEqual(output.length, 3); - assert.ok(output[0] instanceof Vertex); - }); - - it("should get error for malformed requestId for script stream", async () => { - try { - const readable = client.stream('g.V()', {}, {requestId: 'malformed'}); - for await (const result of readable) { - assert.fail("malformed requestId should throw"); - } - } catch (e) { - assert.ok(e); - assert.ok(e.message); - assert.ok(e.message.includes("is not a valid UUID.")); - } - }); - - it("should get error for malformed requestId for script submit", async () => { - try { - await client.submit('g.V()', {}, {requestId: 'malformed'}); - assert.fail("malformed requestId should throw"); - } catch (e) { - assert.ok(e); - assert.ok(e.message); - assert.ok(e.message.includes("is not a valid UUID.")); - } - }); - - it("should reject pending traversal promises if connection closes", async () => { - const closingClient = getClient('gmodern'); - await closingClient.open(); - const timeout = 10000; - const startTime = Date.now(); - let isRejected = false; - - const pending = async function submitTraversals() { - while (Date.now() < startTime + timeout) { - try { - await closingClient.submit("g.V().tail()"); - } catch (e) { - isRejected = true; - return; - } - } - }; - const pendingPromise = pending(); - - await closingClient.close(); - await pendingPromise; - assert.strictEqual(isRejected, true); - }); - - it("should end streams on traversals if connection closes", async () => { - const closingClient = getClient('gmodern'); - await closingClient.open(); - let isRejected = false; - - const readable = client.stream('g.V().limit(3)', {}, { batchSize: 2 }); - - readable.on('end', () => { - isRejected = true; - }); - - await closingClient.close(); - for await (const result of readable) { - // Consume the stream - } - - assert.strictEqual(isRejected, true); - }); + // TODO:: Revisit what it means to close a client in HTTP. + // it("should reject pending traversal promises if connection closes", async () => { + // const closingClient = getClient('gmodern'); + // await closingClient.open(); + // + // // verify the client works before closing + // const result = await closingClient.submit("g.V().tail()"); + // assert.ok(result); + // + // await closingClient.close(); + // assert.ok(!closingClient.isOpen()); + // }); }); }); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/remote-connection-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/remote-connection-tests.js index 73727d18ef..8316b2f853 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/remote-connection-tests.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/remote-connection-tests.js @@ -23,40 +23,45 @@ import assert from 'assert'; import { Vertex } from '../../lib/structure/graph.js'; -import { getConnection } from '../helper.js'; +import anon from '../../lib/process/anonymous-traversal.js'; +import { getConnection, getClient } from '../helper.js'; let connection; +let client; describe('DriverRemoteConnection', function () { before(function () { connection = getConnection('gmodern'); + client = getClient('gmodern'); return connection.open(); }); after(function () { + client.close(); return connection.close(); }); describe('#submit()', function () { it('should send the request and parse the response', function () { - return connection.submit('g.V().tail()') - .then(function (response) { - assert.ok(response); - assert.ok(response.traversers); - assert.strictEqual(response.traversers.length, 1); - assert.ok(response.traversers[0].object instanceof Vertex); + const g = anon.traversal().with_(connection); + return g.V().tail().toList() + .then(function (list) { + assert.ok(list); + assert.strictEqual(list.length, 1); + assert.ok(list[0] instanceof Vertex); }); }); it('should send the request with syntax error and parse the response error', function () { - return connection.submit('SYNTAX_ERROR') + return client.submit('SYNTAX_ERROR') + .then(function() { + assert.fail("syntax error should throw"); + }) .catch(function (err) { assert.ok(err); - assert.ok(err.message.indexOf('599') > 0); - assert.ok(err.statusCode === 599); - assert.ok(err.statusMessage === 'Could not locate method: GraphTraversalSource.SYNTAX_ERROR()'); + assert.ok(err.statusCode === 400); assert.ok(err.statusAttributes); assert.ok(err.statusAttributes.has('exceptions')); assert.ok(err.statusAttributes.has('stackTrace')); }); }); }); -}); \ No newline at end of file +}); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/sasl-authentication-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/sasl-authentication-tests.js deleted file mode 100644 index fd38fbcdbd..0000000000 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/sasl-authentication-tests.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import assert from 'assert'; -import { AssertionError } from 'assert'; -import anon from '../../lib/process/anonymous-traversal.js'; -import { getSecureConnectionWithPlainTextSaslAuthenticator, getDriverRemoteConnection } from '../helper.js'; -import PlainTextSaslAuthenticator from '../../lib/driver/auth/plain-text-sasl-authenticator.js'; - -let connection; -let badServerAuthUrl; -if (process.env.DOCKER_ENVIRONMENT === 'true') { - badServerAuthUrl = 'ws://gremlin-server-test-js:45941/gremlin'; -} else { - badServerAuthUrl = 'ws://localhost:45941/gremlin'; -} - -describe('DriverRemoteConnection', function () { - context('with PlainTextSaslAuthenticator', function () { - this.timeout(20000); - - afterEach(function () { - return connection.close(); - }); - - describe('#submit()', function () { - it('should send the request with valid credentials and parse the response', function () { - connection = getSecureConnectionWithPlainTextSaslAuthenticator(null, 'stephen', 'password'); - - return connection.submit('g.V().tail()') - .then(function (response) { - assert.ok(response); - assert.ok(response.traversers); - }); - }); - - it('should send the request with invalid credentials and parse the response error', function () { - connection = getSecureConnectionWithPlainTextSaslAuthenticator(null, 'Bob', 'password'); - - return connection.submit('g.V().tail()') - .then(function() { - assert.fail("invalid credentials should throw"); - }) - .catch(function (err) { - assert.ok(err); - assert.ok(err.message.indexOf('401') > 0); - }); - }); - - it('should return error when using ws:// for a TLS configured server', function () { - const authenticator = new PlainTextSaslAuthenticator('stephen', 'password'); - connection = getDriverRemoteConnection(badServerAuthUrl, { - authenticator: authenticator, - rejectUnauthorized: false - }); - - return connection.submit('g.V().tail()') - .then(function() { - assert.fail("server is running TLS and trying to connect with ws:// so this should result in error thrown"); - }) - .catch(function (err) { - if (err instanceof AssertionError) throw err; - assert.ok(err); - assert.ok(err.message === 'socket hang up'); - }); - }); - - it('should return error when using ws:// for a TLS configured server', function () { - const authenticator = new PlainTextSaslAuthenticator('stephen', 'password'); - connection = getDriverRemoteConnection(badServerAuthUrl, { - authenticator: authenticator, - rejectUnauthorized: false - }); - - const g = anon.traversal().with_(connection); - return g.V().toList().then(function() { - assert.fail("server is running TLS and trying to connect with ws:// so this should result in error thrown"); - }).catch(function(err) { - if (err instanceof AssertionError) throw err; - assert.ok(err); - assert.ok(err.message === 'socket hang up'); - }); - }); - }); - }); -}); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/socket-connection-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/socket-connection-tests.js index b4ab338b36..423967493e 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/socket-connection-tests.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/socket-connection-tests.js @@ -25,7 +25,7 @@ import assert from "assert"; import http from "http"; import url from "url"; -import * as helper from "../helper.js"; +import Client from '../../lib/driver/client.js'; const testServerPort = 45944; const testServer401ResponseBody = 'Invalid credentials provided'; @@ -48,72 +48,26 @@ describe('Connection', function () { return server.close(); }); - describe('#open()', function () { - it('should use the ws WebSocket when ws specific options are provided', function () { - let globalWebsocketCalls = 0; - globalThis.WebSocket = function () { - globalWebsocketCalls++; - }; - const wsSpecificOptions = [ - 'headers', - 'ca', - 'cert', - 'pfx', - 'rejectUnauthorized', - 'agent', - 'perMessageDeflate', - ]; - const allOptionTests = wsSpecificOptions.map((wsOption) => { - const connection = helper.getDriverRemoteConnection(`ws://localhost:${testServerPort}/401`, { - [wsOption]: 'this option is set', - }); - return connection.open(); - }); - return Promise.allSettled(allOptionTests).then(function () { - assert.equal(globalWebsocketCalls, 0, 'global WebSocket should be used when no ws specific options are provided'); - }); + describe('#submit()', function () { + it('should handle unexpected response errors with body', async function () { + const client = new Client(`http://localhost:${testServerPort}/401`, {}); + try { + await client.submit('g.V()'); + assert.fail('invalid status codes should throw'); + } catch (err) { + assert.ok(err); + assert.ok(err.message.indexOf('401') > 0); + } }); - it('should use the global WebSocket when options are not provided', function () { - let globalWebsocketCalls = 0; - globalThis.WebSocket = function () { - globalWebsocketCalls++; - }; - const connection = helper.getDriverRemoteConnection(`ws://localhost:${testServerPort}/401`, - {enableUserAgentOnConnect: false}); // Global WebSocket is not compatible with user agent headers - return connection - .open() - .catch(() => {}) - .finally(function () { - assert.equal(globalWebsocketCalls, 1, 'global WebSocket should be used when no ws specific options are provided'); - }); - }); - it('should handle unexpected response errors with body', function () { - globalThis.WebSocket = http.WebSocket; - const connection = helper.getDriverRemoteConnection(`ws://localhost:${testServerPort}/401`); - return connection - .open() - .then(function () { - assert.fail('invalid status codes should throw'); - }) - .catch(function (err) { - assert.ok(err); - assert.ok(err.message.indexOf(401) > 0); - assert.ok(err.message.indexOf(testServer401ResponseBody) > 0); - }); - }); - it('should handle unexpected response errors with no body', function () { - globalThis.WebSocket = undefined; - const connection = helper.getDriverRemoteConnection(`ws://localhost:${testServerPort}/404`); - return connection - .open() - .then(function () { - assert.fail('invalid status codes should throw'); - }) - .catch(function (err) { - assert.ok(err); - assert.ok(err.message.indexOf(404) > 0); - assert.ok(err.message.indexOf('body') < 0); - }); + it('should handle unexpected response errors with no body', async function () { + const client = new Client(`http://localhost:${testServerPort}/404`, {}); + try { + await client.submit('g.V()'); + assert.fail('invalid status codes should throw'); + } catch (err) { + assert.ok(err); + assert.ok(err.message.indexOf('404') > 0); + } }); }); }); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js index a23757984e..9ef9dc1008 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js @@ -26,11 +26,12 @@ import { AssertionError } from 'assert'; import {Edge, Vertex, VertexProperty} from '../../lib/structure/graph.js'; import anon from '../../lib/process/anonymous-traversal.js'; import { GraphTraversalSource, GraphTraversal, statics } from '../../lib/process/graph-traversal.js'; -import { SubgraphStrategy, ReadOnlyStrategy, SeedStrategy,HaltedTraverserStrategy, FilterRankingStrategy, - OptionsStrategy, ReservedKeysVerificationStrategy, EdgeLabelVerificationStrategy } from '../../lib/process/traversal-strategy.js'; +import { + SubgraphStrategy, ReadOnlyStrategy, SeedStrategy, HaltedTraverserStrategy, FilterRankingStrategy, + OptionsStrategy, ReservedKeysVerificationStrategy, EdgeLabelVerificationStrategy, MatchAlgorithmStrategy +} from '../../lib/process/traversal-strategy.js'; import GremlinLang from '../../lib/process/gremlin-lang.js'; import { getConnection, getDriverRemoteConnection } from '../helper.js'; -import * as helper from '../helper.js'; const __ = statics; let connection; @@ -74,12 +75,12 @@ describe('Traversal', function () { }); describe("#construct", function () { it('should not hang if server not present', function() { - const g = anon.traversal().with_(getDriverRemoteConnection('ws://localhost:9998/gremlin', {traversalSource: 'g'})); + const g = anon.traversal().with_(getDriverRemoteConnection('http://localhost:9998/gremlin', {traversalSource: 'g'})); return g.V().toList().then(function() { assert.fail("there is no server so an error should have occurred"); }).catch(function(err) { if (err instanceof AssertionError) throw err; - assert.strictEqual(err.code, "ECONNREFUSED"); + assert.ok(err); }); }); }); @@ -225,15 +226,6 @@ describe('Traversal', function () { }); }); }); - describe('lambdas', function() { - it('should handle 1-arg lambdas', function() { - const g = anon.traversal().with_(connection); - return g.V().has('person','name','marko').values('name').map(() => "it.get()[1]").toList().then(function (s) { - assert.ok(s); - assert.strictEqual(s[0], 'a'); - }) - }); - }); describe('dsl', function() { it('should expose DSL methods', function() { const g = anon.traversal(SocialTraversalSource).with_(connection); @@ -311,7 +303,7 @@ describe('Traversal', function () { }); it('should allow with_(evaluationTimeout,10)', function() { const g = anon.traversal().with_(connection).with_('x').with_('evaluationTimeout', 10); - return g.V().repeat(__.both()).iterate().then(() => assert.fail("should have tanked"), (err) => assert.strictEqual(err.statusCode, 598)); + return g.V().repeat(__.both()).iterate().then(() => assert.fail("should have tanked"), (err) => assert.strictEqual(err.statusCode, 400)); }); it('should allow SeedStrategy', function () { const g = anon.traversal().with_(connection).withStrategies(new SeedStrategy({seed: 999999})); @@ -321,125 +313,124 @@ describe('Traversal', function () { }, (err) => assert.fail("tanked: " + err)); }); it('should allow without HaltedTraverserStrategy', function() { - const c = helper.getDriverRemoteConnectionGraphSON( 'gmodern'); - const g = anon.traversal().with_(c).withoutStrategies(HaltedTraverserStrategy); + const g = anon.traversal().with_(connection).withoutStrategies(HaltedTraverserStrategy); return g.V().count().next().then(function (item1) { assert.ok(item1); assert.strictEqual(item1.value, 6); - c.close(); }); }); it('should allow with FilterRankingStrategy', function() { - const c = helper.getDriverRemoteConnectionGraphSON( 'gmodern'); - const g = anon.traversal().with_(c).withStrategies(new FilterRankingStrategy()); + const g = anon.traversal().with_(connection).withStrategies(new FilterRankingStrategy()); return g.V().out().order().dedup().count().next().then(function (item1) { assert.ok(item1); assert.strictEqual(item1.value, 4); - c.close(); - }); - }); - }); - describe("should handle tx errors if graph not support tx", function() { - it('should throw exception on commit if graph not support tx', async function() { - const g = anon.traversal().withRemote(connection); - const tx = g.tx(); - const gtx = tx.begin(); - const result = await g.V().count().next(); - assert.strictEqual(6, result.value); - try { - await tx.commit(); - assert.fail("should throw error"); - } catch (err) { - assert.strictEqual("Server error: Graph does not support transactions (500)", err.message); - } - }); - it('should throw exception on rollback if graph not support tx', async function() { - const g = anon.traversal().withRemote(connection); - const tx = g.tx(); - tx.begin(); - try { - await tx.rollback(); - assert.fail("should throw error"); - } catch (err) { - assert.strictEqual("Server error: Graph does not support transactions (500)", err.message); - } - }); - }); - describe('support remote transactions - commit', function() { - before(function () { - txConnection = getConnection('gtx'); - return txConnection.open(); - }); - after(function () { - const g = anon.traversal().with_(txConnection); - return g.V().drop().iterate().then(() => { - return txConnection.close() }); }); - it('should commit a simple transaction', async function () { - const g = anon.traversal().with_(txConnection); - const tx = g.tx(); - const gtx = tx.begin(); - await Promise.all([ - gtx.addV("person").property("name", "jorge").iterate(), - gtx.addV("person").property("name", "josh").iterate() - ]); - - let r = await gtx.V().count().next(); - // assert within the transaction.... - assert.ok(r); - assert.strictEqual(r.value, 2); - - // now commit changes to test outside of the transaction - await tx.commit(); - - r = await g.V().count().next(); - assert.ok(r); - assert.strictEqual(r.value, 2); - // connection closing async, so need to wait - while (tx._sessionBasedConnection.isOpen) { - await new Promise(resolve => setTimeout(resolve, 10)); - } - assert.ok(!tx._sessionBasedConnection.isOpen); - }); - }); - describe('support remote transactions - rollback', function() { - before(function () { - - txConnection = getConnection('gtx'); - return txConnection.open(); - }); - after(function () { - const g = anon.traversal().with_(txConnection); - return g.V().drop().iterate().then(() => { - return txConnection.close() - }); - }); - it('should rollback a simple transaction', async function() { - const g = anon.traversal().with_(txConnection); - const tx = g.tx(); - const gtx = tx.begin(); - await Promise.all([ - gtx.addV("person").property("name", "jorge").iterate(), - gtx.addV("person").property("name", "josh").iterate() - ]); - - let r = await gtx.V().count().next(); - // assert within the transaction.... - assert.ok(r); - assert.strictEqual(r.value, 2); - - // now rollback changes to test outside of the transaction - await tx.rollback(); - - r = await g.V().count().next(); - assert.ok(r); - assert.strictEqual(r.value, 0); - // connection closing async, so need to wait - while (tx._sessionBasedConnection.isOpen) { - await new Promise(resolve => setTimeout(resolve, 10)); - } - assert.ok(!tx._sessionBasedConnection.isOpen); - }); }); + //TODO:: Re-enable after tx reimplementation + // describe("should handle tx errors if graph not support tx", function() { + // it('should throw exception on commit if graph not support tx', async function() { + // const g = anon.traversal().withRemote(connection); + // const tx = g.tx(); + // const gtx = tx.begin(); + // const result = await g.V().count().next(); + // assert.strictEqual(6, result.value); + // try { + // await tx.commit(); + // assert.fail("should throw error"); + // } catch (err) { + // assert.strictEqual(err.statusCode, 500); + // assert.ok(err.statusMessage.includes('Graph does not support transactions')); + // } + // }); + // it('should throw exception on rollback if graph not support tx', async function() { + // const g = anon.traversal().withRemote(connection); + // const tx = g.tx(); + // tx.begin(); + // try { + // await tx.rollback(); + // assert.fail("should throw error"); + // } catch (err) { + // assert.strictEqual(err.statusCode, 500); + // assert.ok(err.statusMessage.includes('Graph does not support transactions')); + // } + // }); + // }); + // describe('support remote transactions - commit', function() { + // before(function () { + // txConnection = getConnection('gtx'); + // return txConnection.open(); + // }); + // after(function () { + // const g = anon.traversal().with_(txConnection); + // return g.V().drop().iterate().then(() => { + // return txConnection.close() + // }); + // }); + // it('should commit a simple transaction', async function () { + // const g = anon.traversal().with_(txConnection); + // const tx = g.tx(); + // const gtx = tx.begin(); + // await Promise.all([ + // gtx.addV("person").property("name", "jorge").iterate(), + // gtx.addV("person").property("name", "josh").iterate() + // ]); + // + // let r = await gtx.V().count().next(); + // // assert within the transaction.... + // assert.ok(r); + // assert.strictEqual(r.value, 2); + // + // // now commit changes to test outside of the transaction + // await tx.commit(); + // + // r = await g.V().count().next(); + // assert.ok(r); + // assert.strictEqual(r.value, 2); + // // connection closing async, so need to wait + // while (tx._sessionBasedConnection.isOpen) { + // await new Promise(resolve => setTimeout(resolve, 10)); + // } + // assert.ok(!tx._sessionBasedConnection.isOpen); + // }); + // }); + // describe('support remote transactions - rollback', function() { + // before(function () { + // + // txConnection = getConnection('gtx'); + // return txConnection.open(); + // }); + // after(function () { + // const g = anon.traversal().with_(txConnection); + // return g.V().drop().iterate().then(() => { + // return txConnection.close() + // }); + // }); + // it('should rollback a simple transaction', async function() { + // const g = anon.traversal().with_(txConnection); + // const tx = g.tx(); + // const gtx = tx.begin(); + // await Promise.all([ + // gtx.addV("person").property("name", "jorge").iterate(), + // gtx.addV("person").property("name", "josh").iterate() + // ]); + // + // let r = await gtx.V().count().next(); + // // assert within the transaction.... + // assert.ok(r); + // assert.strictEqual(r.value, 2); + // + // // now rollback changes to test outside of the transaction + // await tx.rollback(); + // + // r = await g.V().count().next(); + // assert.ok(r); + // assert.strictEqual(r.value, 0); + // // connection closing async, so need to wait + // while (tx._sessionBasedConnection.isOpen) { + // await new Promise(resolve => setTimeout(resolve, 10)); + // } + // assert.ok(!tx._sessionBasedConnection.isOpen); + // }); + // }); }); \ No newline at end of file diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryReader-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryReader-test.js index bb006690b3..d9c3eec909 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryReader-test.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryReader-test.js @@ -20,7 +20,7 @@ /* * GraphBinaryReader v4 response format tests. * Tests the reader's ability to parse v4 response format: - * {version:0x84}{bulked:Byte}{result_data stream}{marker:0xFD 0x00 0x00}{status_code:Int bare}{status_message:nullable}{exception:nullable} + * {version:0x81}{bulked:Byte}{result_data stream}{marker:0xFD 0x00 0x00}{status_code:Int bare}{status_message:nullable}{exception:nullable} */ import { assert } from 'chai'; @@ -55,9 +55,9 @@ describe('GraphBinaryReader', () => { assert.throws(() => reader.readResponse(buffer), /Unsupported version '0'/); }); - it('rejects version 0x81', () => { - const buffer = Buffer.from([0x81]); - assert.throws(() => reader.readResponse(buffer), /Unsupported version '129'/); + it('rejects version 0x84', () => { + const buffer = Buffer.from([0x84]); + assert.throws(() => reader.readResponse(buffer), /Unsupported version '132'/); }); it('rejects version 0xFF', () => { @@ -69,7 +69,7 @@ describe('GraphBinaryReader', () => { describe('non-bulked responses', () => { it('single value', () => { const buffer = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, // bulked=false 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, // fq Int: type_code=0x01, value_flag=0x00, value=67 0xFD, 0x00, 0x00, // marker @@ -86,7 +86,7 @@ describe('GraphBinaryReader', () => { it('multiple values', () => { const buffer = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, // bulked=false 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, // fq Int: 67 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, // fq String: "hello" @@ -104,7 +104,7 @@ describe('GraphBinaryReader', () => { it('empty result', () => { const buffer = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, // bulked=false 0xFD, 0x00, 0x00, // marker (no data) 0x00, 0x00, 0x00, 0xCC, // status_code=204 @@ -122,7 +122,7 @@ describe('GraphBinaryReader', () => { describe('bulked responses', () => { it('single item with bulk count', () => { const buffer = Buffer.from([ - 0x84, // version + 0x81, // version 0x01, // bulked=true 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, // fq Int: 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // bare Long bulk=3 @@ -140,7 +140,7 @@ describe('GraphBinaryReader', () => { it('multiple items with bulk counts', () => { const buffer = Buffer.from([ - 0x84, // version + 0x81, // version 0x01, // bulked=true 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, // fq Int: 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // bare Long bulk=2 @@ -162,7 +162,7 @@ describe('GraphBinaryReader', () => { describe('status codes', () => { it('status 403', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker 0x00, 0x00, 0x01, 0x93, // status_code=403 0x01, 0x01 // null message, null exception @@ -173,7 +173,7 @@ describe('GraphBinaryReader', () => { it('status 500', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker 0x00, 0x00, 0x01, 0xF4, // status_code=500 0x01, 0x01 // null message, null exception @@ -186,7 +186,7 @@ describe('GraphBinaryReader', () => { describe('nullable status_message', () => { it('present message', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker 0x00, 0x00, 0x00, 0xC8, // status_code=200 0x00, // message present flag @@ -199,7 +199,7 @@ describe('GraphBinaryReader', () => { it('null message', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker 0x00, 0x00, 0x00, 0xC8, // status_code=200 0x01, // message null flag @@ -213,7 +213,7 @@ describe('GraphBinaryReader', () => { describe('nullable exception', () => { it('present exception', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker 0x00, 0x00, 0x01, 0xF4, // status_code=500 0x01, // message null @@ -226,7 +226,7 @@ describe('GraphBinaryReader', () => { it('null exception', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker 0x00, 0x00, 0x00, 0xC8, // status_code=200 0x01, // message null @@ -240,7 +240,7 @@ describe('GraphBinaryReader', () => { describe('error response', () => { it('no result data with error status', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0xFD, 0x00, 0x00, // marker (no data) 0x00, 0x00, 0x01, 0xF4, // status_code=500 0x00, // message present @@ -259,7 +259,7 @@ describe('GraphBinaryReader', () => { describe('complex result values', () => { it('vertex in result data', () => { const buffer = Buffer.from([ - 0x84, 0x00, // version, bulked=false + 0x81, 0x00, // version, bulked=false 0x11, 0x00, // fq Vertex: type_code=0x11, value_flag=0x00 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, // id: fq Int=1 0x00, 0x00, 0x00, 0x01, // label: bare List length=1 diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryWriter-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryWriter-test.js index d034915f54..23170941ea 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryWriter-test.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/GraphBinaryWriter-test.js @@ -20,7 +20,7 @@ /* * GraphBinaryWriter v4 request format tests. * Tests the writer's ability to generate v4 request format: - * {version:0x84}{fields:Map bare}{gremlin:String bare} + * {version:0x81}{fields:Map bare}{gremlin:String bare} */ import { assert } from 'chai'; @@ -32,9 +32,9 @@ describe('GraphBinaryWriter', () => { const writer = new GraphBinaryWriter(ioc); describe('version byte', () => { - it('first byte is 0x84', () => { + it('first byte is 0x81', () => { const result = writer.writeRequest({ gremlin: 'g.V()', fields: new Map() }); - assert.equal(result[0], 0x84); + assert.equal(result[0], 0x81); }); }); @@ -42,7 +42,7 @@ describe('GraphBinaryWriter', () => { it('empty map + bare string', () => { const result = writer.writeRequest({ gremlin: 'g.V()', fields: new Map() }); const expected = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, 0x00, 0x00, 0x00, // empty map bare (length=0) 0x00, 0x00, 0x00, 0x05, // string length=5 0x67, 0x2E, 0x56, 0x28, 0x29 // "g.V()" @@ -57,7 +57,7 @@ describe('GraphBinaryWriter', () => { fields.set('evaluationTimeout', 1000); const result = writer.writeRequest({ gremlin: 'g.V()', fields }); const expected = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, 0x00, 0x00, 0x01, // map length=1 0x03, 0x00, // key type_code=STRING, value_flag=0x00 0x00, 0x00, 0x00, 0x11, // key string length=17 @@ -75,7 +75,7 @@ describe('GraphBinaryWriter', () => { it('undefined fields defaults to empty map', () => { const result = writer.writeRequest({ gremlin: 'g.V()', fields: undefined }); const expected = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, 0x00, 0x00, 0x00, // empty map bare (length=0) 0x00, 0x00, 0x00, 0x05, // string length=5 0x67, 0x2E, 0x56, 0x28, 0x29 // "g.V()" @@ -86,7 +86,7 @@ describe('GraphBinaryWriter', () => { it('null fields defaults to empty map', () => { const result = writer.writeRequest({ gremlin: 'g.V()', fields: null }); const expected = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, 0x00, 0x00, 0x00, // empty map bare (length=0) 0x00, 0x00, 0x00, 0x05, // string length=5 0x67, 0x2E, 0x56, 0x28, 0x29 // "g.V()" @@ -112,7 +112,7 @@ describe('GraphBinaryWriter', () => { it('empty string has length 0', () => { const result = writer.writeRequest({ gremlin: '', fields: new Map() }); const expected = Buffer.from([ - 0x84, // version + 0x81, // version 0x00, 0x00, 0x00, 0x00, // empty map bare (length=0) 0x00, 0x00, 0x00, 0x00 // empty string bare (length=0) ]); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-strategy-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-strategy-test.js index 9e78af86ea..bc551abd0e 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-strategy-test.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-strategy-test.js @@ -31,7 +31,7 @@ describe('TraversalStrategies', function () { const c = new OptionsStrategy({x: 123}); const os = ts.removeStrategy(c); - assert.strictEqual(os.fqcn, c.fqcn); + assert.strictEqual(os.strategyName, c.strategyName); assert.strictEqual(ts.strategies.length, 1); ts.removeStrategy(new ConnectiveStrategy()); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js index 2e9c866a9f..d68cbbea06 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js @@ -39,7 +39,7 @@ describe('Traversal', function () { it('should apply the strategies and return a Promise with the iterator item', function () { const strategyMock = { apply: function (traversal) { - traversal.traversers = [ new Traverser(1, 1), new Traverser(2, 1) ]; + traversal.results = [ new Traverser(1, 1), new Traverser(2, 1) ]; return Promise.resolve(); } }; @@ -67,7 +67,7 @@ describe('Traversal', function () { it('should support bulk', function () { const strategyMock = { apply: function (traversal) { - traversal.traversers = [ new Traverser(1, 2), new Traverser(2, 1) ]; + traversal.results = [ new Traverser(1, 2), new Traverser(2, 1) ]; return Promise.resolve(); } }; @@ -112,7 +112,7 @@ describe('Traversal', function () { it('should apply the strategies and return a Promise with an array', function () { const strategyMock = { apply: function (traversal) { - traversal.traversers = [ new Traverser('a', 1), new Traverser('b', 1) ]; + traversal.results = [ new Traverser('a', 1), new Traverser('b', 1) ]; return Promise.resolve(); } }; @@ -128,7 +128,7 @@ describe('Traversal', function () { it('should return an empty array when traversers is empty', function () { const strategyMock = { apply: function (traversal) { - traversal.traversers = []; + traversal.results = []; return Promise.resolve(); } }; @@ -144,7 +144,7 @@ describe('Traversal', function () { it('should support bulk', function () { const strategyMock = { apply: function (traversal) { - traversal.traversers = [ new Traverser(1, 1), new Traverser(2, 3), new Traverser(3, 2), + traversal.results = [ new Traverser(1, 1), new Traverser(2, 3), new Traverser(3, 2), new Traverser(4, 1) ]; return Promise.resolve(); } @@ -165,7 +165,7 @@ describe('Traversal', function () { const strategyMock = { apply: function (traversal) { applied = true; - traversal.traversers = [ new Traverser('a', 1), new Traverser('b', 1) ]; + traversal.results = [ new Traverser('a', 1), new Traverser('b', 1) ]; return Promise.resolve(); } };
