Skip to content

Commit

Permalink
fix: skip config validation when using connector
Browse files Browse the repository at this point in the history
This changeset fixes a problem in the original custom `connector`
factory method implementation that required the `server` config property
to be defined even though its value is ignored.

Removing the validation when `config.options.connector` is defined fixes
the problem.

Ref: #1540
Fixes: #1541
Signed-off-by: Ruy Adorno <ruyadorno@google.com>
  • Loading branch information
ruyadorno committed Jun 5, 2023
1 parent e4eadf8 commit 3221920
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 12 deletions.
45 changes: 35 additions & 10 deletions src/connection.ts
Expand Up @@ -1052,7 +1052,7 @@ class Connection extends EventEmitter {
throw new TypeError('The "config" argument is required and must be of type Object.');
}

if (typeof config.server !== 'string') {
if (typeof config.server !== 'string' && !config.options!.connector) {
throw new TypeError('The "config.server" property is required and must be of type string.');
}

Expand Down Expand Up @@ -1343,8 +1343,15 @@ class Connection extends EventEmitter {
if (typeof config.options.connector !== 'function') {
throw new TypeError('The "config.options.connector" property must be a function.');
}
if (config.server) {
throw new Error('Server and connector are mutually exclusive, but ' + config.server + ' and a connector function were provided');
}
if (config.options.port) {
throw new Error('Port and connector are mutually exclusive, but ' + config.options.port + ' and a connector function were provided');
}

this.config.options.connector = config.options.connector;
this.config.options.port = undefined;
}

if (config.options.cryptoCredentialsDetails !== undefined) {
Expand Down Expand Up @@ -1900,7 +1907,10 @@ class Connection extends EventEmitter {
initialiseConnection() {
const signal = this.createConnectTimer();

if (this.config.options.port) {
if (this.config.options.connector) {
// port and multiSubnetFailover are not used when using a custom connector
return this.connectOnPort(0, false, signal, this.config.options.connector);
} else if (this.config.options.port) {
return this.connectOnPort(this.config.options.port, this.config.options.multiSubnetFailover, signal, this.config.options.connector);
} else {
return instanceLookup({
Expand Down Expand Up @@ -1995,7 +2005,12 @@ class Connection extends EventEmitter {
this.socket = socket;

this.closed = false;
this.debug.log('connected to ' + this.config.server + ':' + this.config.options.port);

const message =
'connected to ' + this.config.server + ':' + this.config.options.port;
const customConnectorMessage =
'connected via custom connector';
this.debug.log(customConnector ? customConnectorMessage : message);

this.sendPreLogin();
this.transitionTo(this.STATE.SENT_PRELOGIN);
Expand Down Expand Up @@ -2073,8 +2088,10 @@ class Connection extends EventEmitter {
*/
connectTimeout() {
const message = `Failed to connect to ${this.config.server}${this.config.options.port ? `:${this.config.options.port}` : `\\${this.config.options.instanceName}`} in ${this.config.options.connectTimeout}ms`;
this.debug.log(message);
this.emit('connect', new ConnectionError(message, 'ETIMEOUT'));
const customConnectorMessage = `Failed to connect using custom connector in ${this.config.options.connectTimeout}ms`;
const errMessage = this.config.options.connector ? customConnectorMessage : message;
this.debug.log(errMessage);
this.emit('connect', new ConnectionError(errMessage, 'ETIMEOUT'));
this.connectTimer = undefined;
this.dispatchEvent('connectTimeout');
}
Expand Down Expand Up @@ -2202,8 +2219,10 @@ class Connection extends EventEmitter {
socketError(error: Error) {
if (this.state === this.STATE.CONNECTING || this.state === this.STATE.SENT_TLSSSLNEGOTIATION) {
const message = `Failed to connect to ${this.config.server}:${this.config.options.port} - ${error.message}`;
this.debug.log(message);
this.emit('connect', new ConnectionError(message, 'ESOCKET'));
const customConnectorMessage = `Failed to connect using custom connector - ${error.message}`;
const errMessage = this.config.options.connector ? customConnectorMessage : message;
this.debug.log(errMessage);
this.emit('connect', new ConnectionError(errMessage, 'ESOCKET'));
} else {
const message = `Connection lost - ${error.message}`;
this.debug.log(message);
Expand All @@ -2228,15 +2247,21 @@ class Connection extends EventEmitter {
* @private
*/
socketClose() {
this.debug.log('connection to ' + this.config.server + ':' + this.config.options.port + ' closed');
const message = 'connection to ' + this.config.server + ':' + this.config.options.port + ' closed';
const customConnectorMessage = 'connection closed';
this.debug.log(this.config.options.connector ? customConnectorMessage : message);
if (this.state === this.STATE.REROUTING) {
this.debug.log('Rerouting to ' + this.routingData!.server + ':' + this.routingData!.port);
const message = 'Rerouting to ' + this.routingData!.server + ':' + this.routingData!.port;
const customConnectorMessage = 'Rerouting';
this.debug.log(this.config.options.connector ? customConnectorMessage : message);

this.dispatchEvent('reconnect');
} else if (this.state === this.STATE.TRANSIENT_FAILURE_RETRY) {
const server = this.routingData ? this.routingData.server : this.config.server;
const port = this.routingData ? this.routingData.port : this.config.options.port;
this.debug.log('Retry after transient failure connecting to ' + server + ':' + port);
const message = 'Retry after transient failure connecting to ' + server + ':' + port;
const customConnectorMessage = 'Retry after transient failure connecting';
this.debug.log(this.config.options.connector ? customConnectorMessage : message);

this.dispatchEvent('retry');
} else {
Expand Down
61 changes: 59 additions & 2 deletions test/unit/custom-connector.js
Expand Up @@ -28,7 +28,6 @@ describe('custom connector', function() {
const host = server.address().address;
const port = server.address().port;
const connection = new Connection({
server: host,
options: {
connector: async () => {
customConnectorCalled = true;
Expand All @@ -37,7 +36,6 @@ describe('custom connector', function() {
port,
});
},
port
},
});

Expand All @@ -59,4 +57,63 @@ describe('custom connector', function() {

connection.connect();
});

it('should emit socket error custom connector msg', function(done) {
const connection = new Connection({
options: {
connector: async () => {
throw new Error('ERR');
},
},
});

connection.connect((err) => {
assert.strictEqual(
err.code,
'ESOCKET',
'should emit expected error code'
);
assert.strictEqual(
err.message,
'Failed to connect using custom connector - ERR',
'should emit expected custom connector error msg'
);
done();
});
});

it('should only accept functions', function(done) {
assert.throws(() => {
new Connection({
options: {
connector: 'foo',
},
});
}, Error, 'The "config.options.connector" property must be a function.');
done();
});

it('should not allow setting both server and connector options', function(done) {
assert.throws(() => {
new Connection({
server: '0.0.0.0',
options: {
connector: async () => {},
},
});
}, Error, 'Server and connector are mutually exclusive, but 0.0.0.0 and a connector function were provided');
done();
});

it('should not allow setting both port and connector options', function(done) {
assert.throws(() => {
new Connection({
options: {
connector: async () => {},
port: 8080,
},
});
}, Error, 'Port and connector are mutually exclusive, but 8080 and a connector function were provided');
done();
});
});

0 comments on commit 3221920

Please sign in to comment.