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:33 UTC

[tinkerpop] branch TINKERPOP-2070 created (now 22057bd)

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

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


      at 22057bd  Extract Connection implementation from DriverRemoteConnection

This branch includes the following new commits:

     new 22057bd  Extract Connection implementation from DriverRemoteConnection

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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

Posted by jo...@apache.org.
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);
+          });
+      });
     });
   });
 });