Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- Remove the `SdkComposer` fallback transport in `SynchronousWorker`, which has thrown since the sentry-dotnet 5.1.1 bump. The SDK's own default worker and transport are used instead ([#143](https://github.com/getsentry/sentry-powershell/pull/143))
- Silence CS1701/CS1702 warnings emitted by `Add-Type` when importing the module on PowerShell hosts whose runtime `System.Runtime` version differs from the one `Sentry.dll` was compiled against ([#129](https://github.com/getsentry/sentry-powershell/pull/129))

### Features
Expand Down
16 changes: 0 additions & 16 deletions modules/Sentry/private/New-HttpTransport.ps1

This file was deleted.

14 changes: 6 additions & 8 deletions modules/Sentry/private/SynchronousWorker.ps1
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
. "$privateDir/New-HttpTransport.ps1"

class SynchronousWorker : Sentry.Extensibility.IBackgroundWorker {
hidden [Sentry.Extensibility.ITransport] $transport
hidden [Sentry.SentryOptions] $options
hidden $unfinishedTasks = [System.Collections.Generic.List[System.Threading.Tasks.Task]]::new()

SynchronousWorker([Sentry.SentryOptions] $options) {
$this.options = $options

# Start from either the transport given on options, or create a new HTTP transport.
$this.transport = $options.Transport;
if ($null -eq $this.transport) {
$this.transport = New-HttpTransport($options)
# No fallback: the SDK builds its own default worker and transport when BackgroundWorker is left unset.
if ($null -eq $options.Transport) {
throw 'SynchronousWorker requires options.Transport to be set.'
}

$this.options = $options
$this.transport = $options.Transport
}

[bool] EnqueueEnvelope([Sentry.Protocol.Envelopes.Envelope] $envelope) {
Expand Down
64 changes: 64 additions & 0 deletions tests/sdk-internals.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Reflection lookups fail silently, so pin the SDK internals the module depends on. A dependency bump that moves
# one of these must fail here rather than at send time.

BeforeAll {
. "$PSScriptRoot/utils.ps1"
. "$PSScriptRoot/../modules/Sentry/private/SynchronousTransport.ps1"

$instanceFlags = [System.Reflection.BindingFlags]::Instance + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public
Comment thread
vaind marked this conversation as resolved.
Dismissed
$staticFlags = [System.Reflection.BindingFlags]::Static + [System.Reflection.BindingFlags]::NonPublic + [System.Reflection.BindingFlags]::Public
Comment thread
vaind marked this conversation as resolved.
Dismissed

function Get-SentryInternalType([string] $name) {
return [Sentry.SentrySdk].Assembly.GetType($name)
}

function Should-BeMethod($method, [string] $returnType, [string[]] $parameterTypes) {
Comment thread
vaind marked this conversation as resolved.
Dismissed
$method | Should -Not -BeNullOrEmpty
$method.ReturnType.FullName | Should -Be $returnType
($method.GetParameters() | ForEach-Object { $_.ParameterType.FullName }) | Should -Be $parameterTypes
}
}

Describe 'Sentry SDK internals used by SynchronousTransport' {
It 'HttpTransportBase.ProcessEnvelope' {
$method = [Sentry.Http.HttpTransportBase].GetMethod('ProcessEnvelope', $instanceFlags)
Should-BeMethod $method 'Sentry.Protocol.Envelopes.Envelope' @('Sentry.Protocol.Envelopes.Envelope')
Comment thread
vaind marked this conversation as resolved.
Dismissed
}

It 'HttpTransportBase.CreateRequest' {
$method = [Sentry.Http.HttpTransportBase].GetMethod('CreateRequest', $instanceFlags)
Should-BeMethod $method 'System.Net.Http.HttpRequestMessage' @('Sentry.Protocol.Envelopes.Envelope')
Comment thread
vaind marked this conversation as resolved.
Dismissed
}

It 'HttpTransportBase.HandleResponse' {
$method = [Sentry.Http.HttpTransportBase].GetMethod('HandleResponse', $instanceFlags)
Should-BeMethod $method 'System.Void' @('System.Net.Http.HttpResponseMessage', 'Sentry.Protocol.Envelopes.Envelope')
Comment thread
vaind marked this conversation as resolved.
Dismissed
}

It 'Sentry.Internal.Http.EnvelopeHttpContent' {
Get-SentryInternalType 'Sentry.Internal.Http.EnvelopeHttpContent' | Should -Not -BeNullOrEmpty
}

It 'EnvelopeHttpContent.SerializeToStream' {
$type = Get-SentryInternalType 'Sentry.Internal.Http.EnvelopeHttpContent'
$method = $type.GetMethod('SerializeToStream', $instanceFlags)
Should-BeMethod $method 'System.Void' @('System.IO.Stream', 'System.Net.TransportContext', 'System.Threading.CancellationToken')
Comment thread
vaind marked this conversation as resolved.
Dismissed
}
}

Describe 'Sentry SDK internals used by Get-CurrentOptions' {
It 'SentrySdk.CurrentOptions' {
$property = [Sentry.SentrySdk].GetProperty('CurrentOptions', $staticFlags)
$property | Should -Not -BeNullOrEmpty
$property.PropertyType.FullName | Should -Be 'Sentry.SentryOptions'
}
}

Describe 'SynchronousTransport' {
It 'resolves every internal member it needs' {
# The constructor does all of the above lookups and throws on any that fail.
$options = [Sentry.SentryOptions]::new()
$options.Dsn = 'https://key@127.0.0.1/1'
{ [SynchronousTransport]::new($options) } | Should -Not -Throw
}
}
58 changes: 58 additions & 0 deletions tests/synchronous-worker.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
BeforeAll {
. "$PSScriptRoot/utils.ps1"
. "$PSScriptRoot/../modules/Sentry/private/SynchronousWorker.ps1"
. "$PSScriptRoot/../modules/Sentry/private/Get-CurrentOptions.ps1"
$global:SentryPowershellRethrowErrors = $true
Comment thread
vaind marked this conversation as resolved.
Dismissed
}

AfterAll {
$global:SentryPowershellRethrowErrors = $false
Comment thread
vaind marked this conversation as resolved.
Dismissed
}

Describe 'SynchronousWorker' {
It 'throws when options.Transport is not set' {
# Only reachable when the SynchronousTransport constructor threw.
$options = [Sentry.SentryOptions]::new()
$options.Transport | Should -Be $null
{ [SynchronousWorker]::new($options) } | Should -Throw '*requires options.Transport*'
}

It 'sends envelopes through the transport from options' {
$options = [Sentry.SentryOptions]::new()
$options.Dsn = 'https://key@127.0.0.1/1'
$options.Transport = [RecordingTransport]::new()

$sut = [SynchronousWorker]::new($options)
$envelope = [Sentry.Protocol.Envelopes.Envelope]::FromEvent([Sentry.SentryEvent]::new(), $null, $null, $null)
$sut.EnqueueEnvelope($envelope) | Should -Be $true

$options.Transport.envelopes.Count | Should -Be 1
$sut.get_QueuedItems() | Should -Be 0
}
}

Describe 'Start-Sentry worker composition' {
AfterEach {
Stop-Sentry
}

It 'wires a SynchronousWorker on top of a SynchronousTransport' {
Start-Sentry { $_.Dsn = 'https://key@127.0.0.1/1' }

$options = Get-CurrentOptions
$options.Transport.GetType().Name | Should -Be 'SynchronousTransport'
$options.BackgroundWorker.GetType().Name | Should -Be 'SynchronousWorker'
}

It 'keeps a transport supplied through options' {
$transport = [RecordingTransport]::new()
Start-Sentry {
$_.Dsn = 'https://key@127.0.0.1/1'
$_.Transport = $transport
}

$options = Get-CurrentOptions
$options.Transport | Should -Be $transport
$options.BackgroundWorker.GetType().Name | Should -Be 'SynchronousWorker'
}
}
Loading