You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by jo...@apache.org on 2018/10/22 14:49:34 UTC

[tinkerpop] 01/01: Extract Connection implementation from DriverRemoteConnection

This is an automated email from the ASF dual-hosted git repository.

jorgebg pushed a commit to branch TINKERPOP-2070
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 22057bd49645cc7e75147a6a9794f3d65adeadf0
Author: Jorge Bay Gondra <jo...@gmail.com>
AuthorDate: Mon Oct 22 16:48:59 2018 +0200

    Extract Connection implementation from DriverRemoteConnection
    
    Extract Connection implementation out of the DriverRemoteConnection.
    The DriverRemoteConnection uses a Client instance, a Client instance
    may contain one or more Connection instances.
---
 gremlin-javascript/pom.xml                         |  62 +++---
 .../gremlin-javascript/lib/driver/client.js        |  14 +-
 .../{driver-remote-connection.js => connection.js} |  71 ++++---
 .../lib/driver/driver-remote-connection.js         | 214 ++-------------------
 .../lib/driver/remote-connection.js                |  37 ++--
 .../javascript/gremlin-javascript/test/helper.js   |   6 +-
 .../test/integration/client-tests.js               |  16 +-
 .../test/integration/remote-connection-tests.js    |   1 +
 .../test/integration/sasl-authentication-tests.js  |  57 +++---
 9 files changed, 155 insertions(+), 323 deletions(-)

diff --git a/gremlin-javascript/pom.xml b/gremlin-javascript/pom.xml
index 68b91f6..fad3fde 100644
--- a/gremlin-javascript/pom.xml
+++ b/gremlin-javascript/pom.xml
@@ -179,37 +179,37 @@ limitations under the License.
                         </goals>
                     </execution>
                     <execution>
-                        <id>npm install</id>
-                        <phase>generate-test-resources</phase>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <configuration>
-                            <arguments>install</arguments>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>npm test</id>
-                        <phase>integration-test</phase>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <configuration>
-                            <arguments>test</arguments>
-                            <failOnError>true</failOnError>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>npm test gherkin features</id>
-                        <phase>integration-test</phase>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <configuration>
-                            <arguments>run-script features</arguments>
-                            <failOnError>true</failOnError>
-                        </configuration>
-                    </execution>
+                    <id>npm install</id>
+                    <phase>generate-test-resources</phase>
+                    <goals>
+                        <goal>npm</goal>
+                    </goals>
+                    <configuration>
+                        <arguments>install</arguments>
+                    </configuration>
+                </execution>
+                <execution>
+                    <id>npm test</id>
+                    <phase>integration-test</phase>
+                    <goals>
+                        <goal>npm</goal>
+                    </goals>
+                    <configuration>
+                        <arguments>test --exit</arguments>
+                        <failOnError>true</failOnError>
+                    </configuration>
+                </execution>
+                <execution>
+                    <id>npm test gherkin features</id>
+                    <phase>integration-test</phase>
+                    <goals>
+                        <goal>npm</goal>
+                    </goals>
+                    <configuration>
+                        <arguments>run-script features</arguments>
+                        <failOnError>true</failOnError>
+                    </configuration>
+                </execution>
                 </executions>
                 <configuration>
                     <skip>${skipTests}</skip>
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
index d91ce20..ccb7b8b 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/client.js
@@ -18,12 +18,16 @@
  */
 'use strict';
 
-const DriverRemoteConnection = require('./driver-remote-connection');
+const Connection = require('./connection');
 const Bytecode = require('../process/bytecode');
 
