Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

import * as fs from "node:fs/promises";
import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management";
import {FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, FeatureFlagTest } from "./utils.js";
import { FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, FeatureFlagTest } from "./utils.js";

async function runTest(testName: string) {
const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8"));
const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8"));
const ffProvider = new ConfigurationObjectFeatureFlagProvider(config);
const fm = new FeatureManager(ffProvider);

for (const testcase of testcases){
for (const testcase of testcases) {
validateFeatureEvaluation(testcase, fm);
}
}
Expand Down
8 changes: 4 additions & 4 deletions libraryValidations/JavaScript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"sinon": "^15.2.0",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"@microsoft/feature-management": "2.0.0-preview.3",
"@microsoft/feature-management-applicationinsights-browser": "2.0.0-preview.3",
"@microsoft/feature-management-applicationinsights-node": "2.0.0-preview.3",
"@azure/app-configuration-provider": "2.0.0-preview.1",
"@microsoft/feature-management": "latest",
"@microsoft/feature-management-applicationinsights-browser": "latest",
"@microsoft/feature-management-applicationinsights-node": "latest",
"@azure/app-configuration-provider": "latest",
"@microsoft/applicationinsights-web": "^3.3.4",
"applicationinsights": "^2.9.6"
}
Expand Down
69 changes: 69 additions & 0 deletions libraryValidations/JavaScript/telemetryValidation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as sinon from "sinon";
import * as fs from "node:fs/promises";
import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management";
import { createTelemetryPublisher as createNodeTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-node";
import { createTelemetryPublisher as createBrowserTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser";
import { FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, validateTelemetry, FeatureFlagTest } from "./utils.js";
import { ApplicationInsights } from "@microsoft/applicationinsights-web";
import applicationInsights from "applicationinsights";

// For telemetry validation
let eventNameToValidate;
let eventPropertiesToValidate;

applicationInsights.setup("DUMMY-CONNECTION-STRING").start();
sinon.stub(applicationInsights.defaultClient, "trackEvent").callsFake((event) => {
eventNameToValidate = event.name;
eventPropertiesToValidate = event.properties;
});

const appInsights = new ApplicationInsights({ config: { connectionString: "DUMMY-CONNECTION-STRING" }});
sinon.stub(appInsights, "trackEvent").callsFake((event, customProperties) => {
eventNameToValidate = event.name;
eventPropertiesToValidate = customProperties;
});

async function runTestWithNodePackage(testName: string) {
const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8"));
const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8"));
const ffProvider = new ConfigurationObjectFeatureFlagProvider(config);
const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createNodeTelemetryPublisher(applicationInsights.defaultClient) });

for (const testcase of testcases) {
const featureFlagName = testcase.FeatureFlagName;
const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups };
await fm.getVariant(featureFlagName, context);
validateTelemetry(testcase, undefined, eventNameToValidate, eventPropertiesToValidate);
validateFeatureEvaluation(testcase, fm);
}
}

async function runTestWithBrowserPackage(testName: string) {
const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8"));
const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8"));
const ffProvider = new ConfigurationObjectFeatureFlagProvider(config);
const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createBrowserTelemetryPublisher(appInsights) });

for (const testcase of testcases) {
const featureFlagName = testcase.FeatureFlagName;
const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups };
await fm.getVariant(featureFlagName, context);
validateTelemetry(testcase, undefined, eventNameToValidate, eventPropertiesToValidate);
validateFeatureEvaluation(testcase, fm);
}
}

describe("telemetry with provider and node package", function () {
it("should pass BasicTelemetry test", async () => {
await runTestWithNodePackage("BasicTelemetry");
});
});

describe("telemetry with provider and browser package", function () {
it("should pass BasicTelemetry test", async () => {
await runTestWithBrowserPackage("BasicTelemetry");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { load } from "@azure/app-configuration-provider";
import { FeatureManager, ConfigurationMapFeatureFlagProvider } from "@microsoft/feature-management";
import { createTelemetryPublisher as createNodeTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-node";
import { createTelemetryPublisher as createBrowserTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser";
import {FILE_PATH, TESTS_JSON_KEY, FeatureFlagTest, validateFeatureEvaluation, validateTelemetryWithProvider } from "./utils.js";
import { FILE_PATH, TESTS_JSON_KEY, FeatureFlagTest, validateFeatureEvaluation, validateTelemetry } from "./utils.js";
import { ApplicationInsights } from "@microsoft/applicationinsights-web";
import applicationInsights from "applicationinsights";

Expand Down Expand Up @@ -48,11 +48,12 @@ async function runTestWithProviderAndNodePackage(testName: string) {
const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8"));
const ffProvider = new ConfigurationMapFeatureFlagProvider(config);
const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createNodeTelemetryPublisher(applicationInsights.defaultClient) });
for (const testcase of testcases){
for (const testcase of testcases) {
const featureFlagName = testcase.FeatureFlagName;
const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups };
await fm.getVariant(featureFlagName, context);
validateTelemetryWithProvider(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate);
validateTelemetry(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate);
validateFeatureEvaluation(testcase, fm);
}
}

Expand All @@ -77,11 +78,12 @@ async function runTestWithProviderAndBrowserPackage(testName: string) {
const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8"));
const ffProvider = new ConfigurationMapFeatureFlagProvider(config);
const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createBrowserTelemetryPublisher(appInsights) });
for (const testcase of testcases){
for (const testcase of testcases) {
const featureFlagName = testcase.FeatureFlagName;
const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups };
await fm.getVariant(featureFlagName, context);
validateTelemetryWithProvider(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate);
validateTelemetry(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate);
validateFeatureEvaluation(testcase, fm);
}
}

Expand Down
23 changes: 14 additions & 9 deletions libraryValidations/JavaScript/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ export async function validateFeatureEvaluation(testcase: FeatureFlagTest, featu
}
}

export function validateTelemetryWithProvider(testcase: FeatureFlagTest, connectionString: string, eventNameToValidate: string, eventPropertiesToValidate: any) {
// if (testcase.Telemetry?.EventName) {
// expect(eventNameToValidate).to.eq(testcase.Telemetry.EventName);
// }
export function validateTelemetry(testcase: FeatureFlagTest, connectionString: string | undefined, eventNameToValidate: string, eventPropertiesToValidate: any) {
if (testcase.Telemetry?.EventName) {
expect(eventNameToValidate).to.eq(testcase.Telemetry.EventName);
}

const eventProperties = testcase.Telemetry?.EventProperties;
if (eventProperties) {
Expand Down Expand Up @@ -143,16 +143,21 @@ export function validateTelemetryWithProvider(testcase: FeatureFlagTest, connect
expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId);
}
if (eventProperties.FeatureFlagReference) {
const endpointMatch = connectionString.match(/Endpoint=([^;]+)/);
if (endpointMatch) {
expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference);
if (connectionString === undefined) {
expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(eventProperties.FeatureFlagReference);
}
else {
expect.fail("Connection string does not contain endpoint.");
const endpointMatch = connectionString.match(/Endpoint=([^;]+)/);
if (endpointMatch) {
expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference);
}
else {
expect.fail("Connection string does not contain endpoint.");
}
}
}
if (eventProperties.TargetingId) {
expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId);
}
}
}
}