From 5f10d3df706a72406cca1b134e8093db4730621e Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Apr 2023 15:40:47 -0400 Subject: [PATCH 1/7] feat(NODE-5188): add alternative runtime detection to client metadata --- src/cmap/handshake/client_metadata.ts | 62 ++++++++++++-- .../cmap/handshake/client_metadata.test.ts | 80 +++++++++++++++++++ 2 files changed, 137 insertions(+), 5 deletions(-) diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts index 0c00af9a8e..3aab82c3d6 100644 --- a/src/cmap/handshake/client_metadata.ts +++ b/src/cmap/handshake/client_metadata.ts @@ -116,12 +116,12 @@ export function makeClientMetadata(options: MakeClientMetadataOptions): ClientMe ); } - const platformInfo = - platform.length > 0 - ? `Node.js ${process.version}, ${os.endianness()}|${platform}` - : `Node.js ${process.version}, ${os.endianness()}`; + let runtimeInfo = getRuntimeInfo(); + if (platform.length > 0) { + runtimeInfo = `${runtimeInfo}|${platform}`; + } - if (!metadataDocument.ifItFitsItSits('platform', platformInfo)) { + if (!metadataDocument.ifItFitsItSits('platform', runtimeInfo)) { throw new MongoInvalidArgumentError( 'Unable to include driverInfo platform, metadata cannot exceed 512 bytes' ); @@ -234,3 +234,55 @@ export function getFAASEnv(): Map | null { return null; } + +/** + * @internal + * This type represents the global Deno object and the minimal type contract we + * expect it to satisfy. In order to not ship code in the driver that would break + * future versions of this runtime assume all properties are nullish. + */ +declare const Deno: { version?: { deno?: string } } | undefined; + +/** + * @internal + * This type represents the global Bun object and the minimal type contract we + * expect it to satisfy. In order to not ship code in the driver that would break + * future versions of this runtime assume all properties are nullish. + */ +declare const Bun: { version?: string } | undefined; + +/** + * @internal + * Get current JavaScript runtime platform + * + * NOTE: The version information fetching is intentionally written aggressively defensive + * to avoid having a released driver version that becomes incompatible + * with a future change to these global objects + */ +function getRuntimeInfo(): string { + if ('Deno' in globalThis) { + const version = + Deno != null && + typeof Deno === 'object' && + 'version' in Deno && + Deno.version != null && + typeof Deno.version === 'object' && + 'deno' in Deno.version && + typeof Deno.version.deno === 'string' + ? Deno.version.deno + : '0.0.0'; + + return `Deno v${version}, ${os.endianness()}`; + } + + if ('Bun' in globalThis) { + const version = + Bun != null && typeof Bun === 'object' && 'version' in Bun && typeof Bun.version === 'string' + ? Bun.version + : '0.0.0'; + + return `Bun v${version}, ${os.endianness()}`; + } + + return `Node.js ${process.version}, ${os.endianness()}`; +} diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index 83f51e89b1..31694a7adc 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -289,6 +289,86 @@ describe('client metadata module', () => { }); }); }); + + context('when globalThis indicates alternative runtime', () => { + context('deno', () => { + afterEach(() => { + expect(delete globalThis.Deno, 'failed to delete Deno global').to.be.true; + }); + + it('sets platform to Deno', () => { + globalThis.Deno = { version: { deno: '1.2.3' } }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Deno v1.2.3, LE'); + }); + + it('sets platform to Deno with driverInfo.platform', () => { + globalThis.Deno = { version: { deno: '1.2.3' } }; + const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); + expect(metadata.platform).to.equal('Deno v1.2.3, LE|myPlatform'); + }); + + it('ignores version if Deno.version.deno is not a string', () => { + globalThis.Deno = { version: { deno: 1 } }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + }); + + it('ignores version if Deno.version.deno is not a string and sets driverInfo.platform', () => { + globalThis.Deno = { version: { deno: 1 } }; + const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); + expect(metadata.platform).to.equal('Deno v0.0.0, LE|myPlatform'); + }); + + it('ignores version if Deno.version does not have a deno property', () => { + globalThis.Deno = { version: { somethingElse: '1.2.3' } }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + }); + + it('ignores version if Deno.version is null', () => { + globalThis.Deno = { version: null }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + }); + + it('ignores version if Deno does not have a version property', () => { + globalThis.Deno = { version: null }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + }); + }); + + context('bun', () => { + afterEach(() => { + expect(delete globalThis.Bun, 'failed to delete Bun global').to.be.true; + }); + + it('sets platform to Bun', () => { + globalThis.Bun = { version: '1.2.3' }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Bun v1.2.3, LE'); + }); + + it('sets platform to Bun with driverInfo.platform', () => { + globalThis.Bun = { version: '1.2.3' }; + const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); + expect(metadata.platform).to.equal('Bun v1.2.3, LE|myPlatform'); + }); + + it('ignores version if Bun.version is not a string', () => { + globalThis.Bun = { version: 1 }; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Bun v0.0.0, LE'); + }); + + it('ignores version if Bun.version is not a string and sets driverInfo.platform', () => { + globalThis.Bun = { version: 1 }; + const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); + expect(metadata.platform).to.equal('Bun v0.0.0, LE|myPlatform'); + }); + }); + }); }); describe('FAAS metadata application to handshake', () => { From 8dae68df8feb7f649799a4e1d87029211567bbeb Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Apr 2023 16:02:32 -0400 Subject: [PATCH 2/7] fix: assumption about Bun typeof --- src/cmap/handshake/client_metadata.ts | 5 ++++- test/unit/cmap/handshake/client_metadata.test.ts | 12 +++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts index 3aab82c3d6..6a07e73a3f 100644 --- a/src/cmap/handshake/client_metadata.ts +++ b/src/cmap/handshake/client_metadata.ts @@ -277,7 +277,10 @@ function getRuntimeInfo(): string { if ('Bun' in globalThis) { const version = - Bun != null && typeof Bun === 'object' && 'version' in Bun && typeof Bun.version === 'string' + Bun != null && + (typeof Bun === 'function' || typeof Bun === 'object') && + 'version' in Bun && + typeof Bun.version === 'string' ? Bun.version : '0.0.0'; diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index 31694a7adc..d94700af1c 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -344,12 +344,22 @@ describe('client metadata module', () => { expect(delete globalThis.Bun, 'failed to delete Bun global').to.be.true; }); - it('sets platform to Bun', () => { + it('sets platform to Bun if typeof is object', () => { globalThis.Bun = { version: '1.2.3' }; const metadata = makeClientMetadata({ driverInfo: {} }); expect(metadata.platform).to.equal('Bun v1.2.3, LE'); }); + it('sets platform to Bun if typeof is function', () => { + function Bun() { + return null; + } + Bun.version = '1.2.3'; + globalThis.Bun = Bun; + const metadata = makeClientMetadata({ driverInfo: {} }); + expect(metadata.platform).to.equal('Bun v1.2.3, LE'); + }); + it('sets platform to Bun with driverInfo.platform', () => { globalThis.Bun = { version: '1.2.3' }; const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); From 0d26183df376b00ebf572555578fc80e2068eddf Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Apr 2023 16:20:14 -0400 Subject: [PATCH 3/7] fix: remove object case --- src/cmap/handshake/client_metadata.ts | 4 ++-- test/unit/cmap/handshake/client_metadata.test.ts | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts index 6a07e73a3f..5bdcc892ac 100644 --- a/src/cmap/handshake/client_metadata.ts +++ b/src/cmap/handshake/client_metadata.ts @@ -249,7 +249,7 @@ declare const Deno: { version?: { deno?: string } } | undefined; * expect it to satisfy. In order to not ship code in the driver that would break * future versions of this runtime assume all properties are nullish. */ -declare const Bun: { version?: string } | undefined; +declare const Bun: { (): void; version?: string } | undefined; /** * @internal @@ -278,7 +278,7 @@ function getRuntimeInfo(): string { if ('Bun' in globalThis) { const version = Bun != null && - (typeof Bun === 'function' || typeof Bun === 'object') && + typeof Bun === 'function' && 'version' in Bun && typeof Bun.version === 'string' ? Bun.version diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index d94700af1c..339089309a 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -344,18 +344,10 @@ describe('client metadata module', () => { expect(delete globalThis.Bun, 'failed to delete Bun global').to.be.true; }); - it('sets platform to Bun if typeof is object', () => { - globalThis.Bun = { version: '1.2.3' }; - const metadata = makeClientMetadata({ driverInfo: {} }); - expect(metadata.platform).to.equal('Bun v1.2.3, LE'); - }); - - it('sets platform to Bun if typeof is function', () => { - function Bun() { - return null; - } - Bun.version = '1.2.3'; - globalThis.Bun = Bun; + it('sets platform to Bun', () => { + globalThis.Bun = class { + static version = '1.2.3'; + }; const metadata = makeClientMetadata({ driverInfo: {} }); expect(metadata.platform).to.equal('Bun v1.2.3, LE'); }); From 5901ba8246d8d3228ad052277d552dc7bfd718f2 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Apr 2023 16:23:10 -0400 Subject: [PATCH 4/7] fix: unit test --- .../cmap/handshake/client_metadata.test.ts | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index 339089309a..befd99f68b 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -290,7 +290,7 @@ describe('client metadata module', () => { }); }); - context('when globalThis indicates alternative runtime', () => { + context.only('when globalThis indicates alternative runtime', () => { context('deno', () => { afterEach(() => { expect(delete globalThis.Deno, 'failed to delete Deno global').to.be.true; @@ -353,19 +353,31 @@ describe('client metadata module', () => { }); it('sets platform to Bun with driverInfo.platform', () => { - globalThis.Bun = { version: '1.2.3' }; + globalThis.Bun = class { + static version = '1.2.3'; + }; const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); expect(metadata.platform).to.equal('Bun v1.2.3, LE|myPlatform'); }); it('ignores version if Bun.version is not a string', () => { - globalThis.Bun = { version: 1 }; + globalThis.Bun = class { + static version = 1; + }; const metadata = makeClientMetadata({ driverInfo: {} }); expect(metadata.platform).to.equal('Bun v0.0.0, LE'); }); it('ignores version if Bun.version is not a string and sets driverInfo.platform', () => { - globalThis.Bun = { version: 1 }; + globalThis.Bun = class { + static version = 1; + }; + const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); + expect(metadata.platform).to.equal('Bun v0.0.0, LE|myPlatform'); + }); + + it('ignores version if Bun is not a function', () => { + globalThis.Bun = { version: '1.2.3' }; const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); expect(metadata.platform).to.equal('Bun v0.0.0, LE|myPlatform'); }); From 5fc39a1155c6886a96e5f0019d102dd0c069f594 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Apr 2023 17:03:20 -0400 Subject: [PATCH 5/7] rm .only --- test/unit/cmap/handshake/client_metadata.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index befd99f68b..6cb29f8826 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -290,7 +290,7 @@ describe('client metadata module', () => { }); }); - context.only('when globalThis indicates alternative runtime', () => { + context('when globalThis indicates alternative runtime', () => { context('deno', () => { afterEach(() => { expect(delete globalThis.Deno, 'failed to delete Deno global').to.be.true; From be8900787cbcc0ccafe32fdf0268f3c8c5266e32 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 13 Apr 2023 11:32:58 -0400 Subject: [PATCH 6/7] fix: simplify version checking --- src/cmap/handshake/client_metadata.ts | 19 ++----------- .../cmap/handshake/client_metadata.test.ts | 28 ++++++++----------- 2 files changed, 13 insertions(+), 34 deletions(-) diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts index 5bdcc892ac..9e790303ff 100644 --- a/src/cmap/handshake/client_metadata.ts +++ b/src/cmap/handshake/client_metadata.ts @@ -261,28 +261,13 @@ declare const Bun: { (): void; version?: string } | undefined; */ function getRuntimeInfo(): string { if ('Deno' in globalThis) { - const version = - Deno != null && - typeof Deno === 'object' && - 'version' in Deno && - Deno.version != null && - typeof Deno.version === 'object' && - 'deno' in Deno.version && - typeof Deno.version.deno === 'string' - ? Deno.version.deno - : '0.0.0'; + const version = typeof Deno?.version?.deno === 'string' ? Deno?.version?.deno : '0.0.0-unknown'; return `Deno v${version}, ${os.endianness()}`; } if ('Bun' in globalThis) { - const version = - Bun != null && - typeof Bun === 'function' && - 'version' in Bun && - typeof Bun.version === 'string' - ? Bun.version - : '0.0.0'; + const version = typeof Bun?.version === 'string' ? Bun?.version : '0.0.0-unknown'; return `Bun v${version}, ${os.endianness()}`; } diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index 6cb29f8826..3e96df7c6f 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -311,31 +311,25 @@ describe('client metadata module', () => { it('ignores version if Deno.version.deno is not a string', () => { globalThis.Deno = { version: { deno: 1 } }; const metadata = makeClientMetadata({ driverInfo: {} }); - expect(metadata.platform).to.equal('Deno v0.0.0, LE'); - }); - - it('ignores version if Deno.version.deno is not a string and sets driverInfo.platform', () => { - globalThis.Deno = { version: { deno: 1 } }; - const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); - expect(metadata.platform).to.equal('Deno v0.0.0, LE|myPlatform'); + expect(metadata.platform).to.equal('Deno v0.0.0-unknown, LE'); }); it('ignores version if Deno.version does not have a deno property', () => { globalThis.Deno = { version: { somethingElse: '1.2.3' } }; const metadata = makeClientMetadata({ driverInfo: {} }); - expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + expect(metadata.platform).to.equal('Deno v0.0.0-unknown, LE'); }); it('ignores version if Deno.version is null', () => { globalThis.Deno = { version: null }; const metadata = makeClientMetadata({ driverInfo: {} }); - expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + expect(metadata.platform).to.equal('Deno v0.0.0-unknown, LE'); }); - it('ignores version if Deno does not have a version property', () => { - globalThis.Deno = { version: null }; + it('ignores version if Deno is nullish', () => { + globalThis.Deno = null; const metadata = makeClientMetadata({ driverInfo: {} }); - expect(metadata.platform).to.equal('Deno v0.0.0, LE'); + expect(metadata.platform).to.equal('Deno v0.0.0-unknown, LE'); }); }); @@ -365,7 +359,7 @@ describe('client metadata module', () => { static version = 1; }; const metadata = makeClientMetadata({ driverInfo: {} }); - expect(metadata.platform).to.equal('Bun v0.0.0, LE'); + expect(metadata.platform).to.equal('Bun v0.0.0-unknown, LE'); }); it('ignores version if Bun.version is not a string and sets driverInfo.platform', () => { @@ -373,13 +367,13 @@ describe('client metadata module', () => { static version = 1; }; const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); - expect(metadata.platform).to.equal('Bun v0.0.0, LE|myPlatform'); + expect(metadata.platform).to.equal('Bun v0.0.0-unknown, LE|myPlatform'); }); - it('ignores version if Bun is not a function', () => { - globalThis.Bun = { version: '1.2.3' }; + it('ignores version if Bun is nullish', () => { + globalThis.Bun = null; const metadata = makeClientMetadata({ driverInfo: { platform: 'myPlatform' } }); - expect(metadata.platform).to.equal('Bun v0.0.0, LE|myPlatform'); + expect(metadata.platform).to.equal('Bun v0.0.0-unknown, LE|myPlatform'); }); }); }); From f46fb1f57872c15d2b04dfa5020f2810f150b563 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 13 Apr 2023 11:47:15 -0400 Subject: [PATCH 7/7] docs: cleanup --- src/cmap/handshake/client_metadata.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts index 9e790303ff..ab66328ca5 100644 --- a/src/cmap/handshake/client_metadata.ts +++ b/src/cmap/handshake/client_metadata.ts @@ -237,17 +237,13 @@ export function getFAASEnv(): Map | null { /** * @internal - * This type represents the global Deno object and the minimal type contract we - * expect it to satisfy. In order to not ship code in the driver that would break - * future versions of this runtime assume all properties are nullish. + * This type represents the global Deno object and the minimal type contract we expect it to satisfy. */ declare const Deno: { version?: { deno?: string } } | undefined; /** * @internal - * This type represents the global Bun object and the minimal type contract we - * expect it to satisfy. In order to not ship code in the driver that would break - * future versions of this runtime assume all properties are nullish. + * This type represents the global Bun object and the minimal type contract we expect it to satisfy. */ declare const Bun: { (): void; version?: string } | undefined; @@ -255,9 +251,9 @@ declare const Bun: { (): void; version?: string } | undefined; * @internal * Get current JavaScript runtime platform * - * NOTE: The version information fetching is intentionally written aggressively defensive + * NOTE: The version information fetching is intentionally written defensively * to avoid having a released driver version that becomes incompatible - * with a future change to these global objects + * with a future change to these global objects. */ function getRuntimeInfo(): string { if ('Deno' in globalThis) {