+/**
+ * A {@link Client} contains methods to send messages to a Gremlin Server.
+ */
 class Client {
+
   /**
-   * Creates a new instance of DriverRemoteConnection.
+   * Creates a new instance of {@link Client}.
    * @param {String} url The resource uri.
    * @param {Object} [options] The connection options.
    * @param {Array} [options.ca] Trusted certificates.
@@ -39,7 +43,7 @@ class Client {
    */
   constructor(url, options) {
     this._options = options;
-    this._connection = new DriverRemoteConnection(url, options);
+    this._connection = new Connection(url, options);
   }
 
   /**
@@ -53,7 +57,7 @@ class Client {
   /**
    * Send a request to the Gremlin Server, can send a script or bytecode steps.
    * @param {Bytecode|string} message The bytecode or script to send
-   * @param {Object} bindings The script bindings, if any.
+   * @param {Object} [bindings] The script bindings, if any.
    * @returns {Promise}
    */
   submit(message, bindings) {
@@ -62,7 +66,7 @@ class Client {
         'gremlin': message,
         'bindings': bindings, 
         'language': 'gremlin-groovy',
-        'accept': 'application/vnd.gremlin-v2.0+json',
+        'accept': this._connection.mimeType,
         'aliases': { 'g': this._options.traversalSource || 'g' }
       };
 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js
similarity index 82%
copy from gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
copy to gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js
index a1d3d42..0f1e732 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js
@@ -24,21 +24,25 @@
 
 const WebSocket = require('ws');
 const util = require('util');
-const t = require('../process/traversal');
-const RemoteConnection = require('./remote-connection').RemoteConnection;
 const utils = require('../utils');
 const serializer = require('../structure/io/graph-serializer');
+
 const responseStatusCode = {
   success: 200,
   noContent: 204,
   partialContent: 206,
   authenticationChallenge:  407,
 };
+
 const defaultMimeType = 'application/vnd.gremlin-v3.0+json';
 
-class DriverRemoteConnection extends RemoteConnection {
+/**
+ * Represents a single connection to a Gremlin Server.
+ */
+class Connection {
+
   /**
-   * Creates a new instance of DriverRemoteConnection.
+   * Creates a new instance of {@link Connection}.
    * @param {String} url The resource uri.
    * @param {Object} [options] The connection options.
    * @param {Array} [options.ca] Trusted certificates.
@@ -54,7 +58,7 @@ class DriverRemoteConnection extends RemoteConnection {
    * @constructor
    */
   constructor(url, options) {
-    super(url);
+    this.url = url;
     options = options || {};
     this._ws = new WebSocket(url, {
       headers: options.headers,
@@ -63,13 +67,16 @@ class DriverRemoteConnection extends RemoteConnection {
       pfx: options.pfx,
       rejectUnauthorized: options.rejectUnauthorized
     });
+
     this._ws.on('open', () => {
       this.isOpen = true;
       if (this._openCallback) {
         this._openCallback();
       }
     });
+
     this._ws.on('message', data => this._handleMessage(data));
+
     // A map containing the request id and the handler
     this._responseHandlers = {};
     this._reader = options.reader || new serializer.GraphSONReader();
@@ -77,14 +84,17 @@ class DriverRemoteConnection extends RemoteConnection {
     this._openPromise = null;
     this._openCallback = null;
     this._closePromise = null;
-    const mimeType = options.mimeType || defaultMimeType;
-    this._header = String.fromCharCode(mimeType.length) + mimeType;
+
+    /**
+     * Gets the MIME type.
+     * @type {String}
+     */
+    this.mimeType = options.mimeType || defaultMimeType;
+
+    this._header = String.fromCharCode(this.mimeType.length) + this.mimeType;
     this.isOpen = false;
     this.traversalSource = options.traversalSource || 'g';
-
-    if (options.authenticator) {
-      this._authenticator = options.authenticator;
-    }
+    this._authenticator = options.authenticator;
   }
 
   /**
@@ -118,7 +128,7 @@ class DriverRemoteConnection extends RemoteConnection {
         };
       }
 
-      const message = bufferFromString(this._header + JSON.stringify(this._getRequest(requestId, bytecode, op, args, processor)));
+      const message = Buffer.from(this._header + JSON.stringify(this._getRequest(requestId, bytecode, op, args, processor)));
       this._ws.send(message);
     }));
   }
@@ -143,20 +153,20 @@ class DriverRemoteConnection extends RemoteConnection {
   _handleMessage(data) {
     const response = this._reader.read(JSON.parse(data.toString()));
     if (response.requestId === null || response.requestId === undefined) {
-        // There was a serialization issue on the server that prevented the parsing of the request id
-        // We invoke any of the pending handlers with an error
-        Object.keys(this._responseHandlers).forEach(requestId => {
-          const handler = this._responseHandlers[requestId];
-          this._clearHandler(requestId);
-          if (response.status !== undefined && response.status.message) {
-            return handler.callback(
-              new Error(util.format(
-                'Server error (no request information): %s (%d)', response.status.message, response.status.code)));
-          } else {
-            return handler.callback(new Error(util.format('Server error (no request information): %j', response)));
-          }
-        });
-        return;
+      // There was a serialization issue on the server that prevented the parsing of the request id
+      // We invoke any of the pending handlers with an error
+      Object.keys(this._responseHandlers).forEach(requestId => {
+        const handler = this._responseHandlers[requestId];
+        this._clearHandler(requestId);
+        if (response.status !== undefined && response.status.message) {
+          return handler.callback(
+            new Error(util.format(
+              'Server error (no request information): %s (%d)', response.status.message, response.status.code)));
+        } else {
+          return handler.callback(new Error(util.format('Server error (no request information): %j', response)));
+        }
+      });
+      return;
     }
 
     const handler = this._responseHandlers[response.requestId];
@@ -210,7 +220,8 @@ class DriverRemoteConnection extends RemoteConnection {
 
   /**
    * Takes the given args map and ensures all arguments are passed through to _write.adaptObject
-   * @param {Object} args Map of arguments to process
+   * @param {Object} args Map of arguments to process.
+   * @param {Boolean} protocolLevel Determines whether it's a protocol level binding.
    * @returns {Object}
    * @private
    */
@@ -251,8 +262,4 @@ class DriverRemoteConnection extends RemoteConnection {
   }
 }
 
-const bufferFromString = (Int8Array.from !== Buffer.from && Buffer.from) || function newBuffer(text) {
-  return new Buffer(text, 'utf8');
-};
-
-module.exports = DriverRemoteConnection;
+module.exports = Connection;
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
index a1d3d42..f4021d4 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
@@ -22,23 +22,16 @@
  */
 'use strict';
 
-const WebSocket = require('ws');
-const util = require('util');
-const t = require('../process/traversal');
 const RemoteConnection = require('./remote-connection').RemoteConnection;
-const utils = require('../utils');
-const serializer = require('../structure/io/graph-serializer');
-const responseStatusCode = {
-  success: 200,
-  noContent: 204,
-  partialContent: 206,
-  authenticationChallenge:  407,
-};
-const defaultMimeType = 'application/vnd.gremlin-v3.0+json';
+const Client = require('./client');
 
+/**
+ * Represents the default {@link RemoteConnection} implementation.
+ */
 class DriverRemoteConnection extends RemoteConnection {
+
   /**
-   * Creates a new instance of DriverRemoteConnection.
+   * Creates a new instance of {@link DriverRemoteConnection}.
    * @param {String} url The resource uri.
    * @param {Object} [options] The connection options.
    * @param {Array} [options.ca] Trusted certificates.
@@ -55,204 +48,23 @@ class DriverRemoteConnection extends RemoteConnection {
    */
   constructor(url, options) {
     super(url);
-    options = options || {};
-    this._ws = new WebSocket(url, {
-      headers: options.headers,
-      ca: options.ca,
-      cert: options.cert,
-      pfx: options.pfx,
-      rejectUnauthorized: options.rejectUnauthorized
-    });
-    this._ws.on('open', () => {
-      this.isOpen = true;
-      if (this._openCallback) {
-        this._openCallback();
-      }
-    });
-    this._ws.on('message', data => this._handleMessage(data));
-    // A map containing the request id and the handler
-    this._responseHandlers = {};
-    this._reader = options.reader || new serializer.GraphSONReader();
-    this._writer = options.writer || new serializer.GraphSONWriter();
-    this._openPromise = null;
-    this._openCallback = null;
-    this._closePromise = null;
-    const mimeType = options.mimeType || defaultMimeType;
-    this._header = String.fromCharCode(mimeType.length) + mimeType;
-    this.isOpen = false;
-    this.traversalSource = options.traversalSource || 'g';
-
-    if (options.authenticator) {
-      this._authenticator = options.authenticator;
-    }
+    this._client = new Client(url, options);
   }
 
-  /**
-   * Opens the connection, if its not already opened.
-   * @returns {Promise}
-   */
+  /** @override */
   open() {
-    if (this._closePromise) {
-      return this._openPromise = Promise.reject(new Error('Connection has been closed'));
-    }
-    if (this.isOpen) {
-      return Promise.resolve();
-    }
-    if (this._openPromise) {
-      return this._openPromise;
-    }
-    return this._openPromise = new Promise((resolve, reject) => {
-      // Set the callback that will be invoked once the WS is opened
-      this._openCallback = err => err ? reject(err) : resolve();
-    });
+    return this._client.open();
   }
 
   /** @override */
-  submit(bytecode, op, args, requestId, processor) {
-    return this.open().then(() => new Promise((resolve, reject) => {
-      if (requestId === null || requestId === undefined) {
-        requestId = utils.getUuid();
-        this._responseHandlers[requestId] = {
-          callback: (err, result) => err ? reject(err) : resolve(result),
-          result: null
-        };
-      }
-
-      const message = bufferFromString(this._header + JSON.stringify(this._getRequest(requestId, bytecode, op, args, processor)));
-      this._ws.send(message);
-    }));
+  submit(bytecode) {
+    return this._client.submit(bytecode);
   }
 
-  _getRequest(id, bytecode, op, args, processor) {
-    if (args) {
-      args = this._adaptArgs(args, true);
-    }
-
-    return ({
-      'requestId': { '@type': 'g:UUID', '@value': id },
-      'op': op || 'bytecode',
-      // if using op eval need to ensure processor stays unset if caller didn't set it.
-      'processor': (!processor && op !== 'eval') ? 'traversal' : processor,
-      'args': args || {
-        'gremlin': this._writer.adaptObject(bytecode),
-        'aliases': { 'g': this.traversalSource }
-      }
-    });
-  }
-
-  _handleMessage(data) {
-    const response = this._reader.read(JSON.parse(data.toString()));
-    if (response.requestId === null || response.requestId === undefined) {
-        // There was a serialization issue on the server that prevented the parsing of the request id
-        // We invoke any of the pending handlers with an error
-        Object.keys(this._responseHandlers).forEach(requestId => {
-          const handler = this._responseHandlers[requestId];
-          this._clearHandler(requestId);
-          if (response.status !== undefined && response.status.message) {
-            return handler.callback(
-              new Error(util.format(
-                'Server error (no request information): %s (%d)', response.status.message, response.status.code)));
-          } else {
-            return handler.callback(new Error(util.format('Server error (no request information): %j', response)));
-          }
-        });
-        return;
-    }
-
-    const handler = this._responseHandlers[response.requestId];
-
-    if (!handler) {
-      // The handler for a given request id was not found
-      // It was probably invoked earlier due to a serialization issue.
-      return;
-    }
-
-    if (response.status.code === responseStatusCode.authenticationChallenge && this._authenticator) {
-      this._authenticator.evaluateChallenge(response.result.data).then(res => {
-        return this.submit(null, 'authentication', res, response.requestId);
-      }).catch(handler.callback);
-
-      return;
-    }
-    else if (response.status.code >= 400) {
-      // callback in error
-      return handler.callback(
-        new Error(util.format('Server error: %s (%d)', response.status.message, response.status.code)));
-    }
-    switch (response.status.code) {
-      case responseStatusCode.noContent:
-        this._clearHandler(response.requestId);
-        return handler.callback(null, { traversers: []});
-      case responseStatusCode.partialContent:
-        handler.result = handler.result || [];
-        handler.result.push.apply(handler.result, response.result.data);
-        break;
-      default:
-        if (handler.result) {
-          handler.result.push.apply(handler.result, response.result.data);
-        }
-        else {
-          handler.result = response.result.data;
-        }
-        this._clearHandler(response.requestId);
-        return handler.callback(null, { traversers: handler.result });
-    }
-  }
-
-  /**
-   * Clears the internal state containing the callback and result buffer of a given request.
-   * @param requestId
-   * @private
-   */
-  _clearHandler(requestId) {
-    delete this._responseHandlers[requestId];
-  }
-
-  /**
-   * Takes the given args map and ensures all arguments are passed through to _write.adaptObject
-   * @param {Object} args Map of arguments to process
-   * @returns {Object}
-   * @private
-   */
-  _adaptArgs(args, protocolLevel) {
-    if (args instanceof Object) {
-      let newObj = {};
-      Object.keys(args).forEach((key) => {
-        // bindings key (at the protocol-level needs special handling. without this, it wraps the generated Map
-        // in another map for types like EnumValue. Could be a nicer way to do this but for now it's solving the
-        // problem with script submission of non JSON native types
-        if (protocolLevel && key === 'bindings')
-          newObj[key] = this._adaptArgs(args[key], false);
-        else
-          newObj[key] = this._writer.adaptObject(args[key]);
-      });
-
-      return newObj;
-    }
-
-    return args;
-  }
-
-  /**
-   * Closes the Connection.
-   * @return {Promise}
-   */
+  /** @override */
   close() {
-    if (!this._closePromise) {
-      this._closePromise = new Promise(resolve => {
-        this._ws.on('close', function () {
-          this.isOpen = false;
-          resolve();
-        });
-        this._ws.close();
-      });
-    }
-    return this._closePromise;
+    return this._client.close();
   }
 }
 
-const bufferFromString = (Int8Array.from !== Buffer.from && Buffer.from) || function newBuffer(text) {
-  return new Buffer(text, 'utf8');
-};
-
 module.exports = DriverRemoteConnection;
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
index c675c42..9f70679 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/remote-connection.js
@@ -25,23 +25,40 @@
 const t = require('../process/traversal');
 const TraversalStrategy = require('../process/traversal-strategy').TraversalStrategy;
 
+/**
+ * Represents an abstraction of a "connection" to a "server" that is capable of processing a traversal and
+ * returning results.
+ */
 class RemoteConnection {
   constructor(url) {
     this.url = url;
   }
 
   /**
+   * Opens the connection, if its not already opened.
+   * @returns {Promise}
+   */
+  open() {
+    throw new Error('open() must be implemented');
+  }
+
+  /**
+   * Submits the <code>Bytecode</code> provided and returns a <code>RemoteTraversal</code>.
    * @abstract
    * @param {Bytecode} bytecode
-   * @param {String} op Operation to perform, defaults to bytecode.
-   * @param {Object} args The arguments for the operation. Defaults to an associative array containing values for "aliases" and "gremlin" keys.
-   * @param {String} requestId A requestId for the current request. If none provided then a requestId is generated internally.
-   * @param {String} processor The processor to use on the connection.
-   * @returns {Promise}
+   * @returns {Promise} Returns a <code>Promise</code> that resolves to a <code>RemoteTraversal</code>.
    */
-  submit(bytecode, op, args, requestId, processor) {
-    throw new Error('submit() was not implemented');
+  submit(bytecode) {
+    throw new Error('submit() must be implemented');
   };
+
+  /**
+   * Closes the connection, if its not already opened.
+   * @returns {Promise}
+   */
+  close() {
+    throw new Error('close() must be implemented');
+  }
 }
 
 class RemoteTraversal extends t.Traversal {
@@ -75,8 +92,4 @@ class RemoteStrategy extends TraversalStrategy {
   }
 }
 
-module.exports = {
-  RemoteConnection: RemoteConnection,
-  RemoteStrategy: RemoteStrategy,
-  RemoteTraversal: RemoteTraversal
-};
+module.exports = { RemoteConnection, RemoteStrategy, RemoteTraversal };
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 b2a61d2..53358c3 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
@@ -21,18 +21,18 @@
  * @author Jorge Bay Gondra
  */
 'use strict';
-const os = require('os');
 
 const DriverRemoteConnection = require('../lib/driver/driver-remote-connection');
 const Client = require('../lib/driver/client');
 const PlainTextSaslAuthenticator = require('../lib/driver/auth/plain-text-sasl-authenticator');
 
+/** @returns {DriverRemoteConnection} */
 exports.getConnection = function getConnection(traversalSource) {
   return new DriverRemoteConnection('ws://localhost:45940/gremlin', { traversalSource: traversalSource });
 };
 
-exports.getSecureConnectionWithPlainTextSaslAuthenticator = function getConnection(traversalSource) {
-  const authenticator = new PlainTextSaslAuthenticator('stephen', 'password');
+exports.getSecureConnectionWithPlainTextSaslAuthenticator = (traversalSource, username, password) => {
+  const authenticator = new PlainTextSaslAuthenticator(username, password);
   return new DriverRemoteConnection('ws://localhost:45941/gremlin', { 
     traversalSource: traversalSource, 
     authenticator: authenticator, 
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 88d871a..ffad6d6 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
@@ -25,19 +25,19 @@ const graphModule = require('../../lib/structure/graph');
 const helper = require('../helper');
 const t = require('../../lib/process/traversal');
 
-let connection;
+let client;
 
 describe('Client', function () {
   before(function () {
-    connection = helper.getClient('gmodern');
-    return connection.open();
+    client = helper.getClient('gmodern');
+    return client.open();
   });
   after(function () {
-    return connection.close();
+    return client.close();
   });
   describe('#submit()', function () {
     it('should send bytecode', function () {
-      return connection.submit(new Bytecode().addStep('V', []).addStep('tail', []))
+      return client.submit(new Bytecode().addStep('V', []).addStep('tail', []))
         .then(function (response) {
           assert.ok(response);
           assert.ok(response.traversers);
@@ -46,7 +46,7 @@ describe('Client', function () {
         });
     });
     it('should send and parse a script', function () {
-      return connection.submit('g.V().tail()')
+      return client.submit('g.V().tail()')
         .then(function (response) {
           assert.ok(response);
           assert.ok(response.traversers);
@@ -55,7 +55,7 @@ describe('Client', function () {
         });
     });
     it('should send and parse a script with bindings', function () {
-      return connection.submit('x + x', { x: 3 })
+      return client.submit('x + x', { x: 3 })
         .then(function (response) {
           assert.ok(response);
           assert.ok(response.traversers);
@@ -63,7 +63,7 @@ describe('Client', function () {
         });
     });
     it('should send and parse a script with non-native javascript bindings', function () {
-      return connection.submit('card.class.simpleName + ":" + card', { card: t.cardinality.set } )
+      return client.submit('card.class.simpleName + ":" + card', { card: t.cardinality.set } )
         .then(function (response) {
           assert.ok(response);
           assert.strictEqual(response.traversers[0], 'Cardinality:set');
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 afc0e58..b73d909 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
@@ -37,6 +37,7 @@ describe('DriverRemoteConnection', function () {
   after(function () {
     return connection.close();
   });
+
   describe('#submit()', function () {
     it('should send the request and parse the response', function () {
       return connection.submit(new Bytecode().addStep('V', []).addStep('tail', []))
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
index 2cf1dff..d0df3b1 100644
--- 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
@@ -21,43 +21,38 @@
 
 const assert = require('assert');
 const Bytecode = require('../../lib/process/bytecode');
-const graphModule = require('../../lib/structure/graph');
 const helper = require('../helper');
 
 let connection;
 
-describe('DriverRemoteConnectionWithPlainTextSaslAuthenticator', function () {
-  before(function () {
+describe('DriverRemoteConnection', function () {
+  context('with PlainTextSaslAuthenticator', function () {
     this.timeout(20000);
-    connection = helper.getSecureConnectionWithPlainTextSaslAuthenticator(null);
-    return connection.open();
-  });
-  after(function () {
-    return connection.close();
-  });
-  describe('#submit()', function () {
-    it('should send the request with valid credentials and parse the response', function () {
-      return connection.submit(new Bytecode().addStep('V', []).addStep('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._authenticator._options.mechanism._options.username = 'Bob';
-      return connection.submit(new Bytecode().addStep('V', []).addStep('tail', []))
-        .catch(function (err) {
-          assert.ok(err);
-          assert.ok(err.message.indexOf('401') > 0);
-        });
+
+    afterEach(function () {
+      return connection.close();
     });
-    it('should send incorrect configuration to the authenticator and parse the response error', function () {
-      delete connection._authenticator._options.mechanism._options.username;
-      delete connection._authenticator._options.mechanism._options.password;
-      return connection.submit(new Bytecode().addStep('V', []).addStep('tail', []))
-        .catch(function (err) {
-          assert.ok(err);
-        });
+
+    describe('#submit()', function () {
+      it('should send the request with valid credentials and parse the response', function () {
+        connection = helper.getSecureConnectionWithPlainTextSaslAuthenticator(null, 'stephen', 'password');
+
+        return connection.submit(new Bytecode().addStep('V', []).addStep('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 = helper.getSecureConnectionWithPlainTextSaslAuthenticator(null, 'Bob', 'password');
+
+        return connection.submit(new Bytecode().addStep('V', []).addStep('tail', []))
+          .catch(function (err) {
+            assert.ok(err);
+            assert.ok(err.message.indexOf('401') > 0);
+          });
+      });
     });
   });
 });