public async Task SendAsync_SentryTraceHeaderAlreadySet_NotOverwritten()
        {
            // Arrange
            var hub = Substitute.For <IHub>();

            hub.GetTraceHeader().ReturnsForAnyArgs(
                SentryTraceHeader.Parse("75302ac48a024bde9a3b3734a82e36c8-1000000000000000-0")
                );

            using var innerHandler  = new RecordingHttpMessageHandler(new FakeHttpMessageHandler());
            using var sentryHandler = new SentryHttpMessageHandler(innerHandler, hub);
            using var client        = new HttpClient(sentryHandler);

            client.DefaultRequestHeaders.Add("sentry-trace", "foobar");

            // Act
            await client.GetAsync("https://example.com/");

            using var request = innerHandler.GetRequests().Single();

            // Assert
            request.Headers.Should().Contain(h =>
                                             h.Key == "sentry-trace" &&
                                             string.Concat(h.Value) == "foobar"
                                             );
        }
        public async Task TeamsSendToGeneralChannelAsync()
        {
            // Arrange
            var inboundActivity = new Activity
            {
                Type         = ActivityTypes.Message,
                Conversation = new ConversationAccount {
                    Id = "originalId"
                },
                ChannelData = new TeamsChannelData {
                    Team = new TeamInfo {
                        Id = "team123"
                    }
                },
            };

            var turnContext = new TurnContext(new SimpleAdapter((Activity[] arg) => { }), inboundActivity);

            var baseUri        = new Uri("http://no-where");
            var credentials    = new MicrosoftAppCredentials(string.Empty, string.Empty);
            var messageHandler = new RecordingHttpMessageHandler();

            turnContext.TurnState.Add <IConnectorClient>(new ConnectorClient(baseUri, credentials, new HttpClient(messageHandler)));

            // Act
            var(conversationReference, activityId) = await turnContext.TeamsSendToGeneralChannelAsync(MessageFactory.Text("hi"));

            // Assert
            Assert.AreEqual("ConversationId", conversationReference.Conversation.Id);
            Assert.AreEqual("ActivityId", activityId);
        }
Example #3
0
        public async Task SendEnvelopeAsync_AttachmentTooLarge_DropsItem()
        {
            // Arrange
            using var httpHandler = new RecordingHttpMessageHandler(
                      new FakeHttpMessageHandler()
                      );

            var logger = new InMemoryDiagnosticLogger();

            var httpTransport = new HttpTransport(
                new SentryOptions
            {
                Dsn = DsnSamples.ValidDsnWithSecret,
                MaxAttachmentSize = 1,
                DiagnosticLogger  = logger,
                Debug             = true
            },
                new HttpClient(httpHandler)
                );

            var attachmentNormal = new Attachment(
                AttachmentType.Default,
                new StreamAttachmentContent(new MemoryStream(new byte[] { 1 })),
                "test1.txt",
                null
                );

            var attachmentTooBig = new Attachment(
                AttachmentType.Default,
                new StreamAttachmentContent(new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })),
                "test2.txt",
                null
                );

            using var envelope = Envelope.FromEvent(
                      new SentryEvent(),
                      new[] { attachmentNormal, attachmentTooBig }
                      );

            // Act
            await httpTransport.SendEnvelopeAsync(envelope);

            var lastRequest = httpHandler.GetRequests().Last();
            var actualEnvelopeSerialized = await lastRequest.Content.ReadAsStringAsync();

            // Assert
            // (the envelope should have only one item)

            logger.Entries.Should().Contain(e =>
                                            e.Message == "Attachment '{0}' dropped because it's too large ({1} bytes)." &&
                                            e.Args[0].ToString() == "test2.txt" &&
                                            e.Args[1].ToString() == "5"
                                            );

            actualEnvelopeSerialized.Should().NotContain("test2.txt");
        }
Example #4
0
    public async Task SendEnvelopeAsync_AttachmentFail_DropsItem()
    {
        // Arrange
        using var httpHandler = new RecordingHttpMessageHandler(
                  new FakeHttpMessageHandler());

        var logger = new InMemoryDiagnosticLogger();

        var httpTransport = new HttpTransport(
            new SentryOptions
        {
            Dsn = DsnSamples.ValidDsnWithSecret,
            MaxAttachmentSize = 1,
            DiagnosticLogger  = logger,
            Debug             = true
        },
            new HttpClient(httpHandler));

        var attachment = new Attachment(
            AttachmentType.Default,
            new FileAttachmentContent("test1.txt"),
            "test1.txt",
            null);

        using var envelope = Envelope.FromEvent(
                  new SentryEvent(),
                  logger,
                  new[] { attachment });

        // Act
        await httpTransport.SendEnvelopeAsync(envelope);

        var lastRequest = httpHandler.GetRequests().Last();
        var actualEnvelopeSerialized = await lastRequest.Content.ReadAsStringAsync();

        // Assert
        // (the envelope should have only one item)

        logger.Entries.Should().Contain(e =>
                                        e.Message == "Failed to add attachment: {0}." &&
                                        (string)e.Args[0] == "test1.txt");

        actualEnvelopeSerialized.Should().NotContain("test2.txt");
    }
