From 6cc6c5ad903dcd226d34d69b706a7b4b9de38f46 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Fri, 26 Jul 2024 13:43:51 +0200 Subject: [PATCH 1/2] feat(telemetry): report host_id for atlas COMPASS-8092 --- src/telemetry/connectionTelemetry.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/telemetry/connectionTelemetry.ts b/src/telemetry/connectionTelemetry.ts index bbfd3bfb2..282473aaa 100644 --- a/src/telemetry/connectionTelemetry.ts +++ b/src/telemetry/connectionTelemetry.ts @@ -14,6 +14,7 @@ const { version } = require('../../package.json'); export type NewConnectionTelemetryEventProperties = { auth_strategy?: string; is_atlas?: boolean; + host_id?: string | null; is_localhost?: boolean; is_data_lake?: boolean; is_enterprise?: boolean; @@ -56,11 +57,8 @@ async function getHostnameForConnection( } async function getCloudInfoFromDataService( - dataService: DataService + hostname?: string ): Promise { - const hostname = await getHostnameForConnection( - dataService.getConnectionString() - ); const cloudInfo: { isAws?: boolean; isAzure?: boolean; @@ -110,15 +108,22 @@ export async function getConnectionTelemetryProperties( const username = connectionString.username ? 'DEFAULT' : 'NONE'; const authStrategy = authMechanism ?? username; + const hostname = await getHostnameForConnection( + dataService.getConnectionString() + ); + const [instance, cloudInfo] = await Promise.all([ dataService.instance(), - getCloudInfoFromDataService(dataService), + getCloudInfoFromDataService(hostname), ]); + const isAtlas = mongoDBBuildInfo.isAtlas(connectionString.toString()); + const atlasHostId = isAtlas ? hostname : null; preparedProperties = { ...preparedProperties, auth_strategy: authStrategy, - is_atlas: mongoDBBuildInfo.isAtlas(connectionString.toString()), + is_atlas: isAtlas, + host_id: atlasHostId, is_localhost: mongoDBBuildInfo.isLocalhost(connectionString.toString()), is_data_lake: instance.dataLake.isDataLake, is_enterprise: instance.build.isEnterprise, From 90c853e2805d8ca81733a6c55ddb16b89dd297eb Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Fri, 26 Jul 2024 15:28:45 +0200 Subject: [PATCH 2/2] test: add atlas host test and clean up --- src/telemetry/connectionTelemetry.ts | 15 +-- .../telemetry/connectionTelemetry.test.ts | 113 +++++++++++++++--- 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/src/telemetry/connectionTelemetry.ts b/src/telemetry/connectionTelemetry.ts index 282473aaa..68f09794e 100644 --- a/src/telemetry/connectionTelemetry.ts +++ b/src/telemetry/connectionTelemetry.ts @@ -14,7 +14,7 @@ const { version } = require('../../package.json'); export type NewConnectionTelemetryEventProperties = { auth_strategy?: string; is_atlas?: boolean; - host_id?: string | null; + atlas_host_id?: string | null; is_localhost?: boolean; is_data_lake?: boolean; is_enterprise?: boolean; @@ -56,9 +56,7 @@ async function getHostnameForConnection( return hostname; } -async function getCloudInfoFromDataService( - hostname?: string -): Promise { +async function getCloudInfoFromHostname(hostname?: string): Promise { const cloudInfo: { isAws?: boolean; isAzure?: boolean; @@ -107,14 +105,11 @@ export async function getConnectionTelemetryProperties( const authMechanism = connectionString.searchParams.get('authMechanism'); const username = connectionString.username ? 'DEFAULT' : 'NONE'; const authStrategy = authMechanism ?? username; - - const hostname = await getHostnameForConnection( - dataService.getConnectionString() - ); + const hostname = await getHostnameForConnection(connectionString); const [instance, cloudInfo] = await Promise.all([ dataService.instance(), - getCloudInfoFromDataService(hostname), + getCloudInfoFromHostname(hostname), ]); const isAtlas = mongoDBBuildInfo.isAtlas(connectionString.toString()); const atlasHostId = isAtlas ? hostname : null; @@ -123,7 +118,7 @@ export async function getConnectionTelemetryProperties( ...preparedProperties, auth_strategy: authStrategy, is_atlas: isAtlas, - host_id: atlasHostId, + atlas_host_id: atlasHostId, is_localhost: mongoDBBuildInfo.isLocalhost(connectionString.toString()), is_data_lake: instance.dataLake.isDataLake, is_enterprise: instance.build.isEnterprise, diff --git a/src/test/suite/telemetry/connectionTelemetry.test.ts b/src/test/suite/telemetry/connectionTelemetry.test.ts index d393cf597..6c598364b 100644 --- a/src/test/suite/telemetry/connectionTelemetry.test.ts +++ b/src/test/suite/telemetry/connectionTelemetry.test.ts @@ -1,8 +1,9 @@ -import { before, after, beforeEach, afterEach } from 'mocha'; +import { before, beforeEach, afterEach } from 'mocha'; import { connect } from 'mongodb-data-service'; import { expect } from 'chai'; import sinon from 'sinon'; import type { DataService } from 'mongodb-data-service'; +import mongoDBBuildInfo from 'mongodb-build-info'; import * as getCloudInfoModule from 'mongodb-cloud-info'; @@ -13,16 +14,14 @@ import { TEST_DATABASE_URI } from '../dbTestHelper'; suite('ConnectionTelemetry Controller Test Suite', function () { suite('with mock data service', function () { this.timeout(8000); - let dataServiceStub: DataService; const sandbox = sinon.createSandbox(); + let dataServiceStub; + let getConnectionStringStub; + let isAtlasStub; before(() => { - const getConnectionStringStub = sandbox.stub(); - getConnectionStringStub.returns({ - hosts: ['localhost:27088'], - searchParams: { get: () => null }, - username: 'authMechanism', - } as unknown as ReturnType); + getConnectionStringStub = sandbox.stub(); + isAtlasStub = sinon.stub(mongoDBBuildInfo, 'isAtlas'); const instanceStub = sandbox.stub(); instanceStub.resolves({ @@ -46,11 +45,51 @@ suite('ConnectionTelemetry Controller Test Suite', function () { ); }); - after(() => { + afterEach(() => { sandbox.restore(); }); + test('it returns atlas_host_id hostname for atlas clusters', async () => { + isAtlasStub.returns(true); + getConnectionStringStub.returns({ + hosts: ['test-data-sets-a011bb.test.net'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + + const instanceTelemetry = await getConnectionTelemetryProperties( + dataServiceStub, + ConnectionTypes.CONNECTION_FORM + ); + + expect(instanceTelemetry.is_atlas).to.equal(true); + expect(instanceTelemetry.atlas_host_id).to.equal( + 'test-data-sets-a011bb.test.net' + ); + }); + + test('it returns atlas_host_id null for non atlas clusters', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + + const instanceTelemetry = await getConnectionTelemetryProperties( + dataServiceStub, + ConnectionTypes.CONNECTION_FORM + ); + + expect(instanceTelemetry.is_atlas).to.equal(false); + expect(instanceTelemetry.atlas_host_id).to.equal(null); + }); + test('it returns is_used_connect_screen true when the connection type is form', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + const instanceTelemetry = await getConnectionTelemetryProperties( dataServiceStub, ConnectionTypes.CONNECTION_FORM @@ -62,6 +101,12 @@ suite('ConnectionTelemetry Controller Test Suite', function () { }); test('it returns is_used_command_palette true when the connection type is string', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + const instanceTelemetry = await getConnectionTelemetryProperties( dataServiceStub, ConnectionTypes.CONNECTION_STRING @@ -73,6 +118,12 @@ suite('ConnectionTelemetry Controller Test Suite', function () { }); test('it returns is_used_saved_connection true when the connection type is id', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + const instanceTelemetry = await getConnectionTelemetryProperties( dataServiceStub, ConnectionTypes.CONNECTION_ID @@ -83,7 +134,13 @@ suite('ConnectionTelemetry Controller Test Suite', function () { expect(instanceTelemetry.is_used_saved_connection).to.equal(true); }); - test('it has is_localhost false for a remote connection', async () => { + test('it returns is_localhost false for a remote connection', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + const instanceTelemetry = await getConnectionTelemetryProperties( dataServiceStub, ConnectionTypes.CONNECTION_STRING @@ -92,22 +149,50 @@ suite('ConnectionTelemetry Controller Test Suite', function () { expect(instanceTelemetry.is_localhost).to.equal(false); }); - test('it has a default is atlas false', async () => { + test('it returns DEFAULT when auth mechanism undefined and username is specified', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + username: 'Artishok', + } as unknown as ReturnType); + const instanceTelemetry = await getConnectionTelemetryProperties( dataServiceStub, ConnectionTypes.CONNECTION_STRING ); - expect(instanceTelemetry.is_atlas).to.equal(false); + expect(instanceTelemetry.auth_strategy).to.equal('DEFAULT'); }); - test('it has a default driver auth mechanism undefined', async () => { + test('it returns NONE when auth mechanism undefined and username undefined', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => null }, + } as unknown as ReturnType); + const instanceTelemetry = await getConnectionTelemetryProperties( dataServiceStub, ConnectionTypes.CONNECTION_STRING ); - expect(instanceTelemetry.auth_strategy).to.equal('DEFAULT'); + expect(instanceTelemetry.auth_strategy).to.equal('NONE'); + }); + + test('it returns authMechanism when specified', async () => { + isAtlasStub.returns(false); + getConnectionStringStub.returns({ + hosts: ['localhost:27088'], + searchParams: { get: () => 'SCRAM-SHA-1' }, + } as unknown as ReturnType); + + const instanceTelemetry = await getConnectionTelemetryProperties( + dataServiceStub, + ConnectionTypes.CONNECTION_STRING + ); + + expect(instanceTelemetry.auth_strategy).to.equal('SCRAM-SHA-1'); }); });