mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce a centralised way to emit telemetry from calls of injectable functions (#6164)
Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Co-authored-by: Juho Heikka <juho.heikka@gmail.com>
This commit is contained in:
43 files changed
+527
-163
No files matched your search
@@ -19,6 +19,7 @@ import quitAndInstallUpdateInjectable from "../../main/application-update/quit-a
|
||||
import appVersionInjectable from "../../common/vars/app-version.injectable";
|
||||
import periodicalCheckForUpdatesInjectable from "../../main/application-update/periodical-check-for-updates/periodical-check-for-updates.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import emitEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||
|
||||
describe("analytics for installing update", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
@@ -51,6 +52,8 @@ describe("analytics for installing update", () => {
|
||||
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
|
||||
mainDi.unoverride(emitEventInjectable);
|
||||
|
||||
const eventBus = mainDi.inject(appEventBusInjectable);
|
||||
|
||||
eventBus.addListener(analyticsListenerMock);
|
||||
@@ -65,7 +68,6 @@ describe("analytics for installing update", () => {
|
||||
mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable);
|
||||
|
||||
await builder.render();
|
||||
|
||||
});
|
||||
|
||||
it("sends event to analytics for being checked periodically", () => {
|
||||
|
||||
+4
-2
@@ -10,7 +10,7 @@ import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
@@ -45,7 +45,9 @@ describe("disable kube object detail items when cluster is not relevant", () =>
|
||||
|
||||
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
+3
-1
@@ -39,7 +39,9 @@ describe("reactively hide kube object detail item", () => {
|
||||
} as unknown as ApiManager),
|
||||
);
|
||||
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
+5
-2
@@ -10,7 +10,7 @@ import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
@@ -32,7 +32,10 @@ describe("disable kube object menu items when cluster is not relevant", () => {
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
+3
-1
@@ -26,7 +26,9 @@ describe("reactively hide kube object menu item", () => {
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
+5
-2
@@ -10,7 +10,7 @@ import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
@@ -33,7 +33,10 @@ describe("disable kube object statuses when cluster is not relevant", () => {
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
+4
-1
@@ -29,7 +29,10 @@ describe("reactively hide kube object status", () => {
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
+18
-11
@@ -9,7 +9,7 @@ import { useFakeTime } from "../../../common/test-utils/use-fake-time";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IAtom } from "mobx";
|
||||
import { createAtom, computed } from "mobx";
|
||||
import { runInAction, createAtom, computed } from "mobx";
|
||||
import { frontEndRouteInjectionToken } from "../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../renderer/routes/route-specific-component-injection-token";
|
||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
@@ -94,14 +94,17 @@ describe("show status for a kube object", () => {
|
||||
});
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(
|
||||
testRouteInjectable,
|
||||
testRouteComponentInjectable,
|
||||
infoStatusInjectable,
|
||||
warningStatusInjectable,
|
||||
criticalStatusInjectable,
|
||||
someAtomInjectable,
|
||||
);
|
||||
runInAction(() => {
|
||||
windowDi.register(
|
||||
testRouteInjectable,
|
||||
testRouteComponentInjectable,
|
||||
infoStatusInjectable,
|
||||
warningStatusInjectable,
|
||||
criticalStatusInjectable,
|
||||
someAtomInjectable,
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
@@ -141,7 +144,9 @@ describe("show status for a kube object", () => {
|
||||
|
||||
describe("when status for irrelevant kube object kind emerges", () => {
|
||||
beforeEach(() => {
|
||||
windowDi.register(statusForIrrelevantKubeObjectKindInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(statusForIrrelevantKubeObjectKindInjectable);
|
||||
});
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
@@ -161,7 +166,9 @@ describe("show status for a kube object", () => {
|
||||
|
||||
describe("when status for irrelevant kube object api version emerges", () => {
|
||||
beforeEach(() => {
|
||||
windowDi.register(statusForIrrelevantKubeObjectApiVersionInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(statusForIrrelevantKubeObjectApiVersionInjectable);
|
||||
});
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import type { SidebarItemRegistration } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import { noop } from "lodash/fp";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
@@ -22,7 +22,9 @@ describe("cluster - order of sidebar items", () => {
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(testSidebarItemsInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testSidebarItemsInjectable);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import directoryForLensLocalStorageInjectable from "../../common/directory-for-l
|
||||
import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token";
|
||||
import type { SidebarItemRegistration } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import { noop } from "lodash/fp";
|
||||
import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
|
||||
@@ -51,9 +51,11 @@ describe("cluster - sidebar and tab navigation for core", () => {
|
||||
describe("given core registrations", () => {
|
||||
beforeEach(() => {
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(testRouteInjectable);
|
||||
windowDi.register(testRouteComponentInjectable);
|
||||
windowDi.register(testSidebarItemsInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable);
|
||||
windowDi.register(testRouteComponentInjectable);
|
||||
windowDi.register(testSidebarItemsInjectable);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { SidebarItemRegistration } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token";
|
||||
import React from "react";
|
||||
import isAllowedResourceInjectable from "../../common/utils/is-allowed-resource.injectable";
|
||||
@@ -25,9 +25,11 @@ describe("cluster - visibility of sidebar items", () => {
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(testRouteInjectable);
|
||||
windowDi.register(testRouteComponentInjectable);
|
||||
windowDi.register(testSidebarItemsInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteInjectable);
|
||||
windowDi.register(testRouteComponentInjectable);
|
||||
windowDi.register(testSidebarItemsInjectable);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+8
-6
@@ -8,7 +8,7 @@ import React from "react";
|
||||
import getRandomIdInjectable from "../../../../../common/utils/get-random-id.injectable";
|
||||
import { workloadOverviewDetailInjectionToken } from "../../../../../renderer/components/+workloads-overview/workload-overview-details/workload-overview-detail-injection-token";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
|
||||
describe("order of workload overview details", () => {
|
||||
let rendered: RenderResult;
|
||||
@@ -20,11 +20,13 @@ describe("order of workload overview details", () => {
|
||||
windowDi.unoverride(getRandomIdInjectable);
|
||||
windowDi.permitSideEffects(getRandomIdInjectable);
|
||||
|
||||
windowDi.register(
|
||||
someCoreItemWithLowOrderNumberInjectable,
|
||||
someCoreItemWithHighOrderNumberInjectable,
|
||||
someCoreItemWithDefaultOrderNumberInjectable,
|
||||
);
|
||||
runInAction(() => {
|
||||
windowDi.register(
|
||||
someCoreItemWithLowOrderNumberInjectable,
|
||||
someCoreItemWithHighOrderNumberInjectable,
|
||||
someCoreItemWithDefaultOrderNumberInjectable,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import React from "react";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { routeSpecificComponentInjectionToken } from "../renderer/routes/route-specific-component-injection-token";
|
||||
import { observer } from "mobx-react";
|
||||
@@ -32,8 +32,10 @@ describe("navigating between routes", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(testRouteWithoutPathParametersInjectable);
|
||||
windowDi.register(testRouteWithoutPathParametersComponentInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testRouteWithoutPathParametersInjectable);
|
||||
windowDi.register(testRouteWithoutPathParametersComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
@@ -106,8 +108,10 @@ describe("navigating between routes", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(routeWithOptionalPathParametersInjectable);
|
||||
windowDi.register(routeWithOptionalPathParametersComponentInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(routeWithOptionalPathParametersInjectable);
|
||||
windowDi.register(routeWithOptionalPathParametersComponentInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import currentPathInjectable from "../../renderer/routes/current-path.injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import { preferenceNavigationItemInjectionToken } from "../../renderer/components/+preferences/preferences-navigation/preference-navigation-items.injectable";
|
||||
import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
|
||||
import { Preferences } from "../../renderer/components/+preferences";
|
||||
@@ -30,11 +30,13 @@ describe("preferences - closing-preferences", () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.register(testPreferencesRouteInjectable);
|
||||
windowDi.register(testPreferencesRouteComponentInjectable);
|
||||
windowDi.register(testFrontPageRouteInjectable);
|
||||
windowDi.register(testFrontPageRouteComponentInjectable);
|
||||
windowDi.register(testNavigationItemInjectable);
|
||||
runInAction(() => {
|
||||
windowDi.register(testPreferencesRouteInjectable);
|
||||
windowDi.register(testPreferencesRouteComponentInjectable);
|
||||
windowDi.register(testFrontPageRouteInjectable);
|
||||
windowDi.register(testFrontPageRouteComponentInjectable);
|
||||
windowDi.register(testNavigationItemInjectable);
|
||||
});
|
||||
|
||||
windowDi.override(navigateToFrontPageInjectable, (di) => {
|
||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||
|
||||
+7
-4
@@ -13,6 +13,7 @@ import focusApplicationInjectable from "../../main/electron-app/features/focus-a
|
||||
import type { CreateElectronWindow } from "../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
|
||||
import createElectronWindowInjectable from "../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
|
||||
import splashWindowInjectable from "../../main/start-main-application/lens-window/splash-window/splash-window.injectable";
|
||||
import { runInAction } from "mobx";
|
||||
|
||||
describe("opening application window using tray", () => {
|
||||
describe("given application has started", () => {
|
||||
@@ -61,10 +62,12 @@ describe("opening application window using tray", () => {
|
||||
return browserWindow;
|
||||
});
|
||||
|
||||
(mainDi as any).decorateFunction(
|
||||
createElectronWindowInjectable,
|
||||
createElectronWindowMock,
|
||||
);
|
||||
runInAction(() => {
|
||||
(mainDi as any).decorateFunction(
|
||||
createElectronWindowInjectable,
|
||||
createElectronWindowMock,
|
||||
);
|
||||
});
|
||||
|
||||
expectWindowsToBeOpen = expectWindowsToBeOpenFor(builder);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { computed, runInAction } from "mobx";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting";
|
||||
import telemetryWhiteListForFunctionsInjectable from "./renderer/telemetry-white-list-for-functions.injectable";
|
||||
import emitEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||
|
||||
describe("emit-telemetry-from-specific-function-calls", () => {
|
||||
let di: DiContainer;
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
});
|
||||
|
||||
describe("given a telemetry white-list for injectables which instantiate a function", () => {
|
||||
let emitEventMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
di.override(telemetryWhiteListForFunctionsInjectable, () => [
|
||||
"some-white-listed-function",
|
||||
]);
|
||||
|
||||
emitEventMock = jest.fn();
|
||||
di.override(emitEventInjectable, () => emitEventMock);
|
||||
});
|
||||
|
||||
describe("given instances of white-listed, non-white-listed and tagged functions", () => {
|
||||
let whiteListedFunctionMock: jest.Mock;
|
||||
let nonWhiteListedFunctionMock: jest.Mock;
|
||||
let taggedFunctionMock: jest.Mock;
|
||||
let injectedWhiteListedFunction: jest.Mock;
|
||||
let injectedNonWhiteListedFunction: jest.Mock;
|
||||
let injectedTaggedFunction: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
whiteListedFunctionMock = jest.fn();
|
||||
nonWhiteListedFunctionMock = jest.fn();
|
||||
taggedFunctionMock = jest.fn();
|
||||
|
||||
const whiteListedInjectable = getInjectable({
|
||||
id: "some-white-listed-function",
|
||||
instantiate: () => whiteListedFunctionMock,
|
||||
});
|
||||
|
||||
const nonWhiteListedInjectable = getInjectable({
|
||||
id: "some-non-white-listed-function",
|
||||
instantiate: () => nonWhiteListedFunctionMock,
|
||||
});
|
||||
|
||||
const taggedInjectable = getInjectable({
|
||||
id: "some-tagged-function",
|
||||
instantiate: () => taggedFunctionMock,
|
||||
tags: ["emit-telemetry"],
|
||||
});
|
||||
|
||||
runInAction(() => {
|
||||
di.register(whiteListedInjectable);
|
||||
di.register(nonWhiteListedInjectable);
|
||||
di.register(taggedInjectable);
|
||||
});
|
||||
|
||||
injectedWhiteListedFunction = di.inject(whiteListedInjectable);
|
||||
injectedNonWhiteListedFunction = di.inject(nonWhiteListedInjectable);
|
||||
injectedTaggedFunction = di.inject(taggedInjectable);
|
||||
});
|
||||
|
||||
it("telemetry is not emitted yet", () => {
|
||||
expect(emitEventMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when the white-listed function is called", () => {
|
||||
beforeEach(() => {
|
||||
injectedWhiteListedFunction("some-arg", "some-other-arg");
|
||||
});
|
||||
|
||||
it("telemetry is emitted in event bus", () => {
|
||||
expect(emitEventMock).toHaveBeenCalledWith({
|
||||
destination: "auto-capture",
|
||||
action: "telemetry-from-business-action",
|
||||
name: "some-white-listed-function",
|
||||
params: { args: ["some-arg", "some-other-arg"] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the white-listed function is called with MobX reactive content", () => {
|
||||
beforeEach(() => {
|
||||
const someComputedProperty = computed(() => "some-computed-value");
|
||||
|
||||
const someObservable = {
|
||||
someStaticProperty: "some-static-value",
|
||||
someComputedProperty,
|
||||
};
|
||||
|
||||
injectedWhiteListedFunction(someObservable);
|
||||
});
|
||||
|
||||
it("telemetry is emitted in event bus without MobX internals or computeds", () => {
|
||||
expect(emitEventMock).toHaveBeenCalledWith({
|
||||
destination: "auto-capture",
|
||||
action: "telemetry-from-business-action",
|
||||
name: "some-white-listed-function",
|
||||
|
||||
params: {
|
||||
args: [
|
||||
{
|
||||
someStaticProperty: "some-static-value",
|
||||
someComputedProperty: "some-computed-value",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the non-white-listed function is called", () => {
|
||||
beforeEach(() => {
|
||||
injectedNonWhiteListedFunction();
|
||||
});
|
||||
|
||||
it("telemetry is not emitted", () => {
|
||||
expect(emitEventMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the tagged, but not white-listed function is called", () => {
|
||||
beforeEach(() => {
|
||||
injectedTaggedFunction("some-arg", "some-other-arg");
|
||||
});
|
||||
|
||||
it("telemetry is emitted in event bus", () => {
|
||||
expect(emitEventMock).toHaveBeenCalledWith({
|
||||
destination: "auto-capture",
|
||||
action: "telemetry-from-business-action",
|
||||
name: "some-tagged-function",
|
||||
params: { args: ["some-arg", "some-other-arg"] },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import emitEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||
import { toJS, observable } from "mobx";
|
||||
|
||||
const emitTelemetryInjectable = getInjectable({
|
||||
id: "emit-telemetry",
|
||||
|
||||
instantiate: (di) => {
|
||||
const emitEvent = di.inject(emitEventInjectable);
|
||||
|
||||
return ({ action, args }: { action: string; args: any[] }) => {
|
||||
emitEvent({
|
||||
destination: "auto-capture",
|
||||
action: "telemetry-from-business-action",
|
||||
name: action,
|
||||
params: { args: toJS(observable(args)) },
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
decorable: false,
|
||||
});
|
||||
|
||||
export default emitTelemetryInjectable;
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type {
|
||||
DiContainerForInjection,
|
||||
Injectable,
|
||||
} from "@ogre-tools/injectable";
|
||||
|
||||
import {
|
||||
lifecycleEnum,
|
||||
getInjectable,
|
||||
instantiationDecoratorToken,
|
||||
} from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
|
||||
import { isFunction } from "lodash/fp";
|
||||
import emitTelemetryInjectable from "./emit-telemetry.injectable";
|
||||
import telemetryWhiteListForFunctionsInjectable from "./telemetry-white-list-for-functions.injectable";
|
||||
|
||||
const telemetryDecoratorInjectable = getInjectable({
|
||||
id: "telemetry-decorator",
|
||||
|
||||
instantiate: (diForDecorator) => {
|
||||
const emitTelemetry = diForDecorator.inject(emitTelemetryInjectable);
|
||||
|
||||
const whiteList = diForDecorator.inject(
|
||||
telemetryWhiteListForFunctionsInjectable,
|
||||
);
|
||||
|
||||
const shouldEmitTelemetry = shouldEmitTelemetryFor(whiteList);
|
||||
|
||||
return {
|
||||
decorate:
|
||||
(instantiateToBeDecorated: any) =>
|
||||
(di: DiContainerForInjection, instantiationParameter: any) => {
|
||||
const instance = instantiateToBeDecorated(di, instantiationParameter);
|
||||
|
||||
if (isFunction(instance)) {
|
||||
return (...args: any[]) => {
|
||||
const currentContext = di.context.at(-1);
|
||||
|
||||
assert(currentContext);
|
||||
|
||||
if (shouldEmitTelemetry(currentContext.injectable)) {
|
||||
emitTelemetry({ action: currentContext.injectable.id, args });
|
||||
}
|
||||
|
||||
return instance(...args);
|
||||
};
|
||||
}
|
||||
|
||||
return instance;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
decorable: false,
|
||||
// Todo: this is required because of imperfect typing in injectable.
|
||||
lifecycle: lifecycleEnum.singleton,
|
||||
injectionToken: instantiationDecoratorToken,
|
||||
});
|
||||
|
||||
const shouldEmitTelemetryFor =
|
||||
(whiteList: string[]) => (injectable: Injectable<any, any, any>) =>
|
||||
injectable.tags?.includes("emit-telemetry") ||
|
||||
whiteList.includes(injectable.id);
|
||||
|
||||
export default telemetryDecoratorInjectable;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const telemetryWhiteListForFunctionsInjectable = getInjectable({
|
||||
id: "telemetry-white-list-for-functions",
|
||||
instantiate: () => ["some-placeholder-injectable-id"],
|
||||
decorable: false,
|
||||
});
|
||||
|
||||
export default telemetryWhiteListForFunctionsInjectable;
|
||||
Reference in new issue
Block a user