Skip to content

Commit

Permalink
feat: new telemetry events for connections (#6018)
Browse files Browse the repository at this point in the history
  • Loading branch information
paula-stacho authored Jul 31, 2024
1 parent 9a3a002 commit ada8b30
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Passphrase } from './passphrase';
import { SelectTable } from './select-table';
import type { ImportExportResult } from '../hooks/common';
import { useOpenModalThroughIpc } from '../hooks/common';
import { useExportConnections } from '../hooks/use-export';
import { useExportConnections } from '../hooks/use-export-connections';
import { usePreference } from 'compass-preferences-model/provider';

const TOAST_TIMEOUT_MS = 5000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Passphrase } from './passphrase';
import { SelectTable } from './select-table';
import type { ImportExportResult } from '../hooks/common';
import { useOpenModalThroughIpc } from '../hooks/common';
import { useImportConnections } from '../hooks/use-import';
import { useImportConnections } from '../hooks/use-import-connections';
import { usePreference } from 'compass-preferences-model/provider';

const TOAST_TIMEOUT_MS = 5000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
RenderHookResult,
} from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react-hooks';
import { useExportConnections } from './use-export';
import { useExportConnections } from './use-export-connections';
import type { ImportExportResult } from './common';
import os from 'os';
import path from 'path';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
RenderHookResult,
} from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react-hooks';
import { useImportConnections } from './use-import';
import { useImportConnections } from './use-import-connections';
import type { ImportExportResult } from './common';
import os from 'os';
import path from 'path';
Expand Down Expand Up @@ -334,7 +334,10 @@ describe('useImportConnections', function () {
expect(await finishedPromise).to.equal('succeeded');
expect(importConnectionsStub).to.have.been.calledOnce;
const arg = importConnectionsStub.firstCall.args[0];
expect(arg?.options?.trackingProps).to.deep.equal({ context: 'Tests' });
expect(arg?.options?.trackingProps).to.deep.equal({
context: 'Tests',
connection_ids: ['id2'],
});
expect(arg?.options?.filterConnectionIds).to.deep.equal(['id2']);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ export function useImportConnections({
options: {
passphrase,
filterConnectionIds,
trackingProps,
trackingProps: {
...trackingProps,
connection_ids: filterConnectionIds,
},
},
});
} catch (err: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,12 @@ export function useConnectionRepository(): ConnectionRepository {
useEffect(() => {
async function updateListsOfConnections() {
const allConnections = (await storage.loadAll()) || [];
const favoriteConnections = allConnections

const newFavoriteConnections = allConnections
.filter((connection) => connection.savedConnectionType === 'favorite')
.sort(sortedAlphabetically);

const nonFavoriteConnections = allConnections
const newNonFavoriteConnections = allConnections
.filter(
({ savedConnectionType }) =>
savedConnectionType !== 'favorite' &&
Expand All @@ -121,18 +122,18 @@ export function useConnectionRepository(): ConnectionRepository {
);

setFavoriteConnections((prevList) => {
if (areConnectionsEqual(prevList, favoriteConnections)) {
if (areConnectionsEqual(prevList, newFavoriteConnections)) {
return prevList;
} else {
return favoriteConnections;
return newFavoriteConnections;
}
});

setNonFavoriteConnections((prevList) => {
if (areConnectionsEqual(prevList, nonFavoriteConnections)) {
if (areConnectionsEqual(prevList, newNonFavoriteConnections)) {
return prevList;
} else {
return nonFavoriteConnections;
return newNonFavoriteConnections;
}
});

Expand Down
134 changes: 120 additions & 14 deletions packages/compass-connections/src/stores/connections-store.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import {
ConnectionsProvider,
useConnections,
} from '../components/connections-provider';
import {
TelemetryProvider,
type TrackFunction,
} from '@mongodb-js/compass-telemetry/provider';

function getConnectionsManager(mockTestConnectFn?: typeof connect) {
const { log } = createNoopLogger();
Expand Down Expand Up @@ -69,23 +73,31 @@ describe('useConnections', function () {
let renderHookWithContext: (
props?: ComponentProps<typeof ConnectionsProvider>
) => { current: ReturnType<typeof useConnections> };
let trackSpy: TrackFunction;

before(async function () {
preferences = await createSandboxFromDefaultPreferences();
trackSpy = sinon.spy();
renderHookWithContext = (props) => {
const wrapper: React.FC = ({ children }) => {
return (
<ToastArea>
<ConfirmationModalArea>
<PreferencesProvider value={preferences}>
<ConnectionStorageProvider value={mockConnectionStorage}>
<ConnectionsManagerProvider value={connectionsManager}>
<ConnectionsProvider {...props}>
{children}
</ConnectionsProvider>
</ConnectionsManagerProvider>
</ConnectionStorageProvider>
</PreferencesProvider>
<TelemetryProvider
options={{
sendTrack: trackSpy,
}}
>
<PreferencesProvider value={preferences}>
<ConnectionStorageProvider value={mockConnectionStorage}>
<ConnectionsManagerProvider value={connectionsManager}>
<ConnectionsProvider {...props}>
{children}
</ConnectionsProvider>
</ConnectionsManagerProvider>
</ConnectionStorageProvider>
</PreferencesProvider>
</TelemetryProvider>
</ConfirmationModalArea>
</ToastArea>
);
Expand Down Expand Up @@ -123,6 +135,7 @@ describe('useConnections', function () {

afterEach(() => {
cleanup();
sinon.resetHistory();
sinon.restore();
});

Expand All @@ -139,7 +152,7 @@ describe('useConnections', function () {
renderHookWithContext({ onConnected });

await waitFor(() => {
expect(onConnected).to.have.been.called;
expect(onConnected).to.have.been.calledOnce;
});

// autoconnect info should never be saved
Expand Down Expand Up @@ -287,7 +300,7 @@ describe('useConnections', function () {
favorite: { name: 'foobar' },
});

expect(onConnectionFailed).to.have.been.called;
expect(onConnectionFailed).to.have.been.calledOnce;
expect(saveSpy).to.not.have.been.called;
});
});
Expand Down Expand Up @@ -330,8 +343,8 @@ describe('useConnections', function () {
},
});

expect(onConnectionFailed).to.have.been.called;
expect(saveSpy).to.have.been.called;
expect(onConnectionFailed).to.have.been.calledOnce;
expect(saveSpy).to.have.been.calledOnce;
});
});
});
Expand All @@ -352,9 +365,10 @@ describe('useConnections', function () {
await connections.current.disconnect(connectionInfo.id);
await connectPromise;

expect(trackSpy).to.have.been.calledWith('Connection Disconnected');
expect(() => screen.getByText(/Connecting to/)).to.throw;
expect(connectionsManager).to.have.property('closeConnection').have.been
.called;
.calledOnce;
});
});

Expand Down Expand Up @@ -392,6 +406,98 @@ describe('useConnections', function () {
});
});

describe('#saveEditedConnection', function () {
it('new connection: should call save and track the creation', async function () {
const saveSpy = sinon.spy(mockConnectionStorage, 'save');
const connections = renderHookWithContext();

// Waiting for connections to load first
await waitFor(() => {
expect(connections.current.favoriteConnections).to.have.lengthOf.gt(0);
});

const newConnection = {
...createNewConnectionInfo(),
favorite: {
name: 'peaches (50) peaches',
},
savedConnectionType: 'favorite',
};

await connections.current.saveEditedConnection(newConnection);

expect(saveSpy).to.have.been.calledOnce;
expect(trackSpy).to.have.been.calledWith('Connection Created');

await waitFor(() => {
expect(
connections.current.favoriteConnections.find((info) => {
return info.id === newConnection.id;
})
).to.exist;
});
});

it('existing connection: should call save and should not track the creation', async function () {
const saveSpy = sinon.spy(mockConnectionStorage, 'save');
const connections = renderHookWithContext();

// Waiting for connections to load first
await waitFor(() => {
expect(connections.current.favoriteConnections).to.have.lengthOf.gt(0);
});

const updatedConnection = {
...mockConnections[0],
savedConnectionType: 'recent',
};

await connections.current.saveEditedConnection(updatedConnection);

expect(saveSpy).to.have.been.calledOnce;
expect(trackSpy).to.have.been.calledWith('Connection Created');

await waitFor(() => {
expect(
connections.current.recentConnections.find((info) => {
return info.id === updatedConnection.id;
})
).to.exist;
});
});
});

describe('#removeConnection', function () {
it('should disconnect and call delete and track the deletion', async function () {
const deleteSpy = sinon.spy(mockConnectionStorage, 'delete');
const closeConnectionSpy = sinon.spy(
connectionsManager,
'closeConnection'
);
const connections = renderHookWithContext();

// Waiting for connections to load first
await waitFor(() => {
expect(connections.current.favoriteConnections).to.have.lengthOf.gt(0);
});

await connections.current.removeConnection(mockConnections[0].id);

expect(closeConnectionSpy).to.have.been.calledOnce;
expect(trackSpy).to.have.been.calledWith('Connection Removed');
expect(deleteSpy).to.have.been.calledOnce;
expect(trackSpy).to.have.been.calledWith('Connection Disconnected');

await waitFor(() => {
expect(
connections.current.favoriteConnections.find((info) => {
return info.id === mockConnections[0].id;
})
).not.to.exist;
});
});
});

describe('#editConnection', function () {
it('should only allow to edit existing connections', async function () {
const connections = renderHookWithContext();
Expand Down
35 changes: 26 additions & 9 deletions packages/compass-connections/src/stores/connections-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import { showNonGenuineMongoDBWarningModal as _showNonGenuineMongoDBWarningModal
import { getGenuineMongoDB } from 'mongodb-build-info';
import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
import { getConnectionTitle } from '@mongodb-js/connection-info';
import {
trackConnectionCreatedEvent,
trackConnectionDisconnectedEvent,
trackConnectionRemovedEvent,
} from '../utils/telemetry';

const { debug, mongoLogId, log } = createLogger('COMPASS-CONNECTIONS');

Expand Down Expand Up @@ -272,7 +277,7 @@ function useCurrentRef<T>(val: T): { current: T } {
}

export function useConnections({
onConnected,
onConnected, // TODO(COMPASS-7397): move connection-telemetry inside connections
onConnectionFailed,
onConnectionAttemptStarted,
}: {
Expand Down Expand Up @@ -355,12 +360,14 @@ export function useConnections({
} = useConnectionStatusToasts();

const saveConnectionInfo = useCallback(
async (
connectionInfo: RecursivePartial<ConnectionInfo> &
Pick<ConnectionInfo, 'id'>
) => {
async (connectionInfo: PartialConnectionInfo) => {
try {
return await saveConnection(connectionInfo);
const isNewConnection = !getConnectionInfoById(connectionInfo.id);
const savedConnectionInfo = await saveConnection(connectionInfo);
if (isNewConnection) {
trackConnectionCreatedEvent(savedConnectionInfo, track);
}
return savedConnectionInfo;
} catch (err) {
debug(
`error saving connection with id ${connectionInfo.id || ''}: ${
Expand All @@ -379,7 +386,7 @@ export function useConnections({
return null;
}
},
[openToast, saveConnection]
[openToast, saveConnection, getConnectionInfoById, track]
);

const oidcAttemptConnectNotifyDeviceAuth = useCallback(
Expand Down Expand Up @@ -435,6 +442,10 @@ export function useConnections({
);
try {
await connectionsManager.closeConnection(connectionId);
trackConnectionDisconnectedEvent(
getConnectionInfoById(connectionId),
track
);
} catch (error) {
log.error(
mongoLogId(1_001_000_314),
Expand All @@ -447,7 +458,12 @@ export function useConnections({
}
debug('connection closed', connectionId);
},
[closeConnectionStatusToast, connectionsManager]
[
closeConnectionStatusToast,
connectionsManager,
getConnectionInfoById,
track,
]
);

const createNewConnection = useCallback(() => {
Expand Down Expand Up @@ -537,10 +553,11 @@ export function useConnections({
if (connectionInfo) {
void disconnect(connectionId);
await deleteConnection(connectionInfo);
trackConnectionRemovedEvent(connectionInfo, track);
dispatch({ type: 'delete-connection', connectionInfo });
}
},
[deleteConnection, disconnect, getConnectionInfoById]
[deleteConnection, disconnect, getConnectionInfoById, track]
);

const removeAllRecentConnections = useCallback(async () => {
Expand Down
Loading

0 comments on commit ada8b30

Please sign in to comment.