Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Add Dialog / PageView telemetry (#2145) * Update app insights package version * Add PageView logging * move TelemetryView helper to botTelemetryClient.ts * remove telemetry Extensions class, harden helper method, add tests Co-authored-by: Steven Gum <14935595+stevengum@users.noreply.github.com> * move botbuilder-lg and adaptive-expressions out of preview (#2190) * move botbuilder-lg and adaptive-expressions out of preview * correct set-version script in preview packages * restore preview packages to using Version instead of PreviewPackageVersion * Fixed issues with AdaptiveSkillDialog (#2196) and added unit tests Co-authored-by: Gary Pretty <gary@garypretty.co.uk> Co-authored-by: Steven Ickman <stevenic@microsoft.com>
- Loading branch information
1 parent
c3f7e33
commit 77c49e3
Showing
11 changed files
with
275 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
libraries/botbuilder-core/tests/botTelemetryClient.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
const { ok, strictEqual } = require('assert'); | ||
const { Severity, telemetryTrackDialogView } = require('../'); | ||
|
||
describe('BotTelemetryClient', function() { | ||
this.timeout(3000); | ||
|
||
describe('"telemetryTrackDialogView" helper', () => { | ||
it('should call client.trackPageView if it exists', () => { | ||
const testClient = { | ||
trackPageView({ name, properties, metrics }) { | ||
ok(name); | ||
ok(properties); | ||
ok(metrics); | ||
} | ||
}; | ||
const testProps = { description: 'value' }; | ||
const testMetrics = { duration: 1 }; | ||
telemetryTrackDialogView(testClient, 'dialogName', testProps, testMetrics); | ||
}); | ||
|
||
it('should call client.trackTrace if trackPageView is not supported', () => { | ||
const testClient = { | ||
trackTrace({ message, severityLevel }) { | ||
ok(message); | ||
strictEqual(severityLevel, Severity.Information); | ||
} | ||
}; | ||
telemetryTrackDialogView(testClient, 'dialogName'); | ||
}); | ||
|
||
it('should throw TypeError if trackTrace and trackPageView do not exist', () => { | ||
try { | ||
telemetryTrackDialogView(undefined, 'dialogName'); | ||
} catch (err) { | ||
strictEqual(err.message, '"telemetryClient" parameter does not have methods trackPageView() or trackTrace()'); | ||
} | ||
|
||
try { | ||
telemetryTrackDialogView({}, 'dialogName'); | ||
} catch (err) { | ||
strictEqual(err.message, '"telemetryClient" parameter does not have methods trackPageView() or trackTrace()'); | ||
} | ||
|
||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
libraries/botbuilder-dialogs-adaptive/tests/adaptiveSkillDialog.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
const { ok, strictEqual } = require('assert'); | ||
const { createHash } = require('crypto'); | ||
const { stub } = require('sinon'); | ||
const { | ||
ActivityTypes, | ||
ConversationState, | ||
MemoryStorage, | ||
TestAdapter, | ||
SkillConversationIdFactoryBase, | ||
StatusCodes, | ||
TurnContext | ||
} = require('botbuilder-core'); | ||
const { BoolExpression, StringExpression } = require('adaptive-expressions'); | ||
const { DialogManager, DialogTurnStatus } = require('botbuilder-dialogs'); | ||
const { AdaptiveSkillDialog } = require('../') | ||
|
||
|
||
class SimpleConversationIdFactory extends SkillConversationIdFactoryBase { | ||
constructor(config = { disableCreateWithOpts: false, disableGetSkillRef: false }) { | ||
super(); | ||
this._conversationRefs = new Map(); | ||
this.disableCreateWithOpts = config.disableCreateWithOpts; | ||
this.disableGetSkillRef = config.disableGetSkillRef; | ||
} | ||
|
||
async createSkillConversationIdWithOptions(opts) { | ||
if (this.disableCreateWithOpts) { | ||
return super.createSkillConversationIdWithOptions(); | ||
} | ||
} | ||
|
||
async createSkillConversationId(options) { | ||
const key = createHash('md5').update(options.activity.conversation.id + options.activity.serviceUrl).digest('hex'); | ||
|
||
const ref = this._conversationRefs.has(key); | ||
if (!ref) { | ||
this._conversationRefs.set(key, { | ||
conversationReference: TurnContext.getConversationReference(options.activity), | ||
oAuthScope: options.fromBotOAuthScope | ||
}); | ||
} | ||
return key; | ||
} | ||
|
||
async getConversationReference() { | ||
|
||
} | ||
|
||
async getSkillConversationReference(skillConversationId) { | ||
return this._conversationRefs.get(skillConversationId); | ||
} | ||
|
||
deleteConversationReference() { | ||
|
||
} | ||
} | ||
|
||
describe('SkillDialog', function() { | ||
this.timeout(3000); | ||
|
||
let activitySent; // Activity | ||
let fromBotIdSent; // string | ||
let toBotIdSent; // string | ||
let toUriSent; // string (URI) | ||
|
||
// Callback to capture the parameters sent to the skill | ||
const captureAction = (fromBotId, toBotId, toUri, serviceUrl, conversationId, activity) => { | ||
// Capture values sent to the skill so we can assert the right parameters were used. | ||
fromBotIdSent = fromBotId; | ||
toBotIdSent = toBotId; | ||
toUriSent = toUri; | ||
activitySent = activity; | ||
} | ||
|
||
// Create BotFrameworkHttpClient and postActivityStub | ||
const [skillClient, postActivityStub] = createSkillClientAndStub(captureAction); | ||
|
||
// Setup dialog manager | ||
const conversationState = new ConversationState(new MemoryStorage()); | ||
const dm = new DialogManager(); | ||
dm.conversationState = conversationState; | ||
AdaptiveSkillDialog.setSkillHostOptions(dm, skillClient, new SimpleConversationIdFactory()); | ||
|
||
// Setup skill dialog | ||
const dialog = new AdaptiveSkillDialog(); | ||
setSkillDialogOptions(dialog); | ||
dm.rootDialog = dialog; | ||
|
||
it('should call skill via beginDialog()', async () => { | ||
// Send initial activity | ||
const adapter = new TestAdapter(async (context) => { | ||
const { turnResult } = await dm.onTurn(context); | ||
|
||
// Assert results and data sent to the SkillClient for first turn | ||
strictEqual(fromBotIdSent, 'SkillCallerId'); | ||
strictEqual(toBotIdSent, 'SkillId'); | ||
strictEqual(toUriSent, 'http://testskill.contoso.com/api/messages'); | ||
strictEqual(activitySent.text, 'test'); | ||
strictEqual(turnResult.status, DialogTurnStatus.waiting); | ||
ok(postActivityStub.calledOnce); | ||
}); | ||
|
||
await adapter.send('test'); | ||
}); | ||
}); | ||
|
||
function setSkillDialogOptions(dialog) { | ||
dialog.disabled = new BoolExpression(false); | ||
dialog.botId = new StringExpression('SkillCallerId'); | ||
dialog.skillHostEndpoint = new StringExpression('http://test.contoso.com/skill/messages'); | ||
dialog.skillAppId = new StringExpression('SkillId'); | ||
dialog.skillEndpoint = new StringExpression('http://testskill.contoso.com/api/messages'); | ||
} | ||
|
||
/** | ||
* @remarks | ||
* captureAction should match the below signature: | ||
* `(fromBotId: string, toBotId: string, toUrl: string, serviceUrl: string, conversationId: string, activity: Activity) => void` | ||
* @param {Function} captureAction | ||
* @param {StatusCodes} returnStatusCode Defaults to StatusCodes.OK | ||
* @returns [BotFrameworkHttpClient, postActivityStub] | ||
*/ | ||
function createSkillClientAndStub(captureAction, returnStatusCode = StatusCodes.OK) { | ||
// This require should not fail as this method should only be called after verifying that botbuilder is resolvable. | ||
const { BotFrameworkHttpClient } = require('../../botbuilder'); | ||
|
||
if (captureAction && typeof captureAction !== 'function') { | ||
throw new TypeError(`Failed test arrangement - createSkillClientAndStub() received ${typeof captureAction} instead of undefined or a function.`); | ||
} | ||
|
||
// Create ExpectedReplies object for response body | ||
const dummyActivity = { type: ActivityTypes.Message, attachments: [], entities: [] }; | ||
dummyActivity.text = 'dummy activity'; | ||
const activityList = { activities: [dummyActivity] }; | ||
|
||
// Create wrapper for captureAction | ||
function wrapAction(...args) { | ||
captureAction(...args); | ||
return { status: returnStatusCode, body: activityList }; | ||
} | ||
// Create client and stub | ||
const skillClient = new BotFrameworkHttpClient({}); | ||
const postActivityStub = stub(skillClient, 'postActivity'); | ||
|
||
if (captureAction) { | ||
postActivityStub.callsFake(wrapAction); | ||
} else { | ||
postActivityStub.returns({ status: returnStatusCode, body: activityList }); | ||
} | ||
|
||
return [ skillClient, postActivityStub ]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.