Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Main][Task]27939476: Initialization with iKey and endpoint to be promises #2340

Merged
merged 22 commits into from
Jun 26, 2024
Merged
1 change: 1 addition & 0 deletions .aiAutoMinify.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"eBatchDiscardedReason",
"FeatureOptInMode",
"CdnFeatureMode",
"eActiveStatus",
"eLoggingSeverity",
"_eInternalMessageId",
"SendRequestReason",
Expand Down
8 changes: 4 additions & 4 deletions AISKU/Tests/Unit/src/AISKUSize.Tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { Snippet } from "../../../src/Snippet";
import { utlRemoveSessionStorage } from "@microsoft/applicationinsights-common";

export class AISKUSizeCheck extends AITestClass {
private readonly MAX_RAW_SIZE = 140;
private readonly MAX_BUNDLE_SIZE = 140;
private readonly MAX_RAW_DEFLATE_SIZE = 56;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 56;
private readonly MAX_RAW_SIZE = 142;
private readonly MAX_BUNDLE_SIZE = 142;
private readonly MAX_RAW_DEFLATE_SIZE = 57;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 57;
private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js";
// Automatically updated by version scripts
private readonly currentVer = "3.1.2";
Expand Down
111 changes: 104 additions & 7 deletions AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { SinonSpy } from 'sinon';
import { ApplicationInsights } from '../../../src/applicationinsights-web'
import { Sender } from '@microsoft/applicationinsights-channel-js';
import { IDependencyTelemetry, ContextTagKeys, Event, Trace, Exception, Metric, PageView, PageViewPerformance, RemoteDependencyData, DistributedTracingModes, RequestHeaders, IAutoExceptionTelemetry, BreezeChannelIdentifier, IConfig } from '@microsoft/applicationinsights-common';
import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration } from "@microsoft/applicationinsights-core-js";
import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus } from "@microsoft/applicationinsights-core-js";
import { TelemetryContext } from '@microsoft/applicationinsights-properties-js';
import { createAsyncResolvedPromise, createResolvedPromise } from '@nevware21/ts-async';


export class ApplicationInsightsTests extends AITestClass {
Expand Down Expand Up @@ -43,6 +44,7 @@ export class ApplicationInsightsTests extends AITestClass {
private tagKeys = new ContextTagKeys();
private _config;
private _appId: string;
private ctx: any;

constructor(testName?: string) {
super(testName || "ApplicationInsightsTests");
Expand Down Expand Up @@ -73,6 +75,7 @@ export class ApplicationInsightsTests extends AITestClass {
this.isFetchPolyfill = fetch["polyfill"];
this.useFakeServer = false;
this._config = this._getTestConfig(this._sessionPrefix);
this.ctx = {};

const init = new ApplicationInsights({
config: this._config
Expand Down Expand Up @@ -129,18 +132,19 @@ export class ApplicationInsightsTests extends AITestClass {
if (this._ai && this._ai["dependencies"]) {
this._ai["dependencies"].teardown();
}
this.ctx = {};

console.log("* testCleanup(" + (AITestClass.currentTestInfo ? AITestClass.currentTestInfo.name : "<null>") + ")");
}

public registerTests() {
this.addDynamicConfigTests()
this.addGenericE2ETests();
this.addAnalyticsApiTests();
this.addAsyncTests();
this.addDependencyPluginTests();
this.addPropertiesPluginTests();
this.addCDNOverrideTests();
// this.addGenericE2ETests();
// this.addAnalyticsApiTests();
// this.addAsyncTests();
// this.addDependencyPluginTests();
// this.addPropertiesPluginTests();
// this.addCDNOverrideTests();
}

public addGenericE2ETests(): void {
Expand Down Expand Up @@ -240,6 +244,99 @@ export class ApplicationInsightsTests extends AITestClass {
handler.rm();
}
});

this.testCaseAsync({
name: "Init: init with cs promise, change with cs string",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {

// unload previous one first
let oriInst = this._ai;
if (oriInst && oriInst.unload) {
// force unload
oriInst.unload(false);
}

if (oriInst && oriInst["dependencies"]) {
oriInst["dependencies"].teardown();
}

this._config = this._getTestConfig(this._sessionPrefix);
let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
this._config.connectionString = csPromise;


let init = new ApplicationInsights({
config: this._config
});
init.loadAppInsights();
this._ai = init;
let config = this._ai.config;
let core = this._ai.core;
let status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");


config.connectionString = "InstrumentationKey=testIkey1;ingestionendpoint=testUrl1"
this.clock.tick(1);
status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending test1");


}].concat(PollingAssert.createPollingAssert(() => {
let core = this._ai.core
let activeStatus = core.activeStatus && core.activeStatus();

if (activeStatus === ActiveStatus.ACTIVE) {
core.config.instrumentationKey = "testIkey";
core.config.endpointUrl = "testUrl";
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});



this.testCaseAsync({
name: "Init: init with cs string, change with cs promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let config = this._ai.config;
let expectedIkey = ApplicationInsightsTests._instrumentationKey;
let expectedConnectionString = ApplicationInsightsTests._connectionString;
let expectedEndpointUrl = "https://dc.services.visualstudio.com/v2/track";
Assert.ok(config, "ApplicationInsights config exists");
Assert.equal(expectedConnectionString, config.connectionString, "connection string is set");
Assert.equal(expectedIkey, config.instrumentationKey, "ikey is set");
Assert.equal(expectedEndpointUrl, config.endpointUrl, "endpoint url is set from connection string");
let core = this._ai.core;
let status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.ACTIVE, "status should be set to active");

let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");

config.connectionString = csPromise;
this.clock.tick(1);
status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");


}].concat(PollingAssert.createPollingAssert(() => {
let core = this._ai.core
let activeStatus = core.activeStatus && core.activeStatus();

if (activeStatus === ActiveStatus.ACTIVE) {
core.config.instrumentationKey = "testIkey";
core.config.endpointUrl = "testUrl";
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});

}

public addCDNOverrideTests(): void {
Expand Down
47 changes: 43 additions & 4 deletions AISKU/src/AISku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import {
IDependencyListenerHandler
} from "@microsoft/applicationinsights-dependencies-js";
import { PropertiesPlugin } from "@microsoft/applicationinsights-properties-js";
import { IPromise, createPromise } from "@nevware21/ts-async";
import { arrForEach, arrIndexOf, objDefine, objForEachKey, strIndexOf, throwUnsupported } from "@nevware21/ts-utils";
import { IPromise, createAsyncPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async";
import { arrForEach, arrIndexOf, isPromiseLike, objDefine, objForEachKey, strIndexOf, throwUnsupported } from "@nevware21/ts-utils";
import { IApplicationInsights } from "./IApplicationInsights";
import {
STR_ADD_TELEMETRY_INITIALIZER, STR_CLEAR_AUTHENTICATED_USER_CONTEXT, STR_EVT_NAMESPACE, STR_GET_COOKIE_MGR, STR_GET_PLUGIN,
Expand Down Expand Up @@ -194,8 +194,47 @@ export class AppInsightsSku implements IApplicationInsights {

// Will get recalled if any referenced values are changed
_addUnloadHook(onConfigChange(cfgHandler, () => {
if (_config.connectionString) {
const cs = parseConnectionString(_config.connectionString);
let configCs = _config.connectionString;

if (isPromiseLike(configCs)) {
let ikeyPromise = createAsyncPromise<string>((resolve, reject) => {
doAwaitResponse(configCs, (res) => {
let curCs = res.value;
let ikey = _config.instrumentationKey;
if (!res.rejected && curCs) {
// replace cs with resolved values in case of circular promises
_config.connectionString = curCs;
Karlie-777 marked this conversation as resolved.
Show resolved Hide resolved
let resolvedCs = parseConnectionString(curCs);
ikey = resolvedCs.instrumentationkey || ikey;
}
resolve(ikey);
});

});

let urlPromise = createAsyncPromise<string>((resolve, reject) => {
Karlie-777 marked this conversation as resolved.
Show resolved Hide resolved
doAwaitResponse(configCs, (res) => {
let curCs = res.value;
let url = _config.endpointUrl;
if (!res.rejected && curCs) {
let resolvedCs = parseConnectionString(curCs);
let ingest = resolvedCs.ingestionendpoint;
url = ingest? ingest + DEFAULT_BREEZE_PATH : url;
}
resolve(url);
Karlie-777 marked this conversation as resolved.
Show resolved Hide resolved
});

});

_config.instrumentationKey = ikeyPromise;
_config.endpointUrl = _config.userOverrideEndpointUrl || urlPromise;

}
if (isString(configCs)) {
// confirm if promiselike function present
// handle cs promise here
// add cases to oneNote
const cs = parseConnectionString(configCs);
const ingest = cs.ingestionendpoint;
_config.endpointUrl = _config.userOverrideEndpointUrl ? _config.userOverrideEndpointUrl : ingest + DEFAULT_BREEZE_PATH; // add /v2/track
_config.instrumentationKey = cs.instrumentationkey || _config.instrumentationKey;
Expand Down
28 changes: 18 additions & 10 deletions channels/applicationinsights-channel-js/src/Sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import {
createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, utlCanUseSessionStorage, utlSetStoragePrefix
} from "@microsoft/applicationinsights-common";
import {
BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger,
IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, IProcessTelemetryUnloadContext,
ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction,
SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal,
_warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj,
eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, getExceptionName, getIEVersion, isArray, isBeaconsSupported,
isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload
ActiveStatus, BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration,
IDiagnosticLogger, IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext,
IProcessTelemetryUnloadContext, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXDomainRequest, IXHROverride,
OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete,
_eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext,
createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, getExceptionName, getIEVersion,
isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse,
prependTransports, runTargetUnload
} from "@microsoft/applicationinsights-core-js";
import { IPromise } from "@nevware21/ts-async";
import { ITimerHandler, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils";
import { ITimerHandler, isString, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils";
import {
DependencyEnvelopeCreator, EventEnvelopeCreator, ExceptionEnvelopeCreator, MetricEnvelopeCreator, PageViewEnvelopeCreator,
PageViewPerformanceEnvelopeCreator, TraceEnvelopeCreator
Expand Down Expand Up @@ -240,7 +241,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
if (_self.isInitialized()) {
_throwInternal(_self.diagLog(), eLoggingSeverity.CRITICAL, _eInternalMessageId.SenderNotInitialized, "Sender is already initialized");
}



_base.initialize(config, core, extensions, pluginChain);
let identifier = _self.identifier;
_serializer = new Serializer(core.logger);
Expand Down Expand Up @@ -268,6 +270,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
}
});

if (core.activeStatus() === ActiveStatus.PENDING) {
// waiting for core promises to be resolved
return;
Karlie-777 marked this conversation as resolved.
Show resolved Hide resolved
}


// Only update the endpoint if the original config !== the current config
// This is so any redirect endpointUrl is not overwritten
if (_orgEndpointUrl !== senderConfig.endpointUrl) {
Expand Down Expand Up @@ -346,7 +354,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
}

_customHeaders = senderConfig.customHeaders;
if (!isInternalApplicationInsightsEndpoint(_endpointUrl) && _customHeaders && _customHeaders.length > 0) {
if (isString(_endpointUrl) && !isInternalApplicationInsightsEndpoint(_endpointUrl) && _customHeaders && _customHeaders.length > 0) {
arrForEach(_customHeaders, customHeader => {
this.addHeader(customHeader.header, customHeader.value);
});
Expand Down
Loading