Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/repl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async function initClient({ host, endpointId, token }) {
host,
path: `/sql/2.0/warehouses/${endpointId}`,
token,
clientId: 'REPL',
userAgentHeader: 'REPL',
});
}

Expand Down
2 changes: 1 addition & 1 deletion lib/DBSQLClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class DBSQLClient extends EventEmitter implements IDBSQLClient, I
socketTimeout: options.socketTimeout,
proxy: options.proxy,
headers: {
'User-Agent': buildUserAgentString(),
'User-Agent': buildUserAgentString(options.userAgentHeader),
},
};
}
Expand Down
2 changes: 1 addition & 1 deletion lib/contracts/IDBSQLClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type ConnectionOptions = {
host: string;
port?: number;
path: string;
clientId?: string;
userAgentHeader?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The only thing I'd change - maybe use userAgentEntry, like in Python connector

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

socketTimeout?: number;
proxy?: ProxyOptions;
} & AuthOptions;
Expand Down
4 changes: 2 additions & 2 deletions lib/utils/buildUserAgentString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function getOperatingSystemVersion(): string {
return `${os.type()} ${os.release()}`;
}

export default function buildUserAgentString(): string {
const extra = [getNodeVersion(), getOperatingSystemVersion()].filter(Boolean);
export default function buildUserAgentString(userAgentHeader?: string): string {
const extra = [userAgentHeader, getNodeVersion(), getOperatingSystemVersion()].filter(Boolean);
return `${productName}/${packageVersion} (${extra.join('; ')})`;
}
31 changes: 18 additions & 13 deletions tests/unit/utils/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ const progressUpdateResponseStub: TProgressUpdateResp = {
describe('buildUserAgentString', () => {
// It should follow https://www.rfc-editor.org/rfc/rfc7231#section-5.5.3 and
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
// UserAgent ::= <ProductName> '/' <ProductVersion> '(' <Comment> ')'
// where:
// <ProductName> is "NodejsDatabricksSqlConnector"
// <ProductVersion> is three period-separated digits (optionally with a suffix)
// <Comment> is "Node.js <NodeJsVersion>; <OSPlatform> <OSVersion>"
//
// Example:
// - NodejsDatabricksSqlConnector/0.1.8-beta.1 (Node.js 16.13.1; Darwin 21.5.0)
// UserAgent ::= <ProductName> '/' <ProductVersion> '(' <Comment> ')'
// ProductName ::= 'NodejsDatabricksSqlConnector'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit : include the where in comment

// <Comment> ::= [ <userAgentHeader> ';' ] 'Node.js' <NodeJsVersion> ';' <OSPlatform> <OSVersion>
//
// Examples:
// - with <userAgentHeader> provided: NodejsDatabricksSqlConnector/0.1.8-beta.1 (Client ID; Node.js 16.13.1; Darwin 21.5.0)
// - without <userAgentHeader> provided: NodejsDatabricksSqlConnector/0.1.8-beta.1 (Node.js 16.13.1; Darwin 21.5.0)

function checkUserAgentString(ua: string) {
function checkUserAgentString(ua: string, userAgentHeader?: string) {
// Prefix: 'NodejsDatabricksSqlConnector/'
// Version: three period-separated digits and optional suffix
const re =
Expand All @@ -39,13 +39,18 @@ describe('buildUserAgentString', () => {
const parts = comment.split(';').map((s) => s.trim());
expect(parts.length).to.be.gte(2); // at least Node and OS version should be there

// First part should start with "Node.js" followed by a version number.
expect(parts[0]).to.match(/^Node\.js\s+\d+\.\d+\.\d+/);
// Second part should represent the OS platform (a word) and OS version.
expect(parts[1]).to.match(/^\w+/);
if (userAgentHeader) {
expect(comment.trim()).to.satisfy((s: string) => s.startsWith(`${userAgentHeader};`));
}
}

it('matches pattern', () => {
it('matches pattern with userAgentHeader', () => {
const userAgentHeader = 'Some Client ID';
const ua = buildUserAgentString(userAgentHeader);
checkUserAgentString(ua, userAgentHeader);
});

it('matches pattern without userAgentHeader', () => {
const ua = buildUserAgentString();
checkUserAgentString(ua);
});
Expand Down
Loading