[SDK] Add bot-applicationinsights package (#1075)
* Create main structure * Add pom file * Add main classes * Add TelemetryInitializerMiddleware in core folder * Add package-info files * Add MyBotTelemetryClient class in test folder * Add unit tests * Fix issue in WaterfallDialog class Co-authored-by: Federico Bernal <64086728+FedericoBernal@users.noreply.github.com> Co-authored-by: Martin Battaglino <martinbatta32@gmail.com>
This commit is contained in:
Родитель
5c00a74e28
Коммит
c01ecdd56d
|
@ -60,9 +60,22 @@
|
|||
<version>2.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
<artifactId>bot-dialogs</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
<artifactId>bot-builder</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.applicationinsights;
|
||||
|
||||
import com.microsoft.applicationinsights.internal.schemav2.AvailabilityData;
|
||||
import com.microsoft.applicationinsights.internal.util.LocalStringsUtils;
|
||||
import com.microsoft.applicationinsights.internal.util.Sanitizer;
|
||||
import com.microsoft.applicationinsights.telemetry.BaseSampleSourceTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.Duration;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* We took this class from https://github.com/microsoft/ApplicationInsights-Java/issues/1099
|
||||
* as this is not already migrated in ApplicationInsights-Java library.
|
||||
*/
|
||||
public final class AvailabilityTelemetry extends BaseSampleSourceTelemetry<AvailabilityData> {
|
||||
private Double samplingPercentage;
|
||||
private final AvailabilityData data;
|
||||
|
||||
public static final String ENVELOPE_NAME = "Availability";
|
||||
|
||||
public static final String BASE_TYPE = "AvailabilityData";
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the AvailabilityTelemetry class.
|
||||
*/
|
||||
public AvailabilityTelemetry() {
|
||||
this.data = new AvailabilityData();
|
||||
initialize(this.data.getProperties());
|
||||
setId(LocalStringsUtils.generateRandomIntegerId());
|
||||
|
||||
// Setting mandatory fields.
|
||||
setTimestamp(new Date());
|
||||
setSuccess(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the AvailabilityTelemetry class with the given name,
|
||||
* time stamp, duration, HTTP response code and success property values.
|
||||
* @param name A user-friendly name for the request.
|
||||
* @param duration The time of the request.
|
||||
* @param runLocation The duration, in milliseconds, of the request processing.
|
||||
* @param message The HTTP response code.
|
||||
* @param success 'true' if the request was a success, 'false' otherwise.
|
||||
* @param measurements The measurements.
|
||||
* @param properties The corresponding properties.
|
||||
*/
|
||||
public AvailabilityTelemetry(String name, Duration duration, String runLocation, String message,
|
||||
boolean success, ConcurrentMap<String, Double> measurements,
|
||||
ConcurrentMap<String, String> properties) {
|
||||
|
||||
this.data = new AvailabilityData();
|
||||
|
||||
this.data.setProperties(properties);
|
||||
this.data.setMeasurements(measurements);
|
||||
this.data.setMessage(message);
|
||||
|
||||
initialize(this.data.getProperties());
|
||||
|
||||
setId(LocalStringsUtils.generateRandomIntegerId());
|
||||
|
||||
setTimestamp(new Date());
|
||||
|
||||
setName(name);
|
||||
setRunLocation(runLocation);
|
||||
setDuration(duration);
|
||||
setSuccess(success);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the ver value from the data object.
|
||||
* @return The ver value.
|
||||
*/
|
||||
@Override
|
||||
public int getVer() {
|
||||
return getData().getVer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map of application-defined request metrics.
|
||||
* @return The map of metrics
|
||||
*/
|
||||
public ConcurrentMap<String, Double> getMetrics() {
|
||||
return data.getMeasurements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the StartTime. Uses the default behavior and sets the property on the 'data' start time.
|
||||
* @param timestamp The timestamp as Date.
|
||||
*/
|
||||
@Override
|
||||
public void setTimestamp(Date timestamp) {
|
||||
if (timestamp == null) {
|
||||
timestamp = new Date();
|
||||
}
|
||||
|
||||
super.setTimestamp(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or human-readable name of the requested page.
|
||||
* @return A human-readable name.
|
||||
*/
|
||||
public String getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or human-readable name of the requested page.
|
||||
* @param name A human-readable name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
data.setName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or human-readable name of the run location.
|
||||
* @return A human-readable name.
|
||||
*/
|
||||
public String getRunLocation() {
|
||||
return data.getRunLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or human-readable name of the run location.
|
||||
* @param runLocation A human-readable name
|
||||
*/
|
||||
public void setRunLocation(String runLocation) {
|
||||
data.setRunLocation(runLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique identifier of the request.
|
||||
* @return Unique identifier.
|
||||
*/
|
||||
public String getId() {
|
||||
return data.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of the request.
|
||||
* @param id Unique identifier.
|
||||
*/
|
||||
public void setId(String id) {
|
||||
data.setId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether application handled the request successfully.
|
||||
* @return Success indication.
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return data.getSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value indicating whether application handled the request successfully.
|
||||
* @param success Success indication.
|
||||
*/
|
||||
public void setSuccess(boolean success) {
|
||||
data.setSuccess(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of time it took the application to handle the request.
|
||||
* @return Amount of time in milliseconds.
|
||||
*/
|
||||
public Duration getDuration() {
|
||||
return data.getDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount of time it took the application to handle the request.
|
||||
* @param duration Amount of time in captured in a {@link com.microsoft.applicationinsights.telemetry.Duration}.
|
||||
*/
|
||||
public void setDuration(Duration duration) {
|
||||
data.setDuration(duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getSamplingPercentage() {
|
||||
return samplingPercentage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSamplingPercentage(Double samplingPercentage) {
|
||||
this.samplingPercentage = samplingPercentage;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected void additionalSanitize() {
|
||||
data.setName(Sanitizer.sanitizeName(data.getName()));
|
||||
data.setId(Sanitizer.sanitizeName(data.getId()));
|
||||
Sanitizer.sanitizeMeasurements(getMetrics());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AvailabilityData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnvelopName() {
|
||||
return ENVELOPE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseTypeName() {
|
||||
return BASE_TYPE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.applicationinsights;
|
||||
|
||||
import com.microsoft.applicationinsights.TelemetryClient;
|
||||
import com.microsoft.applicationinsights.telemetry.EventTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.ExceptionTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.PageViewTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.SeverityLevel;
|
||||
import com.microsoft.applicationinsights.telemetry.TraceTelemetry;
|
||||
import com.microsoft.bot.builder.BotTelemetryClient;
|
||||
import com.microsoft.bot.builder.Severity;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* A logging client for bot telemetry.
|
||||
*/
|
||||
public class BotTelemetryClientImpl implements BotTelemetryClient {
|
||||
|
||||
private final TelemetryClient telemetryClient;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@link BotTelemetryClient}.
|
||||
*
|
||||
* @param withTelemetryClient The telemetry client to forward bot events to.
|
||||
*/
|
||||
public BotTelemetryClientImpl(TelemetryClient withTelemetryClient) {
|
||||
if (withTelemetryClient == null) {
|
||||
throw new IllegalArgumentException("withTelemetry should be provided");
|
||||
}
|
||||
this.telemetryClient = withTelemetryClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send information about availability of an application.
|
||||
*
|
||||
* @param name Availability test name.
|
||||
* @param timeStamp The time when the availability was captured.
|
||||
* @param duration The time taken for the availability test to run.
|
||||
* @param runLocation Name of the location the availability test was run from.
|
||||
* @param success True if the availability test ran successfully.
|
||||
* @param message Error message on availability test run failure.
|
||||
* @param properties Named string values you can use to classify and search for this availability telemetry.
|
||||
* @param metrics Additional values associated with this availability telemetry.
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:ParameterNumber")
|
||||
@Override
|
||||
public void trackAvailability(String name,
|
||||
OffsetDateTime timeStamp,
|
||||
Duration duration,
|
||||
String runLocation,
|
||||
boolean success,
|
||||
String message,
|
||||
Map<String, String> properties,
|
||||
Map<String, Double> metrics) {
|
||||
com.microsoft.applicationinsights.telemetry.Duration durationTelemetry =
|
||||
new com.microsoft.applicationinsights.telemetry.Duration(duration.toNanos());
|
||||
ConcurrentMap<String, String> concurrentProperties = new ConcurrentHashMap<>(properties);
|
||||
ConcurrentMap<String, Double> concurrentMetrics = new ConcurrentHashMap<>(metrics);
|
||||
AvailabilityTelemetry telemetry = new AvailabilityTelemetry(
|
||||
name,
|
||||
durationTelemetry,
|
||||
runLocation,
|
||||
message,
|
||||
success,
|
||||
concurrentMetrics,
|
||||
concurrentProperties);
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, String> pair: properties.entrySet()) {
|
||||
telemetry.getProperties().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics != null) {
|
||||
for (Map.Entry<String, Double> pair: metrics.entrySet()) {
|
||||
telemetry.getMetrics().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be telemetryClient.trackAvailability(telemetry).
|
||||
* However, it is not present in TelemetryClient class
|
||||
*/
|
||||
telemetryClient.track(telemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send information about an external dependency (outgoing call) in the application.
|
||||
*
|
||||
* @param dependencyTypeName Name of the command initiated with this dependency call. Low cardinality value.
|
||||
* Examples are SQL, Azure table, and HTTP.
|
||||
* @param target External dependency target.
|
||||
* @param dependencyName Name of the command initiated with this dependency call. Low cardinality value.
|
||||
* Examples are stored procedure name and URL path template.
|
||||
* @param data Command initiated by this dependency call. Examples are SQL statement and HTTP
|
||||
* URL's with all query parameters.
|
||||
* @param startTime The time when the dependency was called.
|
||||
* @param duration The time taken by the external dependency to handle the call.
|
||||
* @param resultCode Result code of dependency call execution.
|
||||
* @param success True if the dependency call was handled successfully.
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:ParameterNumber")
|
||||
@Override
|
||||
public void trackDependency(String dependencyTypeName,
|
||||
String target,
|
||||
String dependencyName,
|
||||
String data,
|
||||
OffsetDateTime startTime,
|
||||
Duration duration,
|
||||
String resultCode,
|
||||
boolean success) {
|
||||
com.microsoft.applicationinsights.telemetry.Duration durationTelemetry =
|
||||
new com.microsoft.applicationinsights.telemetry.Duration(duration.toNanos());
|
||||
|
||||
RemoteDependencyTelemetry telemetry =
|
||||
new RemoteDependencyTelemetry(dependencyName, data, durationTelemetry, success);
|
||||
|
||||
telemetry.setType(dependencyTypeName);
|
||||
telemetry.setTarget(target);
|
||||
telemetry.setTimestamp(new Date(startTime.toInstant().toEpochMilli()));
|
||||
telemetry.setResultCode(resultCode);
|
||||
|
||||
telemetryClient.trackDependency(telemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs custom events with extensible named fields.
|
||||
*
|
||||
* @param eventName A name for the event.
|
||||
* @param properties Named string values you can use to search and classify events.
|
||||
* @param metrics Measurements associated with this event.
|
||||
*/
|
||||
@Override
|
||||
public void trackEvent(String eventName, Map<String, String> properties, Map<String, Double> metrics) {
|
||||
EventTelemetry telemetry = new EventTelemetry(eventName);
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, String> pair: properties.entrySet()) {
|
||||
telemetry.getProperties().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics != null) {
|
||||
for (Map.Entry<String, Double> pair: metrics.entrySet()) {
|
||||
telemetry.getMetrics().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
telemetryClient.trackEvent(telemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a system exception.
|
||||
*
|
||||
* @param exception The exception to log.
|
||||
* @param properties Named string values you can use to classify and search for this exception.
|
||||
* @param metrics Additional values associated with this exception
|
||||
*/
|
||||
@Override
|
||||
public void trackException(Exception exception, Map<String, String> properties, Map<String, Double> metrics) {
|
||||
ExceptionTelemetry telemetry = new ExceptionTelemetry(exception);
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, String> pair: properties.entrySet()) {
|
||||
telemetry.getProperties().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics != null) {
|
||||
for (Map.Entry<String, Double> pair: metrics.entrySet()) {
|
||||
telemetry.getMetrics().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
telemetryClient.trackException(telemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a trace message.
|
||||
*
|
||||
* @param message Message to display.
|
||||
* @param severityLevel Trace severity level {@link Severity}.
|
||||
* @param properties Named string values you can use to search and classify events.
|
||||
*/
|
||||
@Override
|
||||
public void trackTrace(String message, Severity severityLevel, Map<String, String> properties) {
|
||||
TraceTelemetry telemetry = new TraceTelemetry(message);
|
||||
telemetry.setSeverityLevel(SeverityLevel.values()[severityLevel.ordinal()]);
|
||||
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, String> pair: properties.entrySet()) {
|
||||
telemetry.getProperties().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
telemetryClient.trackTrace(telemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* We implemented this method calling the tracePageView method from {@link BotTelemetryClientImpl} as the
|
||||
* IBotPageViewTelemetryClient has not been implemented.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void trackDialogView(String dialogName, Map<String, String> properties, Map<String, Double> metrics) {
|
||||
trackPageView(dialogName, properties, metrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a dialog entry / as an Application Insights page view.
|
||||
*
|
||||
* @param dialogName The name of the dialog to log the entry / start for.
|
||||
* @param properties Named string values you can use to search and classify events.
|
||||
* @param metrics Measurements associated with this event.
|
||||
*/
|
||||
public void trackPageView(String dialogName, Map<String, String> properties, Map<String, Double> metrics) {
|
||||
PageViewTelemetry telemetry = new PageViewTelemetry(dialogName);
|
||||
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, String> pair: properties.entrySet()) {
|
||||
telemetry.getProperties().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics != null) {
|
||||
for (Map.Entry<String, Double> pair: metrics.entrySet()) {
|
||||
telemetry.getMetrics().put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
telemetryClient.trackPageView(telemetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the in-memory buffer and any metrics being pre-aggregated.
|
||||
*/
|
||||
@Override
|
||||
public void flush() {
|
||||
telemetryClient.flush();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for
|
||||
// license information.
|
||||
|
||||
package com.microsoft.bot.applicationinsights.core;
|
||||
|
||||
import com.microsoft.applicationinsights.core.dependencies.http.client.protocol.HttpClientContext;
|
||||
import com.microsoft.applicationinsights.core.dependencies.http.protocol.HttpContext;
|
||||
import com.microsoft.bot.builder.BotAssert;
|
||||
import com.microsoft.bot.builder.Middleware;
|
||||
import com.microsoft.bot.builder.NextDelegate;
|
||||
import com.microsoft.bot.builder.TelemetryLoggerMiddleware;
|
||||
import com.microsoft.bot.builder.TurnContext;
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Middleware for storing incoming activity on the HttpContext.
|
||||
*/
|
||||
public class TelemetryInitializerMiddleware implements Middleware {
|
||||
|
||||
private HttpContext httpContext;
|
||||
private final String botActivityKey = "BotBuilderActivity";
|
||||
private final TelemetryLoggerMiddleware telemetryLoggerMiddleware;
|
||||
private final Boolean logActivityTelemetry;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@link TelemetryInitializerMiddleware}.
|
||||
* @param withTelemetryLoggerMiddleware The TelemetryLoggerMiddleware to use.
|
||||
* @param withLogActivityTelemetry Boolean determining if you want to log telemetry activity
|
||||
*/
|
||||
public TelemetryInitializerMiddleware(TelemetryLoggerMiddleware withTelemetryLoggerMiddleware,
|
||||
Boolean withLogActivityTelemetry) {
|
||||
telemetryLoggerMiddleware = withTelemetryLoggerMiddleware;
|
||||
if (withLogActivityTelemetry == null) {
|
||||
withLogActivityTelemetry = true;
|
||||
}
|
||||
logActivityTelemetry = withLogActivityTelemetry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the incoming activity as JSON in the items collection on the HttpContext.
|
||||
* @param context The incoming TurnContext
|
||||
* @param next Delegate to run next on
|
||||
* @return Returns a CompletableFuture with Void value
|
||||
*/
|
||||
public CompletableFuture<Void> onTurn(TurnContext context, NextDelegate next) {
|
||||
BotAssert.contextNotNull(context);
|
||||
|
||||
if (context.getActivity() != null) {
|
||||
Activity activity = context.getActivity();
|
||||
|
||||
if (this.httpContext == null) {
|
||||
this.httpContext = HttpClientContext.create();
|
||||
}
|
||||
|
||||
Object item = httpContext.getAttribute(botActivityKey);
|
||||
|
||||
if (item != null) {
|
||||
httpContext.removeAttribute(botActivityKey);
|
||||
}
|
||||
|
||||
httpContext.setAttribute(botActivityKey, activity);
|
||||
}
|
||||
|
||||
if (logActivityTelemetry) {
|
||||
return telemetryLoggerMiddleware.onTurn(context, next);
|
||||
} else {
|
||||
return next.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for
|
||||
// license information.
|
||||
|
||||
/**
|
||||
* This package contains the classes for bot-applicationinsights.
|
||||
*/
|
||||
package com.microsoft.bot.applicationinsights.core;
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for
|
||||
// license information.
|
||||
|
||||
/**
|
||||
* This package contains the classes for bot-applicationinsights.
|
||||
*/
|
||||
package com.microsoft.bot.applicationinsights;
|
|
@ -0,0 +1,183 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.applicationinsights;
|
||||
|
||||
import com.microsoft.applicationinsights.TelemetryClient;
|
||||
import com.microsoft.applicationinsights.TelemetryConfiguration;
|
||||
import com.microsoft.applicationinsights.channel.TelemetryChannel;
|
||||
import com.microsoft.applicationinsights.telemetry.EventTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.PageViewTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.ExceptionTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.TraceTelemetry;
|
||||
import com.microsoft.applicationinsights.telemetry.SeverityLevel;
|
||||
import com.microsoft.bot.builder.BotTelemetryClient;
|
||||
import com.microsoft.bot.builder.Severity;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BotTelemetryClientTests {
|
||||
|
||||
private BotTelemetryClient botTelemetryClient;
|
||||
private TelemetryChannel mockTelemetryChannel;
|
||||
|
||||
@Before
|
||||
public void initialize() {
|
||||
mockTelemetryChannel = Mockito.mock(TelemetryChannel.class);
|
||||
|
||||
TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration();
|
||||
telemetryConfiguration.setInstrumentationKey("UNITTEST-INSTRUMENTATION-KEY");
|
||||
telemetryConfiguration.setChannel(mockTelemetryChannel);
|
||||
TelemetryClient telemetryClient = new TelemetryClient(telemetryConfiguration);
|
||||
|
||||
botTelemetryClient = new BotTelemetryClientImpl(telemetryClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTelemetryClientThrows() {
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> {
|
||||
new BotTelemetryClientImpl(null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonNullTelemetryClientSucceeds() {
|
||||
TelemetryClient telemetryClient = new TelemetryClient();
|
||||
|
||||
BotTelemetryClient botTelemetryClient = new BotTelemetryClientImpl(telemetryClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideTest() {
|
||||
TelemetryClient telemetryClient = new TelemetryClient();
|
||||
MyBotTelemetryClient botTelemetryClient = new MyBotTelemetryClient(telemetryClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trackAvailabilityTest() {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
Map<String, Double> metrics = new HashMap<>();
|
||||
properties.put("hello", "value");
|
||||
metrics.put("metric", 0.6);
|
||||
|
||||
botTelemetryClient.trackAvailability(
|
||||
"test",
|
||||
OffsetDateTime.now(),
|
||||
Duration.ofNanos(1000),
|
||||
"run location",
|
||||
true,
|
||||
"message",
|
||||
properties,
|
||||
metrics);
|
||||
|
||||
Mockito.verify(mockTelemetryChannel, invocations -> {
|
||||
AvailabilityTelemetry availabilityTelemetry = invocations.getAllInvocations().get(0).getArgument(0);
|
||||
Assert.assertEquals("test", availabilityTelemetry.getName());
|
||||
Assert.assertEquals("message", availabilityTelemetry.getData().getMessage());
|
||||
Assert.assertEquals("value", availabilityTelemetry.getProperties().get("hello"));
|
||||
Assert.assertEquals(0, Double.compare(0.6, availabilityTelemetry.getMetrics().get("metric")));
|
||||
}).send(Mockito.any(AvailabilityTelemetry.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trackEventTest() {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("hello", "value");
|
||||
Map<String, Double> metrics = new HashMap<>();
|
||||
metrics.put("metric", 0.6);
|
||||
|
||||
botTelemetryClient.trackEvent("test", properties, metrics);
|
||||
|
||||
Mockito.verify(mockTelemetryChannel, invocations -> {
|
||||
EventTelemetry eventTelemetry = invocations.getAllInvocations().get(0).getArgument(0);
|
||||
|
||||
Assert.assertEquals("test", eventTelemetry.getName());
|
||||
Assert.assertEquals("value", eventTelemetry.getProperties().get("hello"));
|
||||
Assert.assertEquals(0, Double.compare(0.6, eventTelemetry.getMetrics().get("metric")));
|
||||
}).send(Mockito.any(AvailabilityTelemetry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trackDependencyTest() {
|
||||
botTelemetryClient.trackDependency(
|
||||
"test",
|
||||
"target",
|
||||
"dependencyname",
|
||||
"data",
|
||||
OffsetDateTime.now(),
|
||||
Duration.ofNanos(1000),
|
||||
"result", false);
|
||||
|
||||
Mockito.verify(mockTelemetryChannel, invocations -> {
|
||||
RemoteDependencyTelemetry remoteDependencyTelemetry = invocations.getAllInvocations().get(0).getArgument(0);
|
||||
|
||||
Assert.assertEquals("test", remoteDependencyTelemetry.getType());
|
||||
Assert.assertEquals("target", remoteDependencyTelemetry.getTarget());
|
||||
Assert.assertEquals("dependencyname", remoteDependencyTelemetry.getName());
|
||||
Assert.assertEquals("result", remoteDependencyTelemetry.getResultCode());
|
||||
Assert.assertFalse(remoteDependencyTelemetry.getSuccess());
|
||||
}).send(Mockito.any(AvailabilityTelemetry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trackExceptionTest() {
|
||||
Exception expectedException = new Exception("test-exception");
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("foo", "bar");
|
||||
Map<String, Double> metrics = new HashMap<>();
|
||||
metrics.put("metric", 0.6);
|
||||
|
||||
botTelemetryClient.trackException(expectedException, properties, metrics);
|
||||
|
||||
Mockito.verify(mockTelemetryChannel, invocations -> {
|
||||
ExceptionTelemetry exceptionTelemetry = invocations.getAllInvocations().get(0).getArgument(0);
|
||||
|
||||
Assert.assertEquals(expectedException, exceptionTelemetry.getException());
|
||||
Assert.assertEquals("bar", exceptionTelemetry.getProperties().get("foo"));
|
||||
Assert.assertEquals(0, Double.compare(0.6, exceptionTelemetry.getMetrics().get("metric")));
|
||||
}).send(Mockito.any(ExceptionTelemetry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trackTraceTest() {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("foo", "bar");
|
||||
|
||||
botTelemetryClient.trackTrace("hello", Severity.CRITICAL, properties);
|
||||
|
||||
Mockito.verify(mockTelemetryChannel, invocations -> {
|
||||
TraceTelemetry traceTelemetry = invocations.getAllInvocations().get(0).getArgument(0);
|
||||
|
||||
Assert.assertEquals("hello", traceTelemetry.getMessage());
|
||||
Assert.assertEquals(SeverityLevel.Critical, traceTelemetry.getSeverityLevel());
|
||||
Assert.assertEquals("bar", traceTelemetry.getProperties().get("foo"));
|
||||
}).send(Mockito.any(TraceTelemetry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trackPageViewTest() {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("hello", "value");
|
||||
Map<String, Double> metrics = new HashMap<>();
|
||||
metrics.put("metric", 0.6);
|
||||
|
||||
botTelemetryClient.trackDialogView("test", properties, metrics);
|
||||
|
||||
Mockito.verify(mockTelemetryChannel, invocations -> {
|
||||
PageViewTelemetry pageViewTelemetry = invocations.getAllInvocations().get(0).getArgument(0);
|
||||
|
||||
Assert.assertEquals("test", pageViewTelemetry.getName());
|
||||
Assert.assertEquals("value", pageViewTelemetry.getProperties().get("hello"));
|
||||
Assert.assertEquals(0, Double.compare(0.6, pageViewTelemetry.getMetrics().get("metric")));
|
||||
}).send(Mockito.any(PageViewTelemetry.class));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.applicationinsights;
|
||||
|
||||
import com.microsoft.applicationinsights.TelemetryClient;
|
||||
import com.microsoft.bot.builder.Severity;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
public class MyBotTelemetryClient extends BotTelemetryClientImpl {
|
||||
public MyBotTelemetryClient(TelemetryClient telemetryClient) {
|
||||
super(telemetryClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackDependency(
|
||||
String dependencyTypeName,
|
||||
String target,
|
||||
String dependencyName,
|
||||
String data,
|
||||
OffsetDateTime startTime,
|
||||
Duration duration,
|
||||
String resultCode,
|
||||
boolean success)
|
||||
{
|
||||
super.trackDependency(dependencyName, target, dependencyName, data, startTime, duration, resultCode, success);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackAvailability(
|
||||
String name,
|
||||
OffsetDateTime timeStamp,
|
||||
Duration duration,
|
||||
String runLocation,
|
||||
boolean success,
|
||||
String message,
|
||||
Map<String, String> properties,
|
||||
Map<String, Double> metrics)
|
||||
{
|
||||
super.trackAvailability(name, timeStamp, duration, runLocation, success, message, properties, metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackEvent(
|
||||
String eventName,
|
||||
Map<String, String> properties,
|
||||
Map<String, Double> metrics)
|
||||
{
|
||||
super.trackEvent(eventName, properties, metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackException(
|
||||
Exception exception,
|
||||
Map<String, String> properties,
|
||||
Map<String, Double> metrics)
|
||||
{
|
||||
super.trackException(exception, properties, metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackTrace(
|
||||
String message,
|
||||
Severity severityLevel,
|
||||
Map<String, String> properties)
|
||||
{
|
||||
super.trackTrace(message, severityLevel, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackPageView(
|
||||
String name,
|
||||
Map<String, String> properties,
|
||||
Map<String, Double> metrics)
|
||||
{
|
||||
super.trackPageView(name, properties, metrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush()
|
||||
{
|
||||
super.flush();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.applicationinsights;
|
||||
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import com.microsoft.bot.applicationinsights.core.TelemetryInitializerMiddleware;
|
||||
import com.microsoft.bot.builder.BotTelemetryClient;
|
||||
import com.microsoft.bot.builder.TelemetryLoggerMiddleware;
|
||||
import com.microsoft.bot.builder.adapters.TestAdapter;
|
||||
import com.microsoft.bot.builder.adapters.TestFlow;
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
import com.microsoft.bot.schema.ActivityTypes;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TelemetryInitializerTests {
|
||||
|
||||
@Captor
|
||||
ArgumentCaptor<String> eventNameCaptor;
|
||||
|
||||
@Captor
|
||||
ArgumentCaptor<Map<String, String>> propertiesCaptor;
|
||||
|
||||
@Test
|
||||
public void telemetryInitializerMiddlewareLogActivitiesEnabled() {
|
||||
|
||||
// Arrange
|
||||
BotTelemetryClient mockTelemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
TelemetryLoggerMiddleware telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(mockTelemetryClient, false);
|
||||
|
||||
TestAdapter testAdapter = new TestAdapter()
|
||||
.use(new TelemetryInitializerMiddleware(telemetryLoggerMiddleware, true));
|
||||
|
||||
// Act
|
||||
// Default case logging Send/Receive Activities
|
||||
new TestFlow(testAdapter, turnContext -> {
|
||||
Activity typingActivity = new Activity(ActivityTypes.TYPING);
|
||||
typingActivity.setRelatesTo(turnContext.getActivity().getRelatesTo());
|
||||
|
||||
turnContext.sendActivity(typingActivity).join();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
// Empty error
|
||||
}
|
||||
turnContext.sendActivity(String.format("echo:%s", turnContext.getActivity().getText())).join();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
})
|
||||
.send("foo")
|
||||
.assertReply(activity -> {
|
||||
Assert.assertTrue(activity.isType(ActivityTypes.TYPING));
|
||||
})
|
||||
.assertReply("echo:foo")
|
||||
.send("bar")
|
||||
.assertReply(activity -> {
|
||||
Assert.assertTrue(activity.isType(ActivityTypes.TYPING));
|
||||
})
|
||||
.assertReply("echo:bar")
|
||||
.startTest().join();
|
||||
|
||||
// Verify
|
||||
verify(mockTelemetryClient, times(6)).trackEvent(
|
||||
eventNameCaptor.capture(),
|
||||
propertiesCaptor.capture()
|
||||
);
|
||||
|
||||
List<String> eventNames = eventNameCaptor.getAllValues();
|
||||
Assert.assertEquals(6, eventNames.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telemetryInitializerMiddlewareNotLogActivitiesDisabled() {
|
||||
|
||||
// Arrange
|
||||
BotTelemetryClient mockTelemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
TelemetryLoggerMiddleware telemetryLoggerMiddleware = new TelemetryLoggerMiddleware(mockTelemetryClient, false);
|
||||
|
||||
TestAdapter testAdapter = new TestAdapter()
|
||||
.use(new TelemetryInitializerMiddleware(telemetryLoggerMiddleware, false));
|
||||
|
||||
// Act
|
||||
// Default case logging Send/Receive Activities
|
||||
new TestFlow(testAdapter, (turnContext) -> {
|
||||
Activity typingActivity = new Activity(ActivityTypes.TYPING);
|
||||
typingActivity.setRelatesTo(turnContext.getActivity().getRelatesTo());
|
||||
|
||||
turnContext.sendActivity(typingActivity).join();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
// Empty error
|
||||
}
|
||||
turnContext.sendActivity(String.format("echo:%s", turnContext.getActivity().getText())).join();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
})
|
||||
.send("foo")
|
||||
.assertReply(activity -> {
|
||||
Assert.assertTrue(activity.isType(ActivityTypes.TYPING));
|
||||
})
|
||||
.assertReply("echo:foo")
|
||||
.send("bar")
|
||||
.assertReply(activity -> {
|
||||
Assert.assertTrue(activity.isType(ActivityTypes.TYPING));
|
||||
})
|
||||
.assertReply("echo:bar")
|
||||
.startTest().join();
|
||||
|
||||
// Verify
|
||||
verify(mockTelemetryClient, times(0)).trackEvent(
|
||||
eventNameCaptor.capture(),
|
||||
propertiesCaptor.capture()
|
||||
);
|
||||
List<String> eventNames = eventNameCaptor.getAllValues();
|
||||
Assert.assertEquals(0, eventNames.size());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.applicationinsights;
|
||||
|
||||
import com.microsoft.bot.builder.AutoSaveStateMiddleware;
|
||||
import com.microsoft.bot.builder.BotTelemetryClient;
|
||||
import com.microsoft.bot.builder.StatePropertyAccessor;
|
||||
import com.microsoft.bot.builder.TurnContext;
|
||||
import com.microsoft.bot.builder.adapters.TestAdapter;
|
||||
import com.microsoft.bot.builder.ConversationState;
|
||||
import com.microsoft.bot.builder.MemoryStorage;
|
||||
import com.microsoft.bot.builder.adapters.TestFlow;
|
||||
import com.microsoft.bot.dialogs.Dialog;
|
||||
import com.microsoft.bot.dialogs.DialogContext;
|
||||
import com.microsoft.bot.dialogs.DialogInstance;
|
||||
import com.microsoft.bot.dialogs.DialogReason;
|
||||
import com.microsoft.bot.dialogs.DialogSet;
|
||||
import com.microsoft.bot.dialogs.DialogState;
|
||||
import com.microsoft.bot.dialogs.WaterfallDialog;
|
||||
import com.microsoft.bot.dialogs.WaterfallStep;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class TelemetryWaterfallTests {
|
||||
|
||||
@Test
|
||||
public void waterfall() {
|
||||
ConversationState convoState = new ConversationState(new MemoryStorage());
|
||||
TestAdapter adapter = new TestAdapter(TestAdapter.createConversationReference("Waterfall", "User1", "Bot"))
|
||||
.use(new AutoSaveStateMiddleware(convoState));
|
||||
|
||||
BotTelemetryClient telemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
StatePropertyAccessor<DialogState> dialogState = convoState.createProperty("dialogState");
|
||||
DialogSet dialogs = new DialogSet(dialogState);
|
||||
|
||||
dialogs.add(new WaterfallDialog("test", newWaterfall()));
|
||||
dialogs.setTelemetryClient(telemetryClient);
|
||||
|
||||
new TestFlow(adapter, turnContext -> {
|
||||
DialogContext dc = dialogs.createContext(turnContext).join();
|
||||
dc.continueDialog().join();
|
||||
if (!turnContext.getResponded()) {
|
||||
dc.beginDialog("test", null).join();
|
||||
}
|
||||
return CompletableFuture.completedFuture(null);
|
||||
})
|
||||
.send("hello")
|
||||
.assertReply("step1")
|
||||
.send("hello")
|
||||
.assertReply("step2")
|
||||
.send("hello")
|
||||
.assertReply("step3")
|
||||
.startTest()
|
||||
.join();
|
||||
|
||||
// C#'s trackEvent method of BotTelemetryClient has nullable parameters,
|
||||
// therefore it always calls the same method.
|
||||
// On the other hand, Java's BotTelemetryClient overloads the trackEvent method,
|
||||
// so instead of calling the same method, it calls a method with less parameters.
|
||||
// In this particular test, WaterfallDialog's beginDialog calls the method with only two parameters
|
||||
Mockito.verify(telemetryClient, Mockito.times(4)).trackEvent(
|
||||
Mockito.anyString(),
|
||||
Mockito.anyMap()
|
||||
);
|
||||
System.out.printf("Complete");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waterfallWithCallback() {
|
||||
ConversationState convoState = new ConversationState(new MemoryStorage());
|
||||
TestAdapter adapter = new TestAdapter(TestAdapter.createConversationReference("WaterfallWithCallback", "User1", "Bot"))
|
||||
.use(new AutoSaveStateMiddleware(convoState));
|
||||
|
||||
BotTelemetryClient telemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
StatePropertyAccessor<DialogState> dialogState = convoState.createProperty("dialogState");
|
||||
DialogSet dialogs = new DialogSet(dialogState);
|
||||
WaterfallDialog waterfallDialog = new WaterfallDialog("test", newWaterfall());
|
||||
|
||||
dialogs.add(waterfallDialog);
|
||||
dialogs.setTelemetryClient(telemetryClient);
|
||||
|
||||
new TestFlow(adapter, turnContext -> {
|
||||
DialogContext dc = dialogs.createContext(turnContext).join();
|
||||
dc.continueDialog().join();
|
||||
if (!turnContext.getResponded()) {
|
||||
dc.beginDialog("test", null).join();
|
||||
}
|
||||
return CompletableFuture.completedFuture(null);
|
||||
})
|
||||
.send("hello")
|
||||
.assertReply("step1")
|
||||
.send("hello")
|
||||
.assertReply("step2")
|
||||
.send("hello")
|
||||
.assertReply("step3")
|
||||
.startTest()
|
||||
.join();
|
||||
|
||||
// C#'s trackEvent method of BotTelemetryClient has nullable parameters,
|
||||
// therefore it always calls the same method.
|
||||
// On the other hand, Java's BotTelemetryClient overloads the trackEvent method,
|
||||
// so instead of calling the same method, it calls a method with less parameters.
|
||||
// In this particular test, WaterfallDialog's beginDialog calls the method with only two parameters
|
||||
Mockito.verify(telemetryClient, Mockito.times(4)).trackEvent(
|
||||
Mockito.anyString(),
|
||||
Mockito.anyMap()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waterfallWithActionsNull() {
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> {
|
||||
BotTelemetryClient telemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
WaterfallDialog waterfall = new WaterfallDialog("test", null);
|
||||
waterfall.setTelemetryClient(telemetryClient);
|
||||
waterfall.addStep(null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureEndDialogCalled() {
|
||||
ConversationState convoState = new ConversationState(new MemoryStorage());
|
||||
TestAdapter adapter = new TestAdapter(TestAdapter.createConversationReference("EnsureEndDialogCalled", "User1", "Bot"))
|
||||
.use(new AutoSaveStateMiddleware(convoState));
|
||||
|
||||
StatePropertyAccessor<DialogState> dialogState = convoState.createProperty("dialogState");
|
||||
DialogSet dialogs = new DialogSet(dialogState);
|
||||
HashMap<String, Map<String, String>> saved_properties = new HashMap<>();
|
||||
final int[] counter = {0};
|
||||
|
||||
// Set up the client to save all logged property names and associated properties (in "saved_properties").
|
||||
BotTelemetryClient telemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
Mockito.doAnswer(invocation -> {
|
||||
String eventName = invocation.getArgument(0);
|
||||
Map<String, String> properties = invocation.getArgument(1);
|
||||
|
||||
StringBuilder sb = new StringBuilder(eventName).append("_").append(counter[0]++);
|
||||
saved_properties.put(sb.toString(), properties);
|
||||
|
||||
return null;
|
||||
}).when(telemetryClient).trackEvent(Mockito.anyString(), Mockito.anyMap());
|
||||
|
||||
MyWaterfallDialog waterfallDialog = new MyWaterfallDialog("test", newWaterfall());
|
||||
|
||||
dialogs.add(waterfallDialog);
|
||||
dialogs.setTelemetryClient(telemetryClient);
|
||||
|
||||
new TestFlow(adapter, turnContext -> {
|
||||
DialogContext dc = dialogs.createContext(turnContext).join();
|
||||
dc.continueDialog().join();
|
||||
if (!turnContext.getResponded()) {
|
||||
dc.beginDialog("test", null).join();
|
||||
}
|
||||
return CompletableFuture.completedFuture(null);
|
||||
})
|
||||
.send("hello")
|
||||
.assertReply("step1")
|
||||
.send("hello")
|
||||
.assertReply("step2")
|
||||
.send("hello")
|
||||
.assertReply("step3")
|
||||
.send("hello")
|
||||
.assertReply("step1")
|
||||
.startTest()
|
||||
.join();
|
||||
|
||||
Mockito.verify(telemetryClient, Mockito.times(7)).trackEvent(
|
||||
Mockito.anyString(),
|
||||
Mockito.anyMap()
|
||||
);
|
||||
|
||||
// Verify:
|
||||
// Event name is "WaterfallComplete"
|
||||
// Event occurs on the 4th event logged
|
||||
// Event contains DialogId
|
||||
// Event DialogId is set correctly.
|
||||
Assert.assertTrue(saved_properties.get("WaterfallComplete_4").containsKey("DialogId"));
|
||||
Assert.assertEquals("test", saved_properties.get("WaterfallComplete_4").get("DialogId"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallComplete_4").containsKey("InstanceId"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallStep_1").containsKey("InstanceId"));
|
||||
|
||||
// Verify naming on lambda's is "StepXofY"
|
||||
Assert.assertTrue(saved_properties.get("WaterfallStep_1").containsKey("StepName"));
|
||||
Assert.assertEquals("Step1of3", saved_properties.get("WaterfallStep_1").get("StepName"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallStep_1").containsKey("InstanceId"));
|
||||
Assert.assertTrue(waterfallDialog.getEndDialogCalled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureCancelDialogCalled() {
|
||||
ConversationState convoState = new ConversationState(new MemoryStorage());
|
||||
TestAdapter adapter = new TestAdapter(TestAdapter.createConversationReference("EnsureCancelDialogCalled", "User1", "Bot"))
|
||||
.use(new AutoSaveStateMiddleware(convoState));
|
||||
|
||||
StatePropertyAccessor<DialogState> dialogState = convoState.createProperty("dialogState");
|
||||
DialogSet dialogs = new DialogSet(dialogState);
|
||||
HashMap<String, Map<String, String>> saved_properties = new HashMap<>();
|
||||
final int[] counter = {0};
|
||||
|
||||
// Set up the client to save all logged property names and associated properties (in "saved_properties").
|
||||
BotTelemetryClient telemetryClient = Mockito.mock(BotTelemetryClient.class);
|
||||
Mockito.doAnswer(invocation -> {
|
||||
String eventName = invocation.getArgument(0);
|
||||
Map<String, String> properties = invocation.getArgument(1);
|
||||
|
||||
StringBuilder sb = new StringBuilder(eventName).append("_").append(counter[0]++);
|
||||
saved_properties.put(sb.toString(), properties);
|
||||
|
||||
return null;
|
||||
}).when(telemetryClient).trackEvent(Mockito.anyString(), Mockito.anyMap());
|
||||
|
||||
List<WaterfallStep> steps = new ArrayList<>();
|
||||
steps.add(step -> {
|
||||
step.getContext().sendActivity("step1").join();
|
||||
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
|
||||
});
|
||||
steps.add(step -> {
|
||||
step.getContext().sendActivity("step2").join();
|
||||
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
|
||||
});
|
||||
steps.add(step -> {
|
||||
step.cancelAllDialogs().join();
|
||||
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
|
||||
});
|
||||
|
||||
MyWaterfallDialog waterfallDialog = new MyWaterfallDialog("test", steps);
|
||||
|
||||
dialogs.add(waterfallDialog);
|
||||
dialogs.setTelemetryClient(telemetryClient);
|
||||
|
||||
new TestFlow(adapter, turnContext -> {
|
||||
DialogContext dc = dialogs.createContext(turnContext).join();
|
||||
dc.continueDialog().join();
|
||||
if (!turnContext.getResponded()) {
|
||||
dc.beginDialog("test", null).join();
|
||||
}
|
||||
return CompletableFuture.completedFuture(null);
|
||||
})
|
||||
.send("hello")
|
||||
.assertReply("step1")
|
||||
.send("hello")
|
||||
.assertReply("step2")
|
||||
.send("hello")
|
||||
.assertReply("step1")
|
||||
.startTest()
|
||||
.join();
|
||||
|
||||
Mockito.verify(telemetryClient, Mockito.times(7)).trackEvent(
|
||||
Mockito.anyString(),
|
||||
Mockito.anyMap()
|
||||
);
|
||||
|
||||
// Verify:
|
||||
// Event name is "WaterfallCancel"
|
||||
// Event occurs on the 4th event logged
|
||||
// Event contains DialogId
|
||||
// Event DialogId is set correctly.
|
||||
Assert.assertTrue(saved_properties.get("WaterfallStart_0").containsKey("DialogId"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallStart_0").containsKey("InstanceId"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallCancel_4").containsKey("DialogId"));
|
||||
Assert.assertEquals("test", saved_properties.get("WaterfallCancel_4").get("DialogId"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallCancel_4").containsKey("StepName"));
|
||||
Assert.assertTrue(saved_properties.get("WaterfallCancel_4").containsKey("InstanceId"));
|
||||
|
||||
// Event contains "StepName"
|
||||
// Event naming on lambda's is "StepXofY"
|
||||
Assert.assertEquals("Step3of3", saved_properties.get("WaterfallCancel_4").get("StepName"));
|
||||
Assert.assertTrue(waterfallDialog.getCancelDialogCalled());
|
||||
Assert.assertFalse(waterfallDialog.getEndDialogCalled());
|
||||
}
|
||||
|
||||
private static List<WaterfallStep> newWaterfall() {
|
||||
List<WaterfallStep> waterfall = new ArrayList<>();
|
||||
|
||||
waterfall.add(step -> {
|
||||
step.getContext().sendActivity("step1").join();
|
||||
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
|
||||
});
|
||||
|
||||
waterfall.add(step -> {
|
||||
step.getContext().sendActivity("step2").join();
|
||||
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
|
||||
});
|
||||
|
||||
waterfall.add(step -> {
|
||||
step.getContext().sendActivity("step3").join();
|
||||
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
|
||||
});
|
||||
|
||||
return waterfall;
|
||||
}
|
||||
|
||||
private class MyWaterfallDialog extends WaterfallDialog {
|
||||
private Boolean endDialogCalled = false;
|
||||
private Boolean cancelDialogCalled = false;
|
||||
|
||||
public MyWaterfallDialog(String id, List<WaterfallStep> actions) {
|
||||
super(id, actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> endDialog(TurnContext turnContext, DialogInstance instance, DialogReason reason) {
|
||||
if (reason == DialogReason.END_CALLED) {
|
||||
endDialogCalled = true;
|
||||
} else if (reason == DialogReason.CANCEL_CALLED) {
|
||||
cancelDialogCalled = true;
|
||||
}
|
||||
|
||||
return super.endDialog(turnContext, instance, reason);
|
||||
}
|
||||
|
||||
public Boolean getEndDialogCalled() {
|
||||
return endDialogCalled;
|
||||
}
|
||||
|
||||
public Boolean getCancelDialogCalled() {
|
||||
return cancelDialogCalled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -267,8 +267,8 @@ public class WaterfallDialog extends Dialog {
|
|||
String stepName = steps.get(index).getClass().getSimpleName();
|
||||
|
||||
// Default stepname for lambdas
|
||||
if (StringUtils.isAllBlank(stepName) || stepName.contains("<")) {
|
||||
stepName = String.format("Step%0of%1", index + 1, steps.size());
|
||||
if (StringUtils.isAllBlank(stepName) || stepName.contains("$Lambda$")) {
|
||||
stepName = String.format("Step%dof%d", index + 1, steps.size());
|
||||
}
|
||||
|
||||
return stepName;
|
||||
|
|
Загрузка…
Ссылка в новой задаче