Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.

Conversation

@Zerryth
Copy link
Contributor

@Zerryth Zerryth commented Apr 7, 2020

Fixes #3665


As, done in JS's TranscriptMiddlewareLogger already, ensure that all cloned activities in logger have Ids, so that when logged into MemoryTranscriptStore, each Item also has an Id.

If an activity doesn't have an id, MemoryTranscriptStore will generate an Id for that activity/Item for the transcript storage, prefixing it with "g_" for "generated", as done in JS.

Context

  • Not all Activities created have Ids assigned to them (Activity spec in botframework-sdk)
  • ContinuationToken within the MemoryTranscriptStore.GetTranscriptActivitiesAsync relies on last Activity.Id of loaded PagedResult
  • Because of the above 2 bullets, if an Activity without an Id is the last item in the PagedResult, we may end up infinitely loading the same PagedResult over and over again.

Testing

In order to test that activities with null ids are assigned ids properly in transcript storage, I had to create a custom TestAdapter, since the one "off the shelf" automatically fills in an activity id, never allowing for null ids to pass through to the TranscriptMiddlewareLogger layer.

  • Would have created an own separate class, however needed to derive from it, since TestFlow is tightly coupled to TestAdapter (it requires an adapter of specifically type TestAdapter instead of an interface)

@Zerryth Zerryth marked this pull request as ready for review April 8, 2020 23:50
activity = JsonConvert.DeserializeObject<Activity>(JsonConvert.SerializeObject(activity, _jsonSettings));
return activity;
var activityWithId = EnsureActivityHasId(activity);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, you can just: return EnsureActivityHasId(activity);

{
var activityWithId = activity;

if (activity == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to have the check for null before creating activityWithId

/// </summary>
public class AllowNullIdTestAdapter : TestAdapter
{
private bool _sendTraceActivity;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readonly?

private readonly object _conversationLock = new object();
private readonly object _activeQueueLock = new object();
private Queue<TaskCompletionSource<IActivity>> _queuedRequests = new Queue<TaskCompletionSource<IActivity>>();
private int _nextId = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readonly?

/// </summary>
/// <returns>The next activity in the queue; or null, if the queue is empty.</returns>
/// <remarks>A <see cref="TestFlow"/> object calls this to get the next response from the bot.</remarks>
public new IActivity GetNextReply()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be private.

/// </summary>
/// <param name="cancellationToken">cancellation Token.</param>
/// <returns>activity when it's available or canceled task if it is canceled.</returns>
public new Task<IActivity> GetNextReplyAsync(CancellationToken cancellationToken = default)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method used?

/// <returns>An appropriate message activity.</returns>
/// <remarks>A <see cref="TestFlow"/> object calls this to get a message activity
/// appropriate to the current conversation.</remarks>
public new Activity MakeActivity(string text = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be private?

Copy link
Contributor

@tomlm tomlm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@tomlm tomlm merged commit d9f8dee into master Apr 15, 2020
@tomlm tomlm deleted the Zerryth/TranscriptActivityIds branch April 15, 2020 16:49
@Zerryth
Copy link
Contributor Author

Zerryth commented Apr 15, 2020

Well then...
@mrivera-ms thank you for reviewing.
All of your points were valid!
Just got merged before I pushed the changes though 😲

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MemoryTranscriptStore.GetTranscriptActivitiesAsync may end up in infinite loop

4 participants