public async Task ScenarioWithInspectionMiddlwareOpenAttach()
        {
            // Arrange

            // any bot state should be returned as trace messages per turn
            var storage           = new MemoryStorage();
            var inspectionState   = new InspectionState(storage);
            var userState         = new UserState(storage);
            var conversationState = new ConversationState(storage);

            // set up the middleware with an http client that will just record the traffic - we are expecting the trace activities here
            var recordingHttpClient  = new RecordingHttpMessageHandler();
            var inspectionMiddleware = new TestInspectionMiddleware(
                inspectionState,
                userState,
                conversationState,
                new HttpClient(recordingHttpClient));

            // Act

            // (1) send the /INSPECT open command from the emulator to the middleware
            var openActivity = MessageFactory.Text("/INSPECT open");

            var inspectionAdapter = new TestAdapter(Channels.Test, true);
            await inspectionAdapter.ProcessActivityAsync(openActivity, async (turnContext, cancellationToken) =>
            {
                await inspectionMiddleware.ProcessCommandAsync(turnContext);
            });

            var inspectionOpenResultActivity = inspectionAdapter.ActiveQueue.Dequeue();

            // (2) send the resulting /INSPECT attach command from the channel to the middleware
            var applicationAdapter = new TestAdapter(Channels.Test, true);

            applicationAdapter.Use(inspectionMiddleware);

            var attachCommand = inspectionOpenResultActivity.Value.ToString();

            await applicationAdapter.ProcessActivityAsync(MessageFactory.Text(attachCommand), async (turnContext, cancellationToken) =>
            {
                // nothing happens - just attach the inspector
                await Task.CompletedTask;
            });

            var attachResponse = applicationAdapter.ActiveQueue.Dequeue();

            // (3) send an application messaage from the channel, it should get the reply and then so should the emulator http endpioint
            await applicationAdapter.ProcessActivityAsync(MessageFactory.Text("hi"), async (turnContext, cancellationToken) =>
            {
                await turnContext.SendActivityAsync(MessageFactory.Text($"echo: {turnContext.Activity.Text}"));

                (await userState.CreateProperty <Scratch>("x").GetAsync(turnContext, () => new Scratch())).Property         = "hello";
                (await conversationState.CreateProperty <Scratch>("y").GetAsync(turnContext, () => new Scratch())).Property = "world";
                await userState.SaveChangesAsync(turnContext);
                await conversationState.SaveChangesAsync(turnContext);
            });

            // Assert
            var outboundActivity = applicationAdapter.ActiveQueue.Dequeue();

            Assert.AreEqual("echo: hi", outboundActivity.Text);
            Assert.AreEqual(3, recordingHttpClient.Requests.Count);

            var inboundTrace = JObject.Parse(recordingHttpClient.Requests[0]);

            Assert.AreEqual("trace", inboundTrace["type"].ToString());
            Assert.AreEqual("ReceivedActivity", inboundTrace["name"].ToString());
            Assert.AreEqual("message", inboundTrace["value"]["type"].ToString());
            Assert.AreEqual("hi", inboundTrace["value"]["text"].ToString());

            var outboundTrace = JObject.Parse(recordingHttpClient.Requests[1]);

            Assert.AreEqual("trace", outboundTrace["type"].ToString());
            Assert.AreEqual("SentActivity", outboundTrace["name"].ToString());
            Assert.AreEqual("message", outboundTrace["value"]["type"].ToString());
            Assert.AreEqual("echo: hi", outboundTrace["value"]["text"].ToString());

            var stateTrace = JObject.Parse(recordingHttpClient.Requests[2]);

            Assert.AreEqual("trace", stateTrace["type"].ToString());
            Assert.AreEqual("BotState", stateTrace["name"].ToString());
            Assert.AreEqual("hello", stateTrace["value"]["userState"]["x"]["Property"].ToString());
            Assert.AreEqual("world", stateTrace["value"]["conversationState"]["y"]["Property"].ToString());
        }
        public async Task ScenarioWithInspectionMiddlwareOpenAttachAndTracePassThrough()
        {
            // Arrange

            // any bot state should be returned as trace messages per turn
            var storage         = new MemoryStorage();
            var inspectionState = new InspectionState(storage);

            // set up the middleware with an http client that will just record the traffic - we are expecting the trace activities here
            var recordingHttpClient  = new RecordingHttpMessageHandler();
            var inspectionMiddleware = new TestInspectionMiddleware(
                inspectionState,
                null,
                null,
                new HttpClient(recordingHttpClient));

            // Act

            // (1) send the /INSPECT open command from the emulator to the middleware
            var openActivity = MessageFactory.Text("/INSPECT open");

            var inspectionAdapter = new TestAdapter(Channels.Test, true);
            await inspectionAdapter.ProcessActivityAsync(openActivity, async (turnContext, cancellationToken) =>
            {
                await inspectionMiddleware.ProcessCommandAsync(turnContext);
            });

            var inspectionOpenResultActivity = inspectionAdapter.ActiveQueue.Dequeue();

            // (2) send the resulting /INSPECT attach command from the channel to the middleware
            var applicationAdapter = new TestAdapter(Channels.Test, true);

            applicationAdapter.Use(inspectionMiddleware);

            var attachCommand = inspectionOpenResultActivity.Value.ToString();

            await applicationAdapter.ProcessActivityAsync(MessageFactory.Text(attachCommand), async (turnContext, cancellationToken) =>
            {
                // nothing happens - just attach the inspector
                await Task.CompletedTask;
            });

            var attachResponse = applicationAdapter.ActiveQueue.Dequeue();

            // (3) send an application messaage from the channel, it should get the reply and then so should the emulator http endpioint
            await applicationAdapter.ProcessActivityAsync(MessageFactory.Text("hi"), async (turnContext, cancellationToken) =>
            {
                var activity = (Activity)Activity.CreateTraceActivity("CustomTrace");
                await turnContext.SendActivityAsync(activity);
            });

            // Assert
            var outboundActivity = applicationAdapter.ActiveQueue.Dequeue();

            Assert.AreEqual("CustomTrace", outboundActivity.Name);
            Assert.AreEqual(2, recordingHttpClient.Requests.Count);

            var inboundTrace = JObject.Parse(recordingHttpClient.Requests[0]);

            Assert.AreEqual("trace", inboundTrace["type"].ToString());
            Assert.AreEqual("ReceivedActivity", inboundTrace["name"].ToString());
            Assert.AreEqual("message", inboundTrace["value"]["type"].ToString());
            Assert.AreEqual("hi", inboundTrace["value"]["text"].ToString());

            var outboundTrace = JObject.Parse(recordingHttpClient.Requests[1]);

            Assert.AreEqual("trace", outboundTrace["type"].ToString());
            Assert.AreEqual("CustomTrace", outboundTrace["name"].ToString());
        }