Example #1
0
            public Fixture()
            {
                HttpMessageHandler.VerifyableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
                .Returns(_ => SentryResponses.GetOkResponse());

                HttpClient = new HttpClient(HttpMessageHandler);
            }
Example #2
0
        public async Task SendEnvelopeAsync_CancellationToken_PassedToClient()
        {
            // Arrange
            using var source = new CancellationTokenSource();
            source.Cancel();
            var token = source.Token;

            var httpHandler = Substitute.For <MockableHttpMessageHandler>();

            httpHandler.VerifiableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetOkResponse());

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

            var envelope = Envelope.FromEvent(
                new SentryEvent(eventId: SentryResponses.ResponseId)
                );

#if NET5_0
            await Assert.ThrowsAsync <TaskCanceledException>(() => httpTransport.SendEnvelopeAsync(envelope, token));
#else
            // Act
            await httpTransport.SendEnvelopeAsync(envelope, token);

            // Assert
            await httpHandler
            .Received(1)
            .VerifiableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Is <CancellationToken>(c => c.IsCancellationRequested));
#endif
        }
Example #3
0
        public async Task SendEnvelopeAsync_AttachmentTooLarge_DropsItem()
        {
            // Arrange
            using var httpHandler = new FakeHttpClientHandler(
                      _ => SentryResponses.GetOkResponse()
                      );

            var logger = new AccumulativeDiagnosticLogger();

            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_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 async Task CaptureEventAsync_ResponseNotOkNoMessage_CallbackFired()
        {
            const HttpStatusCode expectedCode = HttpStatusCode.BadGateway;
            var expectedEvent = new SentryEvent();

            _fixture.SentryOptions.DiagnosticLogger.IsEnabled(SentryLevel.Error).Returns(true);
            _fixture.HttpMessageHandler.VerifyableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetErrorResponse(expectedCode, null));

            var sut = _fixture.GetSut();

            await sut.CaptureEventAsync(expectedEvent);

            _fixture.SentryOptions.DiagnosticLogger.Received(1).Log(SentryLevel.Error,
                                                                    "Sentry rejected the event {0}. Status code: {1}. Sentry response: {2}", null,
                                                                    Arg.Is <object[]>(p => p[0].ToString() == expectedEvent.EventId.ToString() &&
                                                                                      p[1].ToString() == expectedCode.ToString() &&
                                                                                      p[2].ToString() == HttpTransport.NoMessageFallback));
        }
Example #6
0
        public async Task SendEnvelopeAsync_ResponseNotOkWithJsonMessage_LogsError()
        {
            // Arrange
            const HttpStatusCode expectedCode    = HttpStatusCode.BadGateway;
            const string         expectedMessage = "Bad Gateway!";
            var expectedCauses          = new[] { "invalid file", "wrong arguments" };
            var expectedCausesFormatted = string.Join(", ", expectedCauses);

            var httpHandler = Substitute.For <MockableHttpMessageHandler>();

            httpHandler.VerifiableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetJsonErrorResponse(expectedCode, expectedMessage, expectedCauses));

            var logger = new InMemoryDiagnosticLogger();

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

            var envelope = Envelope.FromEvent(new SentryEvent());

            // Act
            await httpTransport.SendEnvelopeAsync(envelope);

            // Assert
            logger.Entries.Any(e =>
                               e.Level == SentryLevel.Error &&
                               e.Message == "Sentry rejected the envelope {0}. Status code: {1}. Error detail: {2}. Error causes: {3}." &&
                               e.Exception == null &&
                               e.Args[0].ToString() == envelope.TryGetEventId().ToString() &&
                               e.Args[1].ToString() == expectedCode.ToString() &&
                               e.Args[2].ToString() == expectedMessage &&
                               e.Args[3].ToString() == expectedCausesFormatted
                               ).Should().BeTrue();
        }
Example #7
0
        public async Task SendEnvelopeAsync_ResponseNotOkWithMessage_LogsError()
        {
            // Arrange
            const HttpStatusCode expectedCode    = HttpStatusCode.BadGateway;
            const string         expectedMessage = "Bad Gateway!";

            var httpHandler = Substitute.For <MockableHttpMessageHandler>();

            httpHandler.VerifyableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetErrorResponse(expectedCode, expectedMessage));

            var logger = new AccumulativeDiagnosticLogger();

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

            var envelope = Envelope.FromEvent(new SentryEvent());

            // Act
            await httpTransport.SendEnvelopeAsync(envelope);

            // Assert
            logger.Entries.Any(e =>
                               e.Level == SentryLevel.Error &&
                               e.Message == "Sentry rejected the envelope {0}. Status code: {1}. Sentry response: {2}" &&
                               e.Exception == null &&
                               e.Args[0].ToString() == envelope.TryGetEventId().ToString() &&
                               e.Args[1].ToString() == expectedCode.ToString() &&
                               e.Args[2].ToString() == expectedMessage
                               ).Should().BeTrue();
        }
        public async Task CaptureEventAsync_ResponseNotOkNoMessage_CallbackFired()
        {
            const HttpStatusCode expectedCode = HttpStatusCode.BadGateway;
            var expectedEvent = new SentryEvent();

            var callbackInvoked = false;

            _fixture.HttpOptions.HandleFailedEventSubmission = (e, c, m) =>
            {
                Assert.Same(e, expectedEvent);
                Assert.Equal(HttpTransport.NoMessageFallback, m);
                Assert.Equal(expectedCode, c);
                callbackInvoked = true;
            };
            _fixture.HttpMessageHandler.VerifyableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetErrorResponse(expectedCode, null));

            var sut = _fixture.GetSut();

            await sut.CaptureEventAsync(expectedEvent);

            Assert.True(callbackInvoked);
        }
        public async Task SendEnvelopeAsync_ResponseRequestEntityTooLargeWithoutPathDefined_DoesNotStoreFile()
        {
            // Arrange
            var httpHandler = Substitute.For <MockableHttpMessageHandler>();

            httpHandler.VerifiableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetJsonErrorResponse(HttpStatusCode.RequestEntityTooLarge, ""));

            var logger = new InMemoryDiagnosticLogger();

            var func = Substitute.For <Func <string, string> >();

            func(Arg.Any <string>()).Returns(null as string);

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

            // Act
            await httpTransport.SendEnvelopeAsync(Envelope.FromEvent(new SentryEvent()));

            // Assert
            logger.Entries.Any(e => e.Message == "Environment variable '{0}' set. Writing envelope to {1}")
            .Should()
            .BeFalse();

            logger.Entries.Any(e => e.Message == "Envelope's {0} bytes written to: {1}")
            .Should()
            .BeFalse();
        }
Example #10
0
        public async Task SendEnvelopeAsync_ItemRateLimit_DropsItem()
        {
            // Arrange
            using var httpHandler = new FakeHttpClientHandler(
                      _ => 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 SendEnvelopeAsync_ResponseRequestEntityTooLargeWithPathDefined_StoresFile()
        {
            // Arrange
            var httpHandler = Substitute.For <MockableHttpMessageHandler>();

            httpHandler.VerifiableSendAsync(Arg.Any <HttpRequestMessage>(), Arg.Any <CancellationToken>())
            .Returns(_ => SentryResponses.GetJsonErrorResponse(HttpStatusCode.RequestEntityTooLarge, ""));

            var logger = new InMemoryDiagnosticLogger();

            var          func           = Substitute.For <Func <string, string> >();
            var          path           = Path.GetTempPath();
            const string expectedEnvVar = "SENTRY_KEEP_LARGE_ENVELOPE_PATH";

            func(expectedEnvVar).Returns(path);

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

            var envelope = Envelope.FromEvent(new SentryEvent());

            // Act
            await httpTransport.SendEnvelopeAsync(envelope);

            // Assert
            logger.Entries.Any(e =>
                               e.Level == SentryLevel.Debug &&
                               e.Message == "Environment variable '{0}' set. Writing envelope to {1}" &&
                               e.Exception == null &&
                               e.Args[0].ToString() == expectedEnvVar &&
                               e.Args[1].ToString() == path)
            .Should()
            .BeTrue();

            var fileStoredLogEntry = logger.Entries.FirstOrDefault(e =>
                                                                   e.Level == SentryLevel.Info &&
                                                                   e.Message == "Envelope's {0} bytes written to: {1}");

            Assert.NotNull(fileStoredLogEntry);
            var expectedFile = new FileInfo(fileStoredLogEntry.Args[1].ToString());

            Assert.True(expectedFile.Exists);
            try
            {
                Assert.Null(fileStoredLogEntry.Exception);
                // // Path is based on the provided path:
                Assert.Contains(path, fileStoredLogEntry.Args[1] as string);
                // // Path contains the envelope id in its name:
                Assert.Contains(envelope.TryGetEventId().ToString(), fileStoredLogEntry.Args[1] as string);
                Assert.Equal(expectedFile.Length, (long)fileStoredLogEntry.Args[0]);
            }
            finally
            {
                // It's in the temp folder but just to keep things tidy:
                expectedFile.Delete();
            }
        }