Example #5
0
        public async Task SendEnvelopeAsync_ItemRateLimit_DoesNotAffectNextSessionWithDifferentId()
        {
            // Arrange
            using var httpHandler = new RecordingHttpMessageHandler(
                      new FakeHttpMessageHandler(
                          () => SentryResponses.GetRateLimitResponse("1:session")
                          )
                      );

            var httpTransport = new HttpTransport(
                new SentryOptions
            {
                Dsn = DsnSamples.ValidDsnWithSecret
            },
                new HttpClient(httpHandler)
                );

            var session = new Session("foo", "bar", "baz");

            // First request always goes through
            await httpTransport.SendEnvelopeAsync(Envelope.FromEvent(new SentryEvent()));

            // Send session update with init=true
            await httpTransport.SendEnvelopeAsync(Envelope.FromEvent(new SentryEvent(), null, session.CreateUpdate(true, DateTimeOffset.Now)));

            // Pretend the rate limit has already passed
            foreach (var(category, _) in httpTransport.CategoryLimitResets)
            {
                httpTransport.CategoryLimitResets[category] = DateTimeOffset.Now - TimeSpan.FromDays(1);
            }

            // Act

            // Send an update for different session with init=false (should NOT get promoted)
            var nextSession = new Session("foo2", "bar2", "baz2");
            await httpTransport.SendEnvelopeAsync(Envelope.FromEvent(new SentryEvent(), null, nextSession.CreateUpdate(false, DateTimeOffset.Now)));

            var lastRequest = httpHandler.GetRequests().Last();
            var actualEnvelopeSerialized = await lastRequest.Content.ReadAsStringAsync();

            // Assert
            actualEnvelopeSerialized.Should().NotContain("\"init\":true");
        }
 public RecordingHandlerBuilderFilter(RecordingHttpMessageHandler handler) => _handler = handler;
        public async Task SendEnvelopeAsync_ItemRateLimit_DropsItem()
        {
            // Arrange
            using var httpHandler = new RecordingHttpMessageHandler(
                      new FakeHttpMessageHandler(
                          () => SentryResponses.GetRateLimitResponse("1234:event, 897:transaction")
                          ));

            var httpTransport = new HttpTransport(
                new SentryOptions
            {
                Dsn = DsnSamples.ValidDsnWithSecret
            },
                new HttpClient(httpHandler));

            // First request always goes through
            await httpTransport.SendEnvelopeAsync(Envelope.FromEvent(new SentryEvent()));

            var envelope = new Envelope(
                new Dictionary <string, object>(),
                new[]
            {
                // Should be dropped
                new EnvelopeItem(
                    new Dictionary <string, object> {
                    ["type"] = "event"
                },
                    new EmptySerializable()),
                new EnvelopeItem(
                    new Dictionary <string, object> {
                    ["type"] = "event"
                },
                    new EmptySerializable()),
                new EnvelopeItem(
                    new Dictionary <string, object> {
                    ["type"] = "transaction"
                },
                    new EmptySerializable()),

                // Should stay
                new EnvelopeItem(
                    new Dictionary <string, object> {
                    ["type"] = "other"
                },
                    new EmptySerializable())
            });

            var expectedEnvelope = new Envelope(
                new Dictionary <string, object>(),
                new[]
            {
                new EnvelopeItem(
                    new Dictionary <string, object> {
                    ["type"] = "other"
                },
                    new EmptySerializable())
            });

            var expectedEnvelopeSerialized = await expectedEnvelope.SerializeToStringAsync();

            // Act
            await httpTransport.SendEnvelopeAsync(envelope);

            var lastRequest = httpHandler.GetRequests().Last();
            var actualEnvelopeSerialized = await lastRequest.Content.ReadAsStringAsync();

            // Assert
            actualEnvelopeSerialized.Should().BeEquivalentTo(expectedEnvelopeSerialized);
        }
        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());
        }