[Main][Task]27939476: Initialization with iKey and endpoint to be promises (#2340)
* add init with promise * update * udpate * udpate * update * update * update * update * update * update * update * update * update * update * update * update
This commit is contained in:
Родитель
40b150a3c8
Коммит
db5e084edd
|
@ -8,6 +8,7 @@
|
|||
"eBatchDiscardedReason",
|
||||
"FeatureOptInMode",
|
||||
"CdnFeatureMode",
|
||||
"eActiveStatus",
|
||||
"eLoggingSeverity",
|
||||
"_eInternalMessageId",
|
||||
"SendRequestReason",
|
||||
|
|
|
@ -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 = 141;
|
||||
private readonly MAX_BUNDLE_SIZE = 141;
|
||||
private readonly MAX_RAW_DEFLATE_SIZE = 57;
|
||||
private readonly MAX_BUNDLE_DEFLATE_SIZE = 57;
|
||||
private readonly MAX_RAW_SIZE = 143;
|
||||
private readonly MAX_BUNDLE_SIZE = 143;
|
||||
private readonly MAX_RAW_DEFLATE_SIZE = 58;
|
||||
private readonly MAX_BUNDLE_DEFLATE_SIZE = 58;
|
||||
private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js";
|
||||
// Automatically updated by version scripts
|
||||
private readonly currentVer = "3.2.2";
|
||||
|
|
|
@ -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, FeatureOptInMode } from "@microsoft/applicationinsights-core-js";
|
||||
import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus, FeatureOptInMode } from "@microsoft/applicationinsights-core-js";
|
||||
import { TelemetryContext } from '@microsoft/applicationinsights-properties-js';
|
||||
import { createAsyncResolvedPromise } from '@nevware21/ts-async';
|
||||
import { CONFIG_ENDPOINT_URL } from '../../../src/InternalConstants';
|
||||
import { OfflineChannel } from '@microsoft/applicationinsights-offlinechannel-js';
|
||||
|
||||
|
@ -47,6 +48,7 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
private _appId: string;
|
||||
private _ctx: any;
|
||||
|
||||
|
||||
constructor(testName?: string) {
|
||||
super(testName || "ApplicationInsightsTests");
|
||||
}
|
||||
|
@ -250,6 +252,217 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
}
|
||||
});
|
||||
|
||||
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;
|
||||
this._config.initTimeOut= 80000;
|
||||
|
||||
|
||||
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();
|
||||
// promise is not resolved, no new changes applied
|
||||
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) {
|
||||
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
|
||||
Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Init: init with cs promise and offline channel",
|
||||
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 offlineChannel = new OfflineChannel();
|
||||
this._config.channels = [[offlineChannel]];
|
||||
this._config.initTimeOut= 80000;
|
||||
|
||||
|
||||
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) {
|
||||
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
|
||||
Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set");
|
||||
let sendChannel = this._ai.getPlugin(BreezeChannelIdentifier);
|
||||
let offlineChannelPlugin = this._ai.getPlugin("OfflineChannel").plugin;
|
||||
Assert.equal(sendChannel.plugin.isInitialized(), true, "sender is initialized");
|
||||
Assert.equal(offlineChannelPlugin.isInitialized(), true, "offline channel is initialized");
|
||||
let urlConfig = offlineChannelPlugin["_getDbgPlgTargets"]()[0];
|
||||
Assert.ok(urlConfig, "offline url config is initialized");
|
||||
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;
|
||||
config.initTimeOut = 80000;
|
||||
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) {
|
||||
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
|
||||
Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Init: init with cs null, ikey promise, endpoint promise",
|
||||
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 ikeyPromise = createAsyncResolvedPromise("testIkey");
|
||||
let endpointPromise = createAsyncResolvedPromise("testUrl");
|
||||
//let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
|
||||
//this._config.connectionString = csPromise;
|
||||
this._config.connectionString = null;
|
||||
this._config.instrumentationKey = ikeyPromise;
|
||||
this._config.endpointUrl = endpointPromise;
|
||||
this._config.initTimeOut= 80000;
|
||||
|
||||
|
||||
|
||||
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");
|
||||
Assert.equal(config.connectionString,null, "connection string shoule be null");
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this._ai.core
|
||||
let activeStatus = core.activeStatus && core.activeStatus();
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
|
||||
Assert.equal("testUrl", core.config.endpointUrl ,"endpoint shoule be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
|
||||
this.testCase({
|
||||
name: "CfgSync DynamicConfigTests: Prod CDN is Fetched and feature is turned on/off as expected",
|
||||
useFakeTimers: true,
|
||||
|
@ -295,7 +508,7 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
});
|
||||
|
||||
this.testCase({
|
||||
name: "CfgSync DynamicConfigTests: Offline Support can be added and initialized with endpoint url",
|
||||
name: "Init Promise: Offline Support can be added and initialized with endpoint url",
|
||||
useFakeTimers: true,
|
||||
test: () => {
|
||||
this.clock.tick(1);
|
||||
|
@ -327,13 +540,13 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
if (ai && ai["dependencies"]) {
|
||||
ai["dependencies"].teardown();
|
||||
}
|
||||
offlineChannel.teardown();
|
||||
//offlineChannel.teardown();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "CfgSync DynamicConfigTests: Offline Support can be added and initialized with channels",
|
||||
name: "Init Promise: Offline Support can be added and initialized with channels",
|
||||
useFakeTimers: true,
|
||||
test: () => {
|
||||
this.clock.tick(1);
|
||||
|
@ -365,7 +578,6 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
if (ai && ai["dependencies"]) {
|
||||
ai["dependencies"].teardown();
|
||||
}
|
||||
offlineChannel.teardown();
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -377,7 +589,7 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
this.clock.tick(1);
|
||||
let offlineChannel = new OfflineChannel();
|
||||
let config = {
|
||||
instrumentationKey: "testIKey",
|
||||
connectionString: "InstrumentationKey=testIKey",
|
||||
extensionConfig:{
|
||||
["AppInsightsCfgSyncPlugin"]: {
|
||||
cfgUrl: ""
|
||||
|
@ -395,13 +607,14 @@ export class ApplicationInsightsTests extends AITestClass {
|
|||
Assert.equal(sendChannel.plugin.isInitialized(), true, "sender is initialized");
|
||||
Assert.equal(offlineChannelPlugin.isInitialized(), true, "offline channel is initialized");
|
||||
let urlConfig = offlineChannelPlugin["_getDbgPlgTargets"]()[0];
|
||||
|
||||
this.clock.tick(1);
|
||||
Assert.ok(urlConfig, "offline url config is initialized");
|
||||
|
||||
ai.unload(false);
|
||||
if (ai && ai["dependencies"]) {
|
||||
ai["dependencies"].teardown();
|
||||
}
|
||||
offlineChannel.teardown();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ import { AnalyticsPlugin, ApplicationInsights } from "@microsoft/applicationinsi
|
|||
import { CfgSyncPlugin, ICfgSyncConfig, ICfgSyncMode } from "@microsoft/applicationinsights-cfgsync-js";
|
||||
import { Sender } from "@microsoft/applicationinsights-channel-js";
|
||||
import {
|
||||
AnalyticsPluginIdentifier, DEFAULT_BREEZE_PATH, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry, IEventTelemetry,
|
||||
IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry, IPageViewTelemetry, IRequestHeaders,
|
||||
AnalyticsPluginIdentifier, ConnectionString, DEFAULT_BREEZE_PATH, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry,
|
||||
IEventTelemetry, IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry, IPageViewTelemetry, IRequestHeaders,
|
||||
ITelemetryContext as Common_ITelemetryContext, IThrottleInterval, IThrottleLimit, IThrottleMgrConfig, ITraceTelemetry,
|
||||
PropertiesPluginIdentifier, ThrottleMgr, parseConnectionString
|
||||
} from "@microsoft/applicationinsights-common";
|
||||
|
@ -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 {
|
||||
CONFIG_ENDPOINT_URL, STR_ADD_TELEMETRY_INITIALIZER, STR_CLEAR_AUTHENTICATED_USER_CONTEXT, STR_EVT_NAMESPACE, STR_GET_COOKIE_MGR,
|
||||
|
@ -200,8 +200,65 @@ 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;
|
||||
|
||||
function _parseCs() {
|
||||
return createAsyncPromise<ConnectionString>((resolve, reject) => {
|
||||
doAwaitResponse(configCs, (res) => {
|
||||
let curCs = res && res.value;
|
||||
let parsedCs = null;
|
||||
if (!res.rejected && curCs) {
|
||||
// replace cs with resolved values in case of circular promises
|
||||
_config.connectionString = curCs;
|
||||
parsedCs = parseConnectionString(curCs);
|
||||
}
|
||||
// if can't resolve cs promise, null will be returned
|
||||
resolve(parsedCs);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (isPromiseLike(configCs)) {
|
||||
let ikeyPromise = createAsyncPromise<string>((resolve, reject) => {
|
||||
_parseCs().then((cs) => {
|
||||
let ikey = _config.instrumentationKey;
|
||||
ikey = cs && cs.instrumentationkey || ikey;
|
||||
resolve(ikey);
|
||||
}).catch((e) => {
|
||||
// parseCs will always resolve(unless timeout)
|
||||
// return null in case any error happens
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
let url: IPromise<string> | string = _config.userOverrideEndpointUrl;
|
||||
if (isNullOrUndefined(url)) {
|
||||
url = createAsyncPromise<string>((resolve, reject) => {
|
||||
_parseCs().then((cs) => {
|
||||
let url = _config.endpointUrl;
|
||||
let ingest = cs && cs.ingestionendpoint;
|
||||
url = ingest? ingest + DEFAULT_BREEZE_PATH : url;
|
||||
resolve(url);
|
||||
}).catch((e) => {
|
||||
// parseCs will always resolve(unless timeout)
|
||||
// return null in case any error happens
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
_config.instrumentationKey = ikeyPromise;
|
||||
_config.endpointUrl = url;
|
||||
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -2,10 +2,10 @@ import { AITestClass, Assert } from "@microsoft/ai-test-framework";
|
|||
import * as pako from "pako";
|
||||
|
||||
export class AISKULightSizeCheck extends AITestClass {
|
||||
private readonly MAX_RAW_SIZE = 88;
|
||||
private readonly MAX_BUNDLE_SIZE = 88;
|
||||
private readonly MAX_RAW_DEFLATE_SIZE = 36;
|
||||
private readonly MAX_BUNDLE_DEFLATE_SIZE = 36;
|
||||
private readonly MAX_RAW_SIZE = 89;
|
||||
private readonly MAX_BUNDLE_SIZE = 89;
|
||||
private readonly MAX_RAW_DEFLATE_SIZE = 37;
|
||||
private readonly MAX_BUNDLE_DEFLATE_SIZE = 37;
|
||||
private readonly rawFilePath = "../dist/es5/applicationinsights-web-basic.min.js";
|
||||
private readonly currentVer = "3.2.2";
|
||||
private readonly prodFilePath = `../browser/es5/aib.${this.currentVer[0]}.min.js`;
|
||||
|
|
|
@ -8,8 +8,8 @@ import {
|
|||
AppInsightsCore, IConfigDefaults, IConfiguration, IDynamicConfigHandler, ILoadedPlugin, IPlugin, ITelemetryItem, ITelemetryPlugin,
|
||||
ITelemetryUnloadState, IUnloadHook, UnloadHandler, WatcherFunction, cfgDfValidate, createDynamicConfig, onConfigChange, proxyFunctions
|
||||
} from "@microsoft/applicationinsights-core-js";
|
||||
import { IPromise } from "@nevware21/ts-async";
|
||||
import { isNullOrUndefined, objDefine, throwError } from "@nevware21/ts-utils";
|
||||
import { IPromise, createAsyncPromise, doAwaitResponse } from "@nevware21/ts-async";
|
||||
import { isNullOrUndefined, isPromiseLike, isString, objDefine, throwError } from "@nevware21/ts-utils";
|
||||
|
||||
const defaultConfigValues: IConfigDefaults<IConfiguration> = {
|
||||
diagnosticLogInterval: cfgDfValidate(_chkDiagLevel, 10000)
|
||||
|
@ -73,8 +73,45 @@ export class ApplicationInsights {
|
|||
_config = cfgHandler.cfg;
|
||||
|
||||
core.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;
|
||||
let resolvedCs = parseConnectionString(curCs);
|
||||
ikey = resolvedCs.instrumentationkey || ikey;
|
||||
}
|
||||
resolve(ikey);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
let urlPromise = createAsyncPromise<string>((resolve, reject) => {
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
_config.instrumentationKey = ikeyPromise;
|
||||
_config.endpointUrl = _config.userOverrideEndpointUrl || urlPromise;
|
||||
|
||||
}
|
||||
|
||||
if (isString(configCs)) {
|
||||
const cs = parseConnectionString(configCs);
|
||||
const ingest = cs.ingestionendpoint;
|
||||
_config.endpointUrl = _config.userOverrideEndpointUrl ? _config.userOverrideEndpointUrl : (ingest + DEFAULT_BREEZE_PATH); // only add /v2/track when from connectionstring
|
||||
_config.instrumentationKey = cs.instrumentationkey || _config.instrumentationKey;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { AITestClass } from "@microsoft/ai-test-framework";
|
||||
import { AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
|
||||
import { Sender } from "../../../src/Sender";
|
||||
import { IOfflineListener, createOfflineListener, utlGetSessionStorageKeys, utlRemoveSessionStorage } from "@microsoft/applicationinsights-common";
|
||||
import { EnvelopeCreator } from '../../../src/EnvelopeCreator';
|
||||
import { Exception, CtxTagKeys, isBeaconApiSupported, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, utlCanUseSessionStorage, utlGetSessionStorage, utlSetSessionStorage } from "@microsoft/applicationinsights-common";
|
||||
import { ITelemetryItem, AppInsightsCore, ITelemetryPlugin, DiagnosticLogger, NotificationManager, SendRequestReason, _eInternalMessageId, safeGetLogger, isString, isArray, arrForEach, isBeaconsSupported, IXHROverride, IPayloadData,TransportType, getWindow } from "@microsoft/applicationinsights-core-js";
|
||||
import { ITelemetryItem, AppInsightsCore, ITelemetryPlugin, DiagnosticLogger, NotificationManager, SendRequestReason, _eInternalMessageId, safeGetLogger, isString, isArray, arrForEach, isBeaconsSupported, IXHROverride, IPayloadData,TransportType, getWindow, ActiveStatus } from "@microsoft/applicationinsights-core-js";
|
||||
import { ArraySendBuffer, SessionStorageSendBuffer } from "../../../src/SendBuffer";
|
||||
import { IInternalStorageItem, ISenderConfig } from "../../../src/Interfaces";
|
||||
import { createAsyncResolvedPromise } from "@nevware21/ts-async";
|
||||
|
||||
|
||||
|
||||
|
@ -163,6 +164,40 @@ export class SenderTests extends AITestClass {
|
|||
}
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Channel Init: init with promise",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
|
||||
let core = new AppInsightsCore();
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey");
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl");
|
||||
let coreConfig = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000,
|
||||
extensionConfig: {}
|
||||
}
|
||||
core.initialize(coreConfig, [this._sender]);
|
||||
|
||||
let status = core.activeStatus && core.activeStatus();
|
||||
QUnit.assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this._sender.core;
|
||||
let activeStatus = core.activeStatus && core.activeStatus();
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
QUnit.assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
|
||||
QUnit.assert.equal("testUrl", core.config.endpointUrl ,"endpoint shoule be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "Channel Config: Sender override can be handled correctly",
|
||||
useFakeTimers: true,
|
||||
|
|
|
@ -5,13 +5,14 @@ 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, isNumber, isString, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils";
|
||||
|
@ -242,7 +243,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);
|
||||
|
@ -270,6 +272,19 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
|
|||
}
|
||||
});
|
||||
|
||||
// or is not string
|
||||
if (core.activeStatus() === ActiveStatus.PENDING) {
|
||||
// waiting for core promises to be resolved
|
||||
// NOTE: if active status is set to pending, stop sending, clear timer here
|
||||
_self.pause();
|
||||
} else if (core.activeStatus() === ActiveStatus.ACTIVE) {
|
||||
// core status changed from pending to other status
|
||||
_self.resume();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Only update the endpoint if the original config !== the current config
|
||||
// This is so any redirect endpointUrl is not overwritten
|
||||
if (_orgEndpointUrl !== senderConfig.endpointUrl) {
|
||||
|
@ -348,7 +363,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);
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
eLoggingSeverity, mergeEvtNamespace, onConfigChange, runTargetUnload
|
||||
} from "@microsoft/applicationinsights-core-js";
|
||||
import { IPromise, ITaskScheduler, createAsyncPromise, createTaskScheduler } from "@nevware21/ts-async";
|
||||
import { ITimerHandler, isFunction, objDeepFreeze, scheduleTimeout } from "@nevware21/ts-utils";
|
||||
import { ITimerHandler, isFunction, isString, objDeepFreeze, scheduleTimeout } from "@nevware21/ts-utils";
|
||||
import {
|
||||
EVT_DISCARD_STR, EVT_SENT_STR, EVT_STORE_STR, batchDropNotification, callNotification, isGreaterThanZero
|
||||
} from "./Helpers/Utils";
|
||||
|
@ -401,12 +401,12 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
|
|||
_storeNotification(sentItems);
|
||||
}
|
||||
};
|
||||
if (payloadData) {
|
||||
if (payloadData && _urlCfg && _urlCfg.batchHandler) {
|
||||
let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload);
|
||||
_queueStorageEvent("storeBatch", promise);
|
||||
}
|
||||
|
||||
if (!_inMemoBatch.count()) {
|
||||
if (_inMemoBatch && !_inMemoBatch.count()) {
|
||||
_inMemoFlushTimer && _inMemoFlushTimer.cancel();
|
||||
}
|
||||
|
||||
|
@ -448,8 +448,11 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
|
|||
}
|
||||
|
||||
}
|
||||
let promise = _urlCfg.batchHandler.sendNextBatch(callback, false, _senderInst);
|
||||
_queueStorageEvent("sendNextBatch", promise);
|
||||
if (_urlCfg && _urlCfg.batchHandler) {
|
||||
let promise = _urlCfg.batchHandler.sendNextBatch(callback, false, _senderInst);
|
||||
_queueStorageEvent("sendNextBatch", promise);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -570,6 +573,14 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
|
|||
function _createUrlConfig(coreConfig: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?: ITelemetryPluginChain) {
|
||||
|
||||
_self._addHook(onConfigChange(coreConfig, (details) => {
|
||||
if (!isString(coreConfig.instrumentationKey) || !isString(coreConfig.endpointUrl)) {
|
||||
// if ikey or endpointUrl is promise, delay initialization
|
||||
_self.pause();
|
||||
return;
|
||||
}
|
||||
if (_paused) {
|
||||
_self.resume();
|
||||
}
|
||||
let storageConfig: IOfflineChannelConfiguration = null;
|
||||
let theConfig = details.cfg;
|
||||
|
||||
|
@ -614,7 +625,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
|
|||
|
||||
handler.initialize(providerContext);
|
||||
urlConfig = {
|
||||
iKey: coreConfig.instrumentationKey,
|
||||
iKey: coreConfig.instrumentationKey as string,
|
||||
url: curUrl,
|
||||
minPersistenceCacheLevel: storageConfig.minPersistenceLevel,
|
||||
coreRootCtx: coreRootCtx,
|
||||
|
|
|
@ -5,7 +5,7 @@ import dynamicProto from "@microsoft/dynamicproto-js";
|
|||
import { EventPersistence } from "@microsoft/applicationinsights-common";
|
||||
import {
|
||||
INotificationManager, IProcessTelemetryContext, IUnloadHookContainer, eBatchDiscardedReason, eLoggingSeverity, isNotNullOrUndefined,
|
||||
isNumber, newGuid, onConfigChange
|
||||
isNumber, isString, newGuid, onConfigChange
|
||||
} from "@microsoft/applicationinsights-core-js";
|
||||
import { IPromise, createAsyncAllPromise, createAsyncPromise, doAwait, doAwaitResponse } from "@nevware21/ts-async";
|
||||
import { batchDropNotification, getEndpointDomain, getTimeFromId, getTimeId } from "../Helpers/Utils";
|
||||
|
@ -280,7 +280,12 @@ export class IndexedDbProvider implements IOfflineProvider {
|
|||
}
|
||||
let coreConfig = providerContext.itemCtx.getCfg();
|
||||
let itemCtx = providerContext.itemCtx;
|
||||
_iKey = itemCtx.getCfg().instrumentationKey || coreConfig.instrumentationKey;
|
||||
let ikey = itemCtx.getCfg().instrumentationKey || coreConfig.instrumentationKey;
|
||||
if (!isString(ikey)) {
|
||||
//_iKey = ikey
|
||||
return;
|
||||
}
|
||||
_iKey = ikey;
|
||||
|
||||
let storageConfig: IOfflineChannelConfiguration = providerContext.storageConfig;
|
||||
_storageId = _this.id || providerContext.id || newGuid();
|
||||
|
|
|
@ -1573,16 +1573,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz",
|
||||
"integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz",
|
||||
"integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.13.1",
|
||||
"@typescript-eslint/type-utils": "7.13.1",
|
||||
"@typescript-eslint/utils": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1",
|
||||
"@typescript-eslint/scope-manager": "7.14.1",
|
||||
"@typescript-eslint/type-utils": "7.14.1",
|
||||
"@typescript-eslint/utils": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
|
@ -1606,15 +1606,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz",
|
||||
"integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
|
||||
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.13.1",
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/typescript-estree": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1",
|
||||
"@typescript-eslint/scope-manager": "7.14.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1634,13 +1634,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz",
|
||||
"integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz",
|
||||
"integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1"
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -1651,13 +1651,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz",
|
||||
"integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz",
|
||||
"integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.13.1",
|
||||
"@typescript-eslint/utils": "7.13.1",
|
||||
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||
"@typescript-eslint/utils": "7.14.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
|
@ -1678,9 +1678,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz",
|
||||
"integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz",
|
||||
"integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -1691,13 +1691,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz",
|
||||
"integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz",
|
||||
"integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -1755,15 +1755,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz",
|
||||
"integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz",
|
||||
"integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "7.13.1",
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/typescript-estree": "7.13.1"
|
||||
"@typescript-eslint/scope-manager": "7.14.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/typescript-estree": "7.14.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -1777,12 +1777,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz",
|
||||
"integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz",
|
||||
"integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2641,9 +2641,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.807",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.807.tgz",
|
||||
"integrity": "sha512-kSmJl2ZwhNf/bcIuCH/imtNOKlpkLDn2jqT5FJ+/0CXjhnFaOa9cOe9gHKKy71eM49izwuQjZhKk+lWQ1JxB7A=="
|
||||
"version": "1.4.811",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz",
|
||||
"integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
|
@ -4142,9 +4142,9 @@
|
|||
"peer": true
|
||||
},
|
||||
"node_modules/jsonc-parser": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
|
||||
"integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA=="
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
|
@ -7681,16 +7681,16 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz",
|
||||
"integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz",
|
||||
"integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.13.1",
|
||||
"@typescript-eslint/type-utils": "7.13.1",
|
||||
"@typescript-eslint/utils": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1",
|
||||
"@typescript-eslint/scope-manager": "7.14.1",
|
||||
"@typescript-eslint/type-utils": "7.14.1",
|
||||
"@typescript-eslint/utils": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
|
@ -7698,54 +7698,54 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz",
|
||||
"integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
|
||||
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "7.13.1",
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/typescript-estree": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1",
|
||||
"@typescript-eslint/scope-manager": "7.14.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz",
|
||||
"integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz",
|
||||
"integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1"
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz",
|
||||
"integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz",
|
||||
"integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "7.13.1",
|
||||
"@typescript-eslint/utils": "7.13.1",
|
||||
"@typescript-eslint/typescript-estree": "7.14.1",
|
||||
"@typescript-eslint/utils": "7.14.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz",
|
||||
"integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz",
|
||||
"integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==",
|
||||
"peer": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz",
|
||||
"integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz",
|
||||
"integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/visitor-keys": "7.13.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/visitor-keys": "7.14.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -7781,24 +7781,24 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz",
|
||||
"integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz",
|
||||
"integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "7.13.1",
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/typescript-estree": "7.13.1"
|
||||
"@typescript-eslint/scope-manager": "7.14.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"@typescript-eslint/typescript-estree": "7.14.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz",
|
||||
"integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==",
|
||||
"version": "7.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz",
|
||||
"integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.13.1",
|
||||
"@typescript-eslint/types": "7.14.1",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
}
|
||||
},
|
||||
|
@ -8403,9 +8403,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.807",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.807.tgz",
|
||||
"integrity": "sha512-kSmJl2ZwhNf/bcIuCH/imtNOKlpkLDn2jqT5FJ+/0CXjhnFaOa9cOe9gHKKy71eM49izwuQjZhKk+lWQ1JxB7A=="
|
||||
"version": "1.4.811",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz",
|
||||
"integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA=="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
|
@ -9533,9 +9533,9 @@
|
|||
"peer": true
|
||||
},
|
||||
"jsonc-parser": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
|
||||
"integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA=="
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { SinonStub } from "sinon";
|
||||
import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
|
||||
import { createSyncPromise } from "@nevware21/ts-async";
|
||||
import { createAsyncResolvedPromise, createSyncPromise } from "@nevware21/ts-async";
|
||||
import { AjaxMonitor } from "../../../src/ajax";
|
||||
import { DisabledPropertyName, IConfig, DistributedTracingModes, RequestHeaders, IDependencyTelemetry, IRequestContext, formatTraceParent, createTraceParent, PropertiesPluginIdentifier } from "@microsoft/applicationinsights-common";
|
||||
import {
|
||||
AppInsightsCore, IConfiguration, ITelemetryItem, ITelemetryPlugin, IChannelControls, _eInternalMessageId,
|
||||
getPerformance, getGlobalInst, getGlobal, generateW3CId, arrForEach
|
||||
getPerformance, getGlobalInst, getGlobal, generateW3CId, arrForEach,
|
||||
ActiveStatus
|
||||
} from "@microsoft/applicationinsights-core-js";
|
||||
import { IDependencyListenerDetails } from "../../../src/DependencyListener";
|
||||
import { FakeXMLHttpRequest } from "@microsoft/ai-test-framework";
|
||||
|
@ -208,6 +209,59 @@ export class AjaxTests extends AITestClass {
|
|||
}
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "Dependencies Configuration: init with cs promise ikey promise and default enableAjaxPerfTracking",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
this._ajax = new AjaxMonitor();
|
||||
let csPromise = createAsyncResolvedPromise("testIkey");
|
||||
let appInsightsCore = new AppInsightsCore();
|
||||
let coreConfig = {
|
||||
instrumentationKey: csPromise,
|
||||
initTimeOut: 80000
|
||||
|
||||
};
|
||||
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
|
||||
|
||||
let trackStub = this.sandbox.stub(appInsightsCore, "track");
|
||||
let throwSpy = this.sandbox.spy(appInsightsCore.logger, "throwInternal");
|
||||
Assert.equal(false, trackStub.called, "Track should not be called");
|
||||
Assert.equal(false, throwSpy.called, "We should not have thrown an internal error");
|
||||
|
||||
this._context.core = appInsightsCore;
|
||||
this._context.trackStub = trackStub;
|
||||
this._context.throwSpy = throwSpy;
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://microsoft.com");
|
||||
xhr.setRequestHeader("Content-type", "application/json");
|
||||
xhr.send();
|
||||
// Emulate response
|
||||
(<any>xhr).respond(200, {"Content-Type": "application/json; charset=utf-8", "Access-Control-Allow-Origin": "*"}, "");
|
||||
Assert.ok((<any>xhr)[AJAX_DATA_CONTAINER], "should have xhr hooks");
|
||||
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this._context.core
|
||||
let activeStatus = core.activeStatus && core.activeStatus();
|
||||
let trackStub = this._context.trackStub;
|
||||
let throwSpy = this._context.throwSpy;
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
|
||||
Assert.equal(1, trackStub.callCount, "Track should be called once");
|
||||
Assert.equal(false, throwSpy.called, "We should not have thrown an internal error test1");
|
||||
let data = trackStub.args[0][0].baseData;
|
||||
Assert.equal(data.type, "Ajax", "request type should be ajax");
|
||||
Assert.ok(data.properties, "properties should be added");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCase({
|
||||
name: "Dependencies Configuration: Make sure we don't fail for invalid arguments",
|
||||
test: () => {
|
||||
|
|
|
@ -597,12 +597,14 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
|
|||
_isUsingW3CHeaders = _distributedTracingMode === eDistributedTracingModes.AI_AND_W3C || _distributedTracingMode === eDistributedTracingModes.W3C;
|
||||
|
||||
if (_enableAjaxPerfTracking) {
|
||||
let iKey = config.instrumentationKey || "unkwn";
|
||||
let iKey = (config.instrumentationKey as string) || "unkwn";
|
||||
// TODO: handle ikey promise
|
||||
if (iKey.length > 5) {
|
||||
_markPrefix = AJAX_MONITOR_PREFIX + strSubstring(iKey, iKey.length - 5) + ".";
|
||||
} else {
|
||||
_markPrefix = AJAX_MONITOR_PREFIX + iKey + ".";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_disableAjaxTracking = !!_extensionConfig.disableAjaxTracking;
|
||||
|
|
|
@ -2,8 +2,8 @@ import { AITestClass } from "@microsoft/ai-test-framework";
|
|||
import * as pako from 'pako';
|
||||
|
||||
export class FileSizeCheckTest extends AITestClass {
|
||||
private readonly MAX_BUNDLE_SIZE = 66;
|
||||
private readonly MAX_DEFLATE_SIZE = 28;
|
||||
private readonly MAX_BUNDLE_SIZE = 68;
|
||||
private readonly MAX_DEFLATE_SIZE = 29;
|
||||
private readonly bundleFilePath = "../bundle/es5/ms.core.min.js";
|
||||
|
||||
public testInitialize() {
|
||||
|
|
|
@ -7,6 +7,7 @@ export {
|
|||
} from "./Util";
|
||||
export { ThrottleMgr } from "./ThrottleMgr";
|
||||
export { parseConnectionString, ConnectionStringParser } from "./ConnectionStringParser";
|
||||
export { ConnectionString } from "./Interfaces/ConnectionString";
|
||||
export { FieldType } from "./Enums";
|
||||
export { IRequestHeaders, RequestHeaders, eRequestHeaders } from "./RequestResponseHeaders";
|
||||
export { DisabledPropertyName, ProcessLegacy, SampleRate, HttpMethod, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, strNotSpecified } from "./Constants";
|
||||
|
|
|
@ -2,8 +2,8 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework";
|
|||
import * as pako from "pako";
|
||||
|
||||
export class AppInsightsCoreSizeCheck extends AITestClass {
|
||||
private readonly MAX_RAW_SIZE = 64;
|
||||
private readonly MAX_BUNDLE_SIZE = 64;
|
||||
private readonly MAX_RAW_SIZE = 65;
|
||||
private readonly MAX_BUNDLE_SIZE = 65;
|
||||
private readonly MAX_RAW_DEFLATE_SIZE = 27;
|
||||
private readonly MAX_BUNDLE_DEFLATE_SIZE = 27;
|
||||
private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js";
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
import { Assert, AITestClass } from "@microsoft/ai-test-framework";
|
||||
import { IConfiguration, ITelemetryPlugin, ITelemetryItem, IPlugin, IAppInsightsCore, normalizeJsName, random32, mwcRandomSeed, newId, randomValue, mwcRandom32, isNullOrUndefined, SenderPostManager, OnCompleteCallback, IPayloadData, _ISenderOnComplete, TransportType, _ISendPostMgrConfig, dumpObj } from "../../../src/applicationinsights-core-js"
|
||||
import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
|
||||
import { IConfiguration, ITelemetryPlugin, ITelemetryItem, IPlugin, IAppInsightsCore, normalizeJsName, random32, mwcRandomSeed, newId, randomValue, mwcRandom32, isNullOrUndefined, SenderPostManager, OnCompleteCallback, IPayloadData, _ISenderOnComplete, TransportType, _ISendPostMgrConfig, dumpObj, onConfigChange, createProcessTelemetryContext } from "../../../src/applicationinsights-core-js"
|
||||
import { AppInsightsCore } from "../../../src/JavaScriptSDK/AppInsightsCore";
|
||||
import { IChannelControls } from "../../../src/JavaScriptSDK.Interfaces/IChannelControls";
|
||||
import { _eInternalMessageId, LoggingSeverity } from "../../../src/JavaScriptSDK.Enums/LoggingEnums";
|
||||
import { _InternalLogMessage, DiagnosticLogger } from "../../../src/JavaScriptSDK/DiagnosticLogger";
|
||||
import { ActiveStatus } from "../../../src/JavaScriptSDK.Enums/InitActiveStatusEnum";
|
||||
import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createTimeoutPromise, doAwaitResponse } from "@nevware21/ts-async";
|
||||
|
||||
const AIInternalMessagePrefix = "AITR_";
|
||||
const MaxInt32 = 0xFFFFFFFF;
|
||||
|
||||
export class ApplicationInsightsCoreTests extends AITestClass {
|
||||
private ctx: any;
|
||||
|
||||
public testInitialize() {
|
||||
super.testInitialize();
|
||||
this.ctx = {};
|
||||
}
|
||||
|
||||
public testCleanup() {
|
||||
super.testCleanup();
|
||||
this.ctx = {};
|
||||
|
||||
}
|
||||
|
||||
public registerTests() {
|
||||
|
@ -848,6 +854,814 @@ export class ApplicationInsightsCoreTests extends AITestClass {
|
|||
}
|
||||
});
|
||||
|
||||
// init with ikey: null
|
||||
this.testCase({
|
||||
name: "ApplicationInsightsCore Init: init with ikey null, will throw error message",
|
||||
useFakeTimers: true,
|
||||
test: () => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.NONE, "default should be inactive status");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: undefined,
|
||||
endpointUrl: "testUrl"
|
||||
} as IConfiguration;
|
||||
|
||||
let errorisCalled = false;
|
||||
|
||||
try {
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
} catch (e) {
|
||||
errorisCalled = true;
|
||||
Assert.ok(JSON.stringify(e.message).indexOf("Please provide instrumentation key") > -1, "should send provide ikey error message");
|
||||
}
|
||||
|
||||
Assert.ok(errorisCalled, "ikey error should be called");
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.equal(core.config.instrumentationKey, null, "channel testIkey should be null");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should not be changed");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.INACTIVE, "default should be inactive status test1");
|
||||
|
||||
core.track({name: "test1"});
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
|
||||
|
||||
let isInit = core.isInitialized();
|
||||
Assert.ok(!isInit, "core is not initialized");
|
||||
|
||||
// Test re-init with valid ikey
|
||||
config.instrumentationKey = "testIkey";
|
||||
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should be set");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should not be changed");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status again");
|
||||
isInit = core.isInitialized();
|
||||
Assert.ok(isInit, "core is initialized");
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// init with ikey: string, endpoint null
|
||||
this.testCase({
|
||||
name: "ApplicationInsightsCore Init: init with ikey string, endpoint null",
|
||||
useFakeTimers: true,
|
||||
test: () => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.NONE, "default should be inactive status");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: "testIkey",
|
||||
endpointUrl: undefined
|
||||
} as IConfiguration;
|
||||
|
||||
let errorisCalled = false;
|
||||
|
||||
try {
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
} catch (e) {
|
||||
errorisCalled = true;
|
||||
}
|
||||
|
||||
Assert.ok(!errorisCalled, "ikey error should not be called");
|
||||
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be null");
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status test");
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// init with ikey: string, endpointUrl: string
|
||||
this.testCase({
|
||||
name: "ApplicationInsightsCore Init: init with ikey string, endpoint url string, dynamic changes with string",
|
||||
useFakeTimers: true,
|
||||
test: () => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.NONE, "default should be pending status");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: "testIkey",
|
||||
endpointUrl: "testUrl"
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should be set");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be set");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status");
|
||||
|
||||
|
||||
|
||||
core.config.instrumentationKey = "testIkey1";
|
||||
core.config.endpointUrl = "testUrl1";
|
||||
this.clock.tick(1);
|
||||
core.track({name: "test1"});
|
||||
Assert.equal(channelSpy.callCount, 2, "channel should be called twice");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
|
||||
evt = channelSpy.args[1][0];
|
||||
Assert.equal(evt.name, "test1", "event name should be set");
|
||||
Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status test1");
|
||||
|
||||
|
||||
// change the ikey to null again, inactive
|
||||
core.config.instrumentationKey = undefined;
|
||||
this.clock.tick(1);
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.INACTIVE, "default should be inactive status test1");
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url resolved promise",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey");
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url rejected promise",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey");
|
||||
let urlPromise = createAsyncRejectedPromise(new Error("endpoint error"));
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed");
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey rejected promise, endpoint url rejected promise",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let ikeyPromise = createAsyncRejectedPromise(new Error("ikey error"));
|
||||
let urlPromise = createAsyncRejectedPromise(new Error("endpoint error"));
|
||||
|
||||
this.ctx.ikeyPromise = ikeyPromise;
|
||||
this.ctx.urlPromise = urlPromise;
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
let ikeyPromise = this.ctx.ikeyPromise;
|
||||
let urlPromise = this.ctx.urlPromise;
|
||||
|
||||
if (activeStatus === ActiveStatus.INACTIVE) {
|
||||
Assert.deepEqual(core.config.instrumentationKey, ikeyPromise, "channel testIkey should not be changed");
|
||||
Assert.deepEqual(core.config.endpointUrl, urlPromise, "channel endpoint should not be changed");
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey promise chain, endpoint url promise chain",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let csPromise = createAsyncResolvedPromise("instrumentationKey=testIkey;endpoint=testUrl");
|
||||
let ikeyPromise = createAsyncPromise((resolve, reject) => {
|
||||
doAwaitResponse(csPromise, (res) => {
|
||||
if (!res.rejected) {
|
||||
resolve("testIkey");
|
||||
return;
|
||||
}
|
||||
reject(new Error("ikey error"));
|
||||
})
|
||||
});
|
||||
let urlPromise = createAsyncPromise((resolve, reject) => {
|
||||
doAwaitResponse(csPromise, (res) => {
|
||||
if (!res.rejected) {
|
||||
resolve("testUrl");
|
||||
return;
|
||||
}
|
||||
reject(new Error("url error"));
|
||||
})
|
||||
});
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey mutiple layer promise chain, endpoint url mutiple layer promise chain",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let csPromise = createAsyncResolvedPromise("instrumentationKey=testIkey;endpoint=testUrl");
|
||||
let ikeyPromise = createAsyncPromise((resolve, reject) => {
|
||||
doAwaitResponse(csPromise, (res) => {
|
||||
if (!res.rejected) {
|
||||
resolve(createAsyncResolvedPromise("testIkey"));
|
||||
return;
|
||||
}
|
||||
reject(createAsyncRejectedPromise(new Error("ikey error")));
|
||||
return;
|
||||
})
|
||||
});
|
||||
let urlPromise = createAsyncPromise((resolve, reject) => {
|
||||
doAwaitResponse(csPromise, (res) => {
|
||||
if (!res.rejected) {
|
||||
resolve(createAsyncResolvedPromise("testUrl"));
|
||||
return;
|
||||
}
|
||||
reject(createAsyncRejectedPromise(new Error("url error")));
|
||||
return;
|
||||
})
|
||||
});
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey string, endpoint url string, dynamic changed with resolved promises",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: "testIkey",
|
||||
endpointUrl: "testUrl",
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
Assert.ok(channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status");
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status");
|
||||
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey1");
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl1");
|
||||
core.config.instrumentationKey = ikeyPromise;
|
||||
core.config.endpointUrl = urlPromise;
|
||||
this.clock.tick(1);
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey1", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl1", "channel endpoint should be changed");
|
||||
core.track({name: "test2"});
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
|
||||
let evt = channelSpy.args[1][0];
|
||||
Assert.equal(evt.name, "test2", "event name should be set test2");
|
||||
Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url resolved promise, dynamic change with promise",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey");
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy;
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "active status should be set to active");
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
|
||||
Assert.ok(channelSpy.calledOnce, "channel should be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
let evt = channelSpy.args[0][0];
|
||||
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
|
||||
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey1");
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl1");
|
||||
core.config.instrumentationKey = ikeyPromise;
|
||||
core.config.endpointUrl = urlPromise;
|
||||
this.ctx.secondCall = true;
|
||||
//Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending test1");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise first response" + new Date().toISOString(), 60, 1000) as any).concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy;
|
||||
|
||||
if (this.ctx.secondCall && activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "active status should be set to active test1");
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey1", "channel testIkey should not be changed test1");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl1", "channel endpoint should be changed test1");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
core.track({name: "test1"});
|
||||
let evt = channelSpy.args[1][0];
|
||||
Assert.equal(evt.name, "test1", "event name should be set test2");
|
||||
Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1");
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise second response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey promise, endpoint url promise, dynamic changed with strings",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
|
||||
let ikeyPromise = createAsyncResolvedPromise("testIkey");
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl");
|
||||
|
||||
let unresolveIkeyPromise = createAsyncPromise((resolve, reject) => {
|
||||
//do nothing,
|
||||
}) // init with it, it should be pending
|
||||
|
||||
let newIkeyPromise = createAsyncPromise((resolve, reject) => {
|
||||
resolve("ikey")
|
||||
}) // init with it, pending, no changes or string
|
||||
// resolve first one, active
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status");
|
||||
|
||||
// status is pending, following changes should not be applied
|
||||
core.config.instrumentationKey = "testIkey1";
|
||||
core.config.endpointUrl = "testUrl1";
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
|
||||
let evt1 = channelSpy.args[0][0];
|
||||
Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1");
|
||||
this.clock.tick(1);
|
||||
core.track({name: "test2"});
|
||||
let evt2 = channelSpy.args[1][0];
|
||||
Assert.equal(evt2.name, "test2", "event name should be set test2");
|
||||
Assert.equal(evt2.iKey, "testIkey", "event ikey should be set test1");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey promise, endpoint url promise, dynamic changed with strings while waiting promises",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
|
||||
let urlPromise = createAsyncResolvedPromise("testUrl");
|
||||
|
||||
let resolveFunc;
|
||||
|
||||
let ikeyPromise = createAsyncPromise((resolve, reject) => {
|
||||
resolveFunc = resolve;
|
||||
//do nothing, mock unresolve
|
||||
});
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 80000
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status");
|
||||
|
||||
// status is pending, following changes should not be applied
|
||||
core.config.instrumentationKey = "testIkey1";
|
||||
this.clock.tick(1);
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status");
|
||||
|
||||
resolveFunc("testIkey");
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.ACTIVE) {
|
||||
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
|
||||
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
|
||||
let evt1 = channelSpy.args[0][0];
|
||||
Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1");
|
||||
this.clock.tick(1);
|
||||
core.track({name: "test2"});
|
||||
let evt2 = channelSpy.args[1][0];
|
||||
Assert.equal(evt2.name, "test2", "event name should be set test2");
|
||||
Assert.equal(evt2.iKey, "testIkey", "event ikey should be set test1");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey and endpoint timeout promises",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let trackPlugin = new TrackPlugin();
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let ikeyPromise = createTimeoutPromise(60, true,"testIkey");
|
||||
let urlPromise = createTimeoutPromise(60, true, "testUrl");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 1
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[trackPlugin, channelPlugin]);
|
||||
|
||||
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 1, "Event should be queued");
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy;
|
||||
|
||||
if (activeStatus === ActiveStatus.INACTIVE) {
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
this.testCaseAsync({
|
||||
name: "ApplicationInsightsCore Init: init with ikey timeout promises and endpoint promises",
|
||||
stepDelay: 100,
|
||||
useFakeTimers: true,
|
||||
steps: [() => {
|
||||
let channelPlugin = new ChannelPlugin();
|
||||
channelPlugin.priority = 1001;
|
||||
let core = new AppInsightsCore();
|
||||
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
|
||||
|
||||
let ikeyPromise = createTimeoutPromise(20, true, "testIkey1");
|
||||
let urlPromise = createTimeoutPromise(1, true, "testUrl1");
|
||||
|
||||
let config = {
|
||||
instrumentationKey: ikeyPromise,
|
||||
endpointUrl: urlPromise,
|
||||
initTimeOut: 6
|
||||
} as IConfiguration;
|
||||
core.initialize(
|
||||
config,
|
||||
[channelPlugin]);
|
||||
this.ctx.core = core;
|
||||
this.ctx.channelSpy = channelSpy;
|
||||
|
||||
let activeStatus = core.activeStatus();
|
||||
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
|
||||
Assert.ok(!channelSpy.calledOnce, "channel should not be called");
|
||||
core.track({name: "testEvent"});
|
||||
|
||||
|
||||
}].concat(PollingAssert.createPollingAssert(() => {
|
||||
let core = this.ctx.core;
|
||||
let activeStatus = core.activeStatus();
|
||||
let channelSpy = this.ctx.channelSpy
|
||||
|
||||
if (activeStatus === ActiveStatus.INACTIVE) {
|
||||
Assert.ok(core.eventCnt() == 0, "Event should be released");
|
||||
Assert.ok(!channelSpy.called, "channel should not be called");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
this.testCase({
|
||||
name: 'newId tests length',
|
||||
|
@ -1186,9 +2000,11 @@ class ChannelPlugin implements IChannelControls {
|
|||
}
|
||||
|
||||
public initialize = (config: IConfiguration) => {
|
||||
|
||||
}
|
||||
|
||||
public _processTelemetry(env: ITelemetryItem) {
|
||||
console.log(JSON.stringify(env))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1295,7 +2111,6 @@ class TestOfflineChannelPlugin implements IChannelControls {
|
|||
this.events.push(env);
|
||||
|
||||
// Just calling processTelemetry as this is the original design of the Plugins (as opposed to the newer processNext())
|
||||
this._nextPlugin?.processTelemetry(env);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { createEnumStyle } from "./EnumHelperFuncs";
|
||||
|
||||
export const enum eActiveStatus {
|
||||
|
||||
// None
|
||||
NONE = 0,
|
||||
/**
|
||||
* inactive status means there might be rejected ikey/endpoint promises or ikey/endpoint resolved is not valid
|
||||
*/
|
||||
INACTIVE = 1,
|
||||
|
||||
/**
|
||||
* active mean ikey/endpoint promises is resolved and initializing with ikey/endpoint is successful
|
||||
*/
|
||||
ACTIVE = 2,
|
||||
|
||||
/**
|
||||
* Waiting for promises to be resolved
|
||||
* NOTE: if status is set to be pending, incoming changes will be dropped until pending status is removed
|
||||
*/
|
||||
PENDING = 3,
|
||||
}
|
||||
|
||||
export const ActiveStatus = createEnumStyle<typeof eActiveStatus>({
|
||||
NONE: eActiveStatus.NONE,
|
||||
PENDING: eActiveStatus.PENDING,
|
||||
INACTIVE: eActiveStatus.INACTIVE,
|
||||
ACTIVE: eActiveStatus.ACTIVE
|
||||
});
|
||||
export type ActiveStatus = number | eActiveStatus;
|
|
@ -126,7 +126,8 @@ export const enum _eInternalMessageId {
|
|||
DynamicConfigException = 108,
|
||||
DefaultThrottleMsgKey = 109,
|
||||
CdnDeprecation = 110,
|
||||
SdkLdrUpdate = 111
|
||||
SdkLdrUpdate = 111,
|
||||
InitPromiseException = 112
|
||||
}
|
||||
|
||||
export type _InternalMessageId = number | _eInternalMessageId;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import { IPromise } from "@nevware21/ts-async";
|
||||
import { ITimerHandler } from "@nevware21/ts-utils";
|
||||
import { WatcherFunction } from "../Config/IDynamicWatcher";
|
||||
import { eActiveStatus } from "../JavaScriptSDK.Enums/InitActiveStatusEnum";
|
||||
import { SendRequestReason } from "../JavaScriptSDK.Enums/SendRequestReason";
|
||||
import { UnloadHandler } from "../JavaScriptSDK/UnloadHandlerContainer";
|
||||
import { IChannelControls } from "./IChannelControls";
|
||||
|
@ -225,4 +226,22 @@ export interface IAppInsightsCore<CfgType extends IConfiguration = IConfiguratio
|
|||
* Function used to identify the get w parameter used to identify status bit to some channels
|
||||
*/
|
||||
getWParam: () => number;
|
||||
|
||||
/**
|
||||
* Watches and tracks status of initialization process
|
||||
* @returns ActiveStatus
|
||||
* @since 3.3.0
|
||||
* If returned status is active, it means initialization process is completed.
|
||||
* If returned status is pending, it means the initialization process is waiting for promieses to be resolved.
|
||||
* If returned status is inactive, it means ikey is invalid or can 't get ikey or enpoint url from promsises.
|
||||
*/
|
||||
activeStatus?: () => eActiveStatus | number;
|
||||
|
||||
/**
|
||||
* Set Active Status to pending, which will block the incoming changes until internal promises are resolved
|
||||
* @internal Internal use
|
||||
* @since 3.3.0
|
||||
*/
|
||||
_setPendingStatus?: () => void;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
import { IPromise } from "@nevware21/ts-async";
|
||||
import { IAppInsightsCore } from "./IAppInsightsCore";
|
||||
import { IChannelControls } from "./IChannelControls";
|
||||
import { ICookieMgrConfig } from "./ICookieMgr";
|
||||
|
@ -17,12 +18,12 @@ export interface IConfiguration {
|
|||
/**
|
||||
* Instrumentation key of resource. Either this or connectionString must be specified.
|
||||
*/
|
||||
instrumentationKey?: string;
|
||||
instrumentationKey?: string| IPromise<string>;
|
||||
|
||||
/**
|
||||
* Connection string of resource. Either this or instrumentationKey must be specified.
|
||||
*/
|
||||
connectionString?: string;
|
||||
connectionString?: string | IPromise<string> ;
|
||||
|
||||
/**
|
||||
* Set the timer interval (in ms) for internal logging queue, this is the
|
||||
|
@ -72,7 +73,7 @@ export interface IConfiguration {
|
|||
/**
|
||||
* Endpoint where telemetry data is sent
|
||||
*/
|
||||
endpointUrl?: string;
|
||||
endpointUrl?: string | IPromise<string>;
|
||||
|
||||
/**
|
||||
* Extension configs loaded in SDK
|
||||
|
@ -190,4 +191,21 @@ export interface IConfiguration {
|
|||
* @defaultValue undefined
|
||||
*/
|
||||
featureOptIn?: IFeatureOptIn;
|
||||
|
||||
/**
|
||||
* If your connection string, instrumentation key and endpoint url are promises,
|
||||
* this config is to manually set timeout for those promises.
|
||||
* Default: 50000ms
|
||||
* @since 3.3.0
|
||||
*/
|
||||
initTimeOut?: number;
|
||||
|
||||
/**
|
||||
* If your connection string, instrumentation key and endpoint url are promises,
|
||||
* this config is to manually set in memory proxy track calls count limit before promises finished.
|
||||
* Default: 100
|
||||
* @since 3.3.0
|
||||
*/
|
||||
initInMemoMaxSize?: number;
|
||||
|
||||
}
|
||||
|
|
|
@ -3,16 +3,17 @@
|
|||
"use strict";
|
||||
|
||||
import dynamicProto from "@microsoft/dynamicproto-js";
|
||||
import { IPromise, createPromise } from "@nevware21/ts-async";
|
||||
import { IPromise, createAllSettledPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async";
|
||||
import {
|
||||
ITimerHandler, arrAppend, arrForEach, arrIndexOf, createTimeout, deepExtend, hasDocument, isFunction, isNullOrUndefined, isPlainObject,
|
||||
objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError
|
||||
isPromiseLike, objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError
|
||||
} from "@nevware21/ts-utils";
|
||||
import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig";
|
||||
import { IConfigDefaults } from "../Config/IConfigDefaults";
|
||||
import { IDynamicConfigHandler, _IInternalDynamicConfigHandler } from "../Config/IDynamicConfigHandler";
|
||||
import { IWatchDetails, WatcherFunction } from "../Config/IDynamicWatcher";
|
||||
import { eEventsDiscardedReason } from "../JavaScriptSDK.Enums/EventsDiscardedReason";
|
||||
import { ActiveStatus, eActiveStatus } from "../JavaScriptSDK.Enums/InitActiveStatusEnum";
|
||||
import { _eInternalMessageId, eLoggingSeverity } from "../JavaScriptSDK.Enums/LoggingEnums";
|
||||
import { SendRequestReason } from "../JavaScriptSDK.Enums/SendRequestReason";
|
||||
import { TelemetryUnloadReason } from "../JavaScriptSDK.Enums/TelemetryUnloadReason";
|
||||
|
@ -41,7 +42,7 @@ import { createCookieMgr } from "./CookieMgr";
|
|||
import { createUniqueNamespace } from "./DataCacheHelper";
|
||||
import { getDebugListener } from "./DbgExtensionUtils";
|
||||
import { DiagnosticLogger, _InternalLogMessage, _throwInternal, _warnToConsole } from "./DiagnosticLogger";
|
||||
import { getSetValue, proxyFunctionAs, proxyFunctions, toISOString } from "./HelperFuncs";
|
||||
import { getSetValue, isNotNullOrUndefined, proxyFunctionAs, proxyFunctions, toISOString } from "./HelperFuncs";
|
||||
import {
|
||||
STR_CHANNELS, STR_CREATE_PERF_MGR, STR_DISABLED, STR_EMPTY, STR_EXTENSIONS, STR_EXTENSION_CONFIG, UNDEFINED_VALUE
|
||||
} from "./InternalConstants";
|
||||
|
@ -59,6 +60,8 @@ const strValidationError = "Plugins must provide initialize method";
|
|||
const strNotificationManager = "_notificationManager";
|
||||
const strSdkUnloadingError = "SDK is still unloading...";
|
||||
const strSdkNotInitialized = "SDK is not initialized";
|
||||
const maxInitQueueSize = 100;
|
||||
const maxInitTimeout = 50000;
|
||||
// const strPluginUnloadFailed = "Failed to unload plugin";
|
||||
|
||||
/**
|
||||
|
@ -292,6 +295,11 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
let _extensions: IPlugin[];
|
||||
let _pluginVersionStringArr: string[];
|
||||
let _pluginVersionString: string;
|
||||
let _activeStatus: eActiveStatus; // to indicate if ikey or endpoint url promised is resolved or not
|
||||
let _endpoint: string;
|
||||
let _initInMemoMaxSize: number; // max event count limit during wait for init promises to be resolved
|
||||
let _isStatusSet: boolean; // track if active status is set in case of init timeout and init promises setting the status twice
|
||||
let _initTimer: ITimerHandler;
|
||||
|
||||
/**
|
||||
* Internal log poller
|
||||
|
@ -307,11 +315,20 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
|
||||
// Special internal method to allow the unit tests and DebugPlugin to hook embedded objects
|
||||
_self["_getDbgPlgTargets"] = () => {
|
||||
return [_extensions];
|
||||
return [_extensions, _eventQueue];
|
||||
};
|
||||
|
||||
_self.isInitialized = () => _isInitialized;
|
||||
|
||||
// since version 3.3.0
|
||||
_self.activeStatus = () => _activeStatus;
|
||||
|
||||
// since version 3.3.0
|
||||
// internal
|
||||
_self._setPendingStatus = () => {
|
||||
_activeStatus = eActiveStatus.PENDING;
|
||||
};
|
||||
|
||||
// Creating the self.initialize = ()
|
||||
_self.initialize = (config: CfgType, extensions: IPlugin[], logger?: IDiagnosticLogger, notificationManager?: INotificationManager): void => {
|
||||
if (_isUnloading) {
|
||||
|
@ -330,8 +347,122 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
|
||||
// This will be "re-run" if the referenced config properties are changed
|
||||
_addUnloadHook(_configHandler.watch((details) => {
|
||||
_instrumentationKey = details.cfg.instrumentationKey;
|
||||
let rootCfg = details.cfg;
|
||||
|
||||
let isPending = _activeStatus === eActiveStatus.PENDING;
|
||||
|
||||
if (isPending){
|
||||
// means waiting for previous promises to be resolved, won't apply new changes
|
||||
return;
|
||||
}
|
||||
|
||||
_initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize;
|
||||
// app Insights core only handle ikey and endpointurl, aisku will handle cs
|
||||
let ikey = rootCfg.instrumentationKey;
|
||||
let endpointUrl = rootCfg.endpointUrl; // do not need to validate endpoint url, if it is null, default one will be set by sender
|
||||
|
||||
if (isNullOrUndefined(ikey)) {
|
||||
_instrumentationKey = null;
|
||||
// if new ikey is null, set status to be inactive, all new events will be saved in memory or dropped
|
||||
_activeStatus = ActiveStatus.INACTIVE;
|
||||
let msg = "Please provide instrumentation key";
|
||||
|
||||
if (!_isInitialized) {
|
||||
// only throw error during initialization
|
||||
throwError(msg);
|
||||
} else {
|
||||
_throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InvalidInstrumentationKey, msg);
|
||||
_releaseQueues();
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
let promises: IPromise<string>[] = [];
|
||||
if (isPromiseLike(ikey)) {
|
||||
promises.push(ikey);
|
||||
_instrumentationKey = null; // reset current local ikey variable (otherwise it will always be the previous ikeys if timeout is called before promise cb)
|
||||
} else {
|
||||
// string
|
||||
_instrumentationKey = ikey;
|
||||
}
|
||||
|
||||
if (isPromiseLike(endpointUrl)) {
|
||||
promises.push(endpointUrl);
|
||||
_endpoint = null; // reset current local endpoint variable (otherwise it will always be the previous urls if timeout is called before promise cb)
|
||||
} else {
|
||||
// string or null
|
||||
_endpoint = endpointUrl;
|
||||
}
|
||||
|
||||
// at least have one promise
|
||||
if (promises.length) {
|
||||
// reset to false for new dynamic changes
|
||||
_isStatusSet = false;
|
||||
_activeStatus = eActiveStatus.PENDING;
|
||||
let initTimeout = isNotNullOrUndefined(rootCfg.initTimeOut)? rootCfg.initTimeOut : maxInitTimeout; // rootCfg.initTimeOut could be 0
|
||||
let allPromises = createAllSettledPromise<string>(promises);
|
||||
_initTimer = scheduleTimeout(() => {
|
||||
// set _isStatusSet to true
|
||||
// set active status
|
||||
// release queues
|
||||
_initTimer = null;
|
||||
if (!_isStatusSet) {
|
||||
_setStatus();
|
||||
}
|
||||
|
||||
}, initTimeout);
|
||||
|
||||
doAwaitResponse(allPromises, (response) => {
|
||||
try {
|
||||
if (_isStatusSet) {
|
||||
// promises take too long to resolve, ignore them
|
||||
// active status should be set by timeout already
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.rejected) {
|
||||
let values = response.value;
|
||||
if (values && values.length) {
|
||||
// ikey
|
||||
let ikeyRes = values[0];
|
||||
_instrumentationKey = ikeyRes && ikeyRes.value;
|
||||
|
||||
// endpoint
|
||||
if (values.length > 1) {
|
||||
let endpointRes = values[1];
|
||||
_endpoint = endpointRes && endpointRes.value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (_instrumentationKey) {
|
||||
// if ikey is null, no need to trigger extra dynamic changes for extensions
|
||||
config.instrumentationKey = _instrumentationKey; // set config.instrumentationKey for extensions to consume
|
||||
config.endpointUrl = _endpoint; // set config.endpointUrl for extensions to consume
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// set _isStatusSet to true
|
||||
// set active status
|
||||
// release queues
|
||||
_setStatus();
|
||||
|
||||
} catch (e) {
|
||||
if (!_isStatusSet){
|
||||
_setStatus();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
// means no promises
|
||||
_setStatus();
|
||||
|
||||
}
|
||||
|
||||
//_instrumentationKey = details.cfg.instrumentationKey;
|
||||
// Mark the extensionConfig and all first level keys as referenced
|
||||
// This is so that calls to getExtCfg() will always return the same object
|
||||
// Even when a user may "re-assign" the plugin properties (or it's unloaded/reloaded)
|
||||
|
@ -339,10 +470,8 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
objForEachKey(extCfg, (key) => {
|
||||
details.ref(extCfg, key);
|
||||
});
|
||||
|
||||
if (isNullOrUndefined(_instrumentationKey)) {
|
||||
throwError("Please provide instrumentation key");
|
||||
}
|
||||
|
||||
|
||||
}));
|
||||
|
||||
_notificationManager = notificationManager;
|
||||
|
@ -377,9 +506,10 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
_cfgListeners = null;
|
||||
|
||||
_isInitialized = true;
|
||||
_self.releaseQueue();
|
||||
|
||||
_self.pollInternalLogs();
|
||||
if (_activeStatus === ActiveStatus.ACTIVE) {
|
||||
_releaseQueues();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
_self.getChannels = (): IChannelControls[] => {
|
||||
|
@ -416,12 +546,16 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
// Common Schema 4.0
|
||||
telemetryItem.ver = telemetryItem.ver || "4.0";
|
||||
|
||||
if (!_isUnloading && _self.isInitialized()) {
|
||||
if (!_isUnloading && _self.isInitialized() && _activeStatus === ActiveStatus.ACTIVE) {
|
||||
// Process the telemetry plugin chain
|
||||
_createTelCtx().processNext(telemetryItem);
|
||||
} else {
|
||||
} else if (_activeStatus !== ActiveStatus.INACTIVE){
|
||||
// Queue events until all extensions are initialized
|
||||
_eventQueue.push(telemetryItem);
|
||||
if (_eventQueue.length <= _initInMemoMaxSize) {
|
||||
// set limit, if full, stop adding new events
|
||||
_eventQueue.push(telemetryItem);
|
||||
}
|
||||
|
||||
}
|
||||
}, () => ({ item: telemetryItem }), !((telemetryItem as any).sync));
|
||||
};
|
||||
|
@ -490,10 +624,18 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
if (_isInitialized && _eventQueue.length > 0) {
|
||||
let eventQueue = _eventQueue;
|
||||
_eventQueue = [];
|
||||
if (_activeStatus === eActiveStatus.ACTIVE) {
|
||||
arrForEach(eventQueue, (event: ITelemetryItem) => {
|
||||
event.iKey = event.iKey || _instrumentationKey;
|
||||
_createTelCtx().processNext(event);
|
||||
});
|
||||
|
||||
arrForEach(eventQueue, (event: ITelemetryItem) => {
|
||||
_createTelCtx().processNext(event);
|
||||
});
|
||||
} else {
|
||||
// new one for msg ikey
|
||||
_throwInternal(_logger, eLoggingSeverity.WARNING, _eInternalMessageId.FailedToSendQueuedTelemetry, "core init status is not active");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -505,6 +647,25 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
return _startLogPoller(true);
|
||||
};
|
||||
|
||||
function _setStatus() {
|
||||
_isStatusSet = true;
|
||||
if (isNullOrUndefined(_instrumentationKey)) {
|
||||
_activeStatus = ActiveStatus.INACTIVE;
|
||||
_throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InitPromiseException, "ikey can't be resolved from promises");
|
||||
} else {
|
||||
_activeStatus = ActiveStatus.ACTIVE;
|
||||
}
|
||||
_releaseQueues();
|
||||
|
||||
}
|
||||
|
||||
function _releaseQueues() {
|
||||
if (_isInitialized) {
|
||||
_self.releaseQueue();
|
||||
_self.pollInternalLogs();
|
||||
}
|
||||
}
|
||||
|
||||
function _startLogPoller(alwaysStart?: boolean): ITimerHandler {
|
||||
if ((!_internalLogPoller || !_internalLogPoller.enabled) && !_forceStopInternalLogPoller) {
|
||||
let shouldStart = alwaysStart || (_logger && _logger.queue.length > 0);
|
||||
|
@ -872,6 +1033,11 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
_forceStopInternalLogPoller = false;
|
||||
_internalLogPoller = null;
|
||||
_internalLogPollerListening = false;
|
||||
_activeStatus = eActiveStatus.NONE; // default is None
|
||||
_endpoint = null;
|
||||
_initInMemoMaxSize = null;
|
||||
_isStatusSet = false;
|
||||
_initTimer = null;
|
||||
}
|
||||
|
||||
function _createTelCtx(): IProcessTelemetryContext {
|
||||
|
@ -1403,6 +1569,30 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watches and tracks status of initialization process
|
||||
* @returns ActiveStatus
|
||||
* @since 3.3.0
|
||||
* If returned status is active, it means initialization process is completed.
|
||||
* If returned status is pending, it means the initialization process is waiting for promieses to be resolved.
|
||||
* If returned status is inactive, it means ikey is invalid or can 't get ikey or enpoint url from promsises.
|
||||
*/
|
||||
public activeStatus(): eActiveStatus | number {
|
||||
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Active Status to pending, which will block the incoming changes until internal promises are resolved
|
||||
* @internal Internal use
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public _setPendingStatus(): void {
|
||||
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected releaseQueue() {
|
||||
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ export { eEventsDiscardedReason, EventsDiscardedReason, eBatchDiscardedReason, B
|
|||
export { SendRequestReason, TransportType } from "./JavaScriptSDK.Enums/SendRequestReason";
|
||||
export { TelemetryUpdateReason } from "./JavaScriptSDK.Enums/TelemetryUpdateReason";
|
||||
export { TelemetryUnloadReason } from "./JavaScriptSDK.Enums/TelemetryUnloadReason";
|
||||
export { eActiveStatus, ActiveStatus } from "./JavaScriptSDK.Enums/InitActiveStatusEnum"
|
||||
export { throwAggregationError } from "./JavaScriptSDK/AggregationError";
|
||||
export { AppInsightsCore } from "./JavaScriptSDK/AppInsightsCore";
|
||||
export { BaseTelemetryPlugin } from "./JavaScriptSDK/BaseTelemetryPlugin";
|
||||
|
|
|
@ -56,7 +56,7 @@ declare var cfg:ISnippetConfig;
|
|||
function _parseConnectionString() {
|
||||
let fields:Fields = {};
|
||||
let connectionString = aiConfig.connectionString;
|
||||
if (connectionString) {
|
||||
if (typeof connectionString === "string" && connectionString) {
|
||||
let kvPairs = connectionString.split(";");
|
||||
for (let lp = 0; lp < kvPairs.length; lp++) {
|
||||
let kvParts = kvPairs[lp].split("=");
|
||||
|
|
Загрузка…
Ссылка в новой задаче