diff --git a/src/CloudEventsPowerShell/CloudEvents.Sdk.psd1 b/src/CloudEventsPowerShell/CloudEvents.Sdk.psd1 index bcaa783..558ce15 100644 --- a/src/CloudEventsPowerShell/CloudEvents.Sdk.psd1 +++ b/src/CloudEventsPowerShell/CloudEvents.Sdk.psd1 @@ -9,7 +9,7 @@ RootModule = 'CloudEvents.Sdk.psm1' # Version number of this module. -ModuleVersion = '0.2.0' +ModuleVersion = '0.2.1' # Supported PSEditions CompatiblePSEditions = @('Core') diff --git a/src/CloudEventsPowerShell/CloudEvents.Sdk.psm1 b/src/CloudEventsPowerShell/CloudEvents.Sdk.psm1 index bd03947..f878b8c 100644 --- a/src/CloudEventsPowerShell/CloudEvents.Sdk.psm1 +++ b/src/CloudEventsPowerShell/CloudEvents.Sdk.psm1 @@ -556,7 +556,7 @@ PROCESS { $headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToString()) } elseif ($attribute.Value -is [DateTime]) { - $headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToString("u")) + $headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')) } elseif ($attribute.Value -is [Uri] -or $attribute.Value -is [int]) { $headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToString()) diff --git a/test/integration/HttpIntegration.Tests.ps1 b/test/integration/HttpIntegration.Tests.ps1 index 950b6fd..f58225a 100644 --- a/test/integration/HttpIntegration.Tests.ps1 +++ b/test/integration/HttpIntegration.Tests.ps1 @@ -4,277 +4,306 @@ # ************************************************************************** param( - [Parameter()] - [ValidateScript({Test-Path $_})] - [string] - $CloudEventsModulePath) + [Parameter()] + [ValidateScript( { Test-Path $_ })] + [string] + $CloudEventsModulePath) Describe "Client-Server Integration Tests" { - Context "Send And Receive CloudEvents over Http" { - BeforeAll { - $testServerUrl = 'http://localhost:52673/' + Context "Send And Receive CloudEvents over Http" { + BeforeAll { + $testServerUrl = 'http://localhost:52673/' - $serverProcess = $null + $serverProcess = $null - . (Join-Path $PSScriptRoot 'ProtocolConstants.ps1') + . (Join-Path $PSScriptRoot 'ProtocolConstants.ps1') - # Starts CloudEvent Test Server - $usePowerShell = (Get-Process -Id $pid).ProcessName - $serverScript = Join-Path $PSScriptRoot 'HttpServer.ps1' - $serverProcessArguments = "-Command $serverScript -CloudEventsModulePath '$CloudEventsModulePath' -ServerUrl '$testServerUrl'" + # Starts CloudEvent Test Server + $usePowerShell = (Get-Process -Id $pid).ProcessName + $serverScript = Join-Path $PSScriptRoot 'HttpServer.ps1' + $serverProcessArguments = "-Command $serverScript -CloudEventsModulePath '$CloudEventsModulePath' -ServerUrl '$testServerUrl'" - $serverProcess = Start-Process ` - -FilePath $usePowerShell ` - -ArgumentList $serverProcessArguments ` - -PassThru ` - -NoNewWindow - } + $serverProcess = Start-Process ` + -FilePath $usePowerShell ` + -ArgumentList $serverProcessArguments ` + -PassThru ` + -NoNewWindow - AfterAll { - # Requests Stop CloudEvent Test Server - $serverStopRequest = ` - New-CloudEvent ` - -Id ([Guid]::NewGuid()) ` - -Type $script:ServerStopType ` - -Source $script:ClientSource | ` - ConvertTo-HttpMessage ` - -ContentMode Structured + # Wait Server to Start + $serverPingRequest = ` + New-CloudEvent ` + -Id ([Guid]::NewGuid()) ` + -Type $script:ServerPingType ` + -Source $script:ClientSource | ` + ConvertTo-HttpMessage ` + -ContentMode Structured - Invoke-WebRequest ` - -Uri $testServerUrl ` - -Headers $serverStopRequest.Headers ` - -Body $serverStopRequest.Body | Out-Null + $serverReady = $false + $maxRetries = 10 + do { + try { + Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $serverPingRequest.Headers ` + -Body $serverPingRequest.Body | Out-Null + $serverReady = $true + } catch { + Write-Verbose "Wait CloudEvents HTTP Test Server to start" + Start-Sleep -Seconds 1 + $maxRetries-- + } + } while (-not $serverReady -and $maxRetries -gt 0) + + if ($maxRetries -eq 0) { + throw "CloudEvents HTTP Test Server failed to start." + } + } - if ($serverProcess -ne $null -and ` - -not $serverProcess.HasExited) { - $serverProcess | Wait-Process - } - } + AfterAll { + # Requests Stop CloudEvent Test Server + $serverStopRequest = ` + New-CloudEvent ` + -Id ([Guid]::NewGuid()) ` + -Type $script:ServerStopType ` + -Source $script:ClientSource | ` + ConvertTo-HttpMessage ` + -ContentMode Structured - It 'Echo binary content mode cloud events' { - # Arrange - $cloudEvent = New-CloudEvent ` - -Type $script:EchoBinaryType ` - -Source $script:ClientSource ` - -Id 'integration-test-1' ` - -Time (Get-Date) | ` - Set-CloudEventJsonData -Data @{ - 'a1' = 'b' - 'a2' = 'c' - 'a3' = 'd' - } + Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $serverStopRequest.Headers ` + -Body $serverStopRequest.Body | Out-Null - # Act + if ($serverProcess -ne $null -and ` + -not $serverProcess.HasExited) { + $serverProcess | Wait-Process + } + } - ## Convert CloudEvent to HTTP Message - $httpRequest = ConvertTo-HttpMessage ` - -CloudEvent $cloudEvent ` - -ContentMode Binary + It 'Echo binary content mode cloud events' { + # Arrange + $cloudEvent = New-CloudEvent ` + -Type $script:EchoBinaryType ` + -Source $script:ClientSource ` + -Id 'integration-test-1' ` + -Time (Get-Date) | ` + Set-CloudEventJsonData -Data @{ + 'a1' = 'b' + 'a2' = 'c' + 'a3' = 'd' + } - ## Invoke WebRequest with the HTTP Message - $httpResponse = Invoke-WebRequest ` - -Uri $testServerUrl ` - -Headers $httpRequest.Headers ` - -Body $httpRequest.Body + # Act - ## Convert HTTP Response to CloudEvent - $resultCloudEvent = ConvertFrom-HttpMessage ` - -Headers $httpResponse.Headers ` - -Body $httpResponse.Content + ## Convert CloudEvent to HTTP Message + $httpRequest = ConvertTo-HttpMessage ` + -CloudEvent $cloudEvent ` + -ContentMode Binary - # Assert + ## Invoke WebRequest with the HTTP Message + $httpResponse = Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $httpRequest.Headers ` + -Body $httpRequest.Body - ## Assert echoed CloudEvent - $resultCloudEvent | Should -Not -Be $null - $resultCloudEvent.Source | Should -Be $script:ServerSource - $resultCloudEvent.Type | Should -Be $script:EchoBinaryType - $resultCloudEvent.Id | Should -Be $cloudEvent.Id - $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time + ## Convert HTTP Response to CloudEvent + $resultCloudEvent = ConvertFrom-HttpMessage ` + -Headers $httpResponse.Headers ` + -Body $httpResponse.Content - ## Assert Result CloudEvent Data - ## Read Data as Json - $resultData = $resultCloudEvent | Read-CloudEventJsonData - $resultData.a1 | Should -Be 'b' - $resultData.a2 | Should -Be 'c' - $resultData.a3 | Should -Be 'd' - } + # Assert - It 'Echo binary content mode cloud events with XML data' { - # Arrange - $cloudEvent = New-CloudEvent ` - -Type $script:EchoBinaryType ` - -Source $script:ClientSource ` - -Id 'integration-test-2' ` - -Time (Get-Date) | ` - Set-CloudEventXmlData -Data @{ - 'a1' = @{ - 'a2' = 'c' - 'a3' = 'd' - } - } ` - -AttributesKeysInElementAttributes $false + ## Assert echoed CloudEvent + $resultCloudEvent | Should -Not -Be $null + $resultCloudEvent.Source | Should -Be $script:ServerSource + $resultCloudEvent.Type | Should -Be $script:EchoBinaryType + $resultCloudEvent.Id | Should -Be $cloudEvent.Id + $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time - # Act + ## Assert Result CloudEvent Data + ## Read Data as Json + $resultData = $resultCloudEvent | Read-CloudEventJsonData + $resultData.a1 | Should -Be 'b' + $resultData.a2 | Should -Be 'c' + $resultData.a3 | Should -Be 'd' + } - ## Convert CloudEvent to HTTP Message - $httpRequest = ConvertTo-HttpMessage ` - -CloudEvent $cloudEvent ` - -ContentMode Binary + It 'Echo binary content mode cloud events with XML data' { + # Arrange + $cloudEvent = New-CloudEvent ` + -Type $script:EchoBinaryType ` + -Source $script:ClientSource ` + -Id 'integration-test-2' ` + -Time (Get-Date) | ` + Set-CloudEventXmlData -Data @{ + 'a1' = @{ + 'a2' = 'c' + 'a3' = 'd' + } + } ` + -AttributesKeysInElementAttributes $false - ## Invoke WebRequest with the HTTP Message - $httpResponse = Invoke-WebRequest ` - -Uri $testServerUrl ` - -Headers $httpRequest.Headers ` - -Body $httpRequest.Body + # Act - ## Convert HTTP Response to CloudEvent - $resultCloudEvent = ConvertFrom-HttpMessage ` - -Headers $httpResponse.Headers ` - -Body $httpResponse.Content + ## Convert CloudEvent to HTTP Message + $httpRequest = ConvertTo-HttpMessage ` + -CloudEvent $cloudEvent ` + -ContentMode Binary - # Assert + ## Invoke WebRequest with the HTTP Message + $httpResponse = Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $httpRequest.Headers ` + -Body $httpRequest.Body - ## Assert echoed CloudEvent - $resultCloudEvent | Should -Not -Be $null - $resultCloudEvent.Source | Should -Be $script:ServerSource - $resultCloudEvent.Type | Should -Be $script:EchoBinaryType - $resultCloudEvent.Id | Should -Be $cloudEvent.Id - $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time + ## Convert HTTP Response to CloudEvent + $resultCloudEvent = ConvertFrom-HttpMessage ` + -Headers $httpResponse.Headers ` + -Body $httpResponse.Content - ## Assert Result CloudEvent Data - ## Read Data as Xml - $resultData = $resultCloudEvent | Read-CloudEventXmlData -ConvertMode 'SkipAttributes' - $resultData -is [hashtable] | Should -Be $true - $resultData.a1 -is [hashtable] | Should -Be $true - $resultData.a1.a2 | Should -Be 'c' - $resultData.a1.a3 | Should -Be 'd' - } + # Assert - It 'Echo structured content mode cloud events' { - # Arrange - $cloudEvent = New-CloudEvent ` - -Type $script:EchoStructuredType ` - -Source $script:ClientSource ` - -Id 'integration-test-3' ` - -Time (Get-Date) | ` - Set-CloudEventJsonData -Data @{ - 'b1' = 'd' - 'b2' = 'e' - 'b3' = 'f' - } + ## Assert echoed CloudEvent + $resultCloudEvent | Should -Not -Be $null + $resultCloudEvent.Source | Should -Be $script:ServerSource + $resultCloudEvent.Type | Should -Be $script:EchoBinaryType + $resultCloudEvent.Id | Should -Be $cloudEvent.Id + $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time - # Act + ## Assert Result CloudEvent Data + ## Read Data as Xml + $resultData = $resultCloudEvent | Read-CloudEventXmlData -ConvertMode 'SkipAttributes' + $resultData -is [hashtable] | Should -Be $true + $resultData.a1 -is [hashtable] | Should -Be $true + $resultData.a1.a2 | Should -Be 'c' + $resultData.a1.a3 | Should -Be 'd' + } - ## Convert CloudEvent to HTTP Message - $httpRequest = ConvertTo-HttpMessage ` - -CloudEvent $cloudEvent ` - -ContentMode Structured + It 'Echo structured content mode cloud events' { + # Arrange + $cloudEvent = New-CloudEvent ` + -Type $script:EchoStructuredType ` + -Source $script:ClientSource ` + -Id 'integration-test-3' ` + -Time (Get-Date) | ` + Set-CloudEventJsonData -Data @{ + 'b1' = 'd' + 'b2' = 'e' + 'b3' = 'f' + } - ## Invoke WebRequest with the HTTP Message - $httpResponse = Invoke-WebRequest ` - -Uri $testServerUrl ` - -Headers $httpRequest.Headers ` - -Body $httpRequest.Body + # Act - ## Convert HTTP Response to CloudEvent - $resultCloudEvent = ConvertFrom-HttpMessage ` - -Headers $httpResponse.Headers ` - -Body $httpResponse.Content + ## Convert CloudEvent to HTTP Message + $httpRequest = ConvertTo-HttpMessage ` + -CloudEvent $cloudEvent ` + -ContentMode Structured - # Assert + ## Invoke WebRequest with the HTTP Message + $httpResponse = Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $httpRequest.Headers ` + -Body $httpRequest.Body - ## Assert echoed CloudEvent - $resultCloudEvent | Should -Not -Be $null - $resultCloudEvent.Source | Should -Be $script:ServerSource - $resultCloudEvent.Type | Should -Be $script:EchoStructuredType - $resultCloudEvent.Id | Should -Be $cloudEvent.Id - $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time + ## Convert HTTP Response to CloudEvent + $resultCloudEvent = ConvertFrom-HttpMessage ` + -Headers $httpResponse.Headers ` + -Body $httpResponse.Content - ## Assert Result CloudEvent Data - ## Read Data as Json - $resultData = $resultCloudEvent | Read-CloudEventJsonData - $resultData.b1 | Should -Be 'd' - $resultData.b2 | Should -Be 'e' - $resultData.b3 | Should -Be 'f' - } + # Assert - It 'Echo structured content mode cloud events with XML data' { - # Arrange - $cloudEvent = New-CloudEvent ` - -Type $script:EchoStructuredType ` - -Source $script:ClientSource ` - -Id 'integration-test-4' ` - -Time (Get-Date) | ` - Set-CloudEventXmlData -Data @{ - 'b1' = @{ - 'b2' = 'e' - 'b3' = 'f' - } - } ` - -AttributesKeysInElementAttributes $false + ## Assert echoed CloudEvent + $resultCloudEvent | Should -Not -Be $null + $resultCloudEvent.Source | Should -Be $script:ServerSource + $resultCloudEvent.Type | Should -Be $script:EchoStructuredType + $resultCloudEvent.Id | Should -Be $cloudEvent.Id + $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time - # Act + ## Assert Result CloudEvent Data + ## Read Data as Json + $resultData = $resultCloudEvent | Read-CloudEventJsonData + $resultData.b1 | Should -Be 'd' + $resultData.b2 | Should -Be 'e' + $resultData.b3 | Should -Be 'f' + } - ## Convert CloudEvent to HTTP Message - $httpRequest = ConvertTo-HttpMessage ` - -CloudEvent $cloudEvent ` - -ContentMode Structured + It 'Echo structured content mode cloud events with XML data' { + # Arrange + $cloudEvent = New-CloudEvent ` + -Type $script:EchoStructuredType ` + -Source $script:ClientSource ` + -Id 'integration-test-4' ` + -Time (Get-Date) | ` + Set-CloudEventXmlData -Data @{ + 'b1' = @{ + 'b2' = 'e' + 'b3' = 'f' + } + } ` + -AttributesKeysInElementAttributes $false - ## Invoke WebRequest with the HTTP Message - $httpResponse = Invoke-WebRequest ` - -Uri $testServerUrl ` - -Headers $httpRequest.Headers ` - -Body $httpRequest.Body + # Act - ## Convert HTTP Response to CloudEvent - $resultCloudEvent = ConvertFrom-HttpMessage ` - -Headers $httpResponse.Headers ` - -Body $httpResponse.Content + ## Convert CloudEvent to HTTP Message + $httpRequest = ConvertTo-HttpMessage ` + -CloudEvent $cloudEvent ` + -ContentMode Structured - # Assert + ## Invoke WebRequest with the HTTP Message + $httpResponse = Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $httpRequest.Headers ` + -Body $httpRequest.Body - ## Assert echoed CloudEvent - $resultCloudEvent | Should -Not -Be $null - $resultCloudEvent.Source | Should -Be $script:ServerSource - $resultCloudEvent.Type | Should -Be $script:EchoStructuredType - $resultCloudEvent.Id | Should -Be $cloudEvent.Id - $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time + ## Convert HTTP Response to CloudEvent + $resultCloudEvent = ConvertFrom-HttpMessage ` + -Headers $httpResponse.Headers ` + -Body $httpResponse.Content - ## Assert Result CloudEvent Data - ## Read Data as Xml - $resultData = $resultCloudEvent | Read-CloudEventXmlData -ConvertMode 'SkipAttributes' - $resultData -is [hashtable] | Should -Be $true - $resultData.b1 -is [hashtable] | Should -Be $true - $resultData.b1.b2 | Should -Be 'e' - $resultData.b1.b3 | Should -Be 'f' - } + # Assert - It 'Send cloud event expecting no result' { - # Arrange - $cloudEvent = New-CloudEvent ` - -Type 'no-content' ` - -Source $script:ClientSource ` - -Id 'integration-test-5' ` - -Time (Get-Date) | ` - Set-CloudEventData ` - -Data 'This is text data' ` - -DataContentType 'application/text' + ## Assert echoed CloudEvent + $resultCloudEvent | Should -Not -Be $null + $resultCloudEvent.Source | Should -Be $script:ServerSource + $resultCloudEvent.Type | Should -Be $script:EchoStructuredType + $resultCloudEvent.Id | Should -Be $cloudEvent.Id + $resultCloudEvent.Time | Should -BeGreaterThan $cloudEvent.Time - # Act + ## Assert Result CloudEvent Data + ## Read Data as Xml + $resultData = $resultCloudEvent | Read-CloudEventXmlData -ConvertMode 'SkipAttributes' + $resultData -is [hashtable] | Should -Be $true + $resultData.b1 -is [hashtable] | Should -Be $true + $resultData.b1.b2 | Should -Be 'e' + $resultData.b1.b3 | Should -Be 'f' + } - ## Convert CloudEvent to HTTP Message - $httpRequest = ConvertTo-HttpMessage ` - -CloudEvent $cloudEvent ` - -ContentMode Structured + It 'Send cloud event expecting no result' { + # Arrange + $cloudEvent = New-CloudEvent ` + -Type 'no-content' ` + -Source $script:ClientSource ` + -Id 'integration-test-5' ` + -Time (Get-Date) | ` + Set-CloudEventData ` + -Data 'This is text data' ` + -DataContentType 'application/text' - ## Invoke WebRequest with the HTTP Message - $httpResponse = Invoke-WebRequest ` - -Uri $testServerUrl ` - -Headers $httpRequest.Headers ` - -Body $httpRequest.Body + # Act - # Assert - $httpResponse.StatusCode | Should -Be ([int]([System.Net.HttpStatusCode]::NoContent)) - } - } + ## Convert CloudEvent to HTTP Message + $httpRequest = ConvertTo-HttpMessage ` + -CloudEvent $cloudEvent ` + -ContentMode Structured + + ## Invoke WebRequest with the HTTP Message + $httpResponse = Invoke-WebRequest ` + -Uri $testServerUrl ` + -Headers $httpRequest.Headers ` + -Body $httpRequest.Body + + # Assert + $httpResponse.StatusCode | Should -Be ([int]([System.Net.HttpStatusCode]::NoContent)) + } + } } \ No newline at end of file diff --git a/test/integration/HttpServer.ps1 b/test/integration/HttpServer.ps1 index fead90f..96ae1be 100644 --- a/test/integration/HttpServer.ps1 +++ b/test/integration/HttpServer.ps1 @@ -4,18 +4,18 @@ # ************************************************************************** param( - [Parameter(Mandatory = $true)] - [ValidateScript({Test-Path $_})] - [string] - $CloudEventsModulePath, + [Parameter(Mandatory = $true)] + [ValidateScript( { Test-Path $_ })] + [string] + $CloudEventsModulePath, - [Parameter( - Mandatory = $true, - ValueFromPipeline = $false, - ValueFromPipelineByPropertyName = $false)] - [ValidateNotNull()] - [string] - $ServerUrl + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false)] + [ValidateNotNull()] + [string] + $ServerUrl ) . (Join-Path $PSScriptRoot 'ProtocolConstants.ps1') @@ -24,128 +24,139 @@ param( Import-Module $CloudEventsModulePath function Start-HttpCloudEventListener { -<# + <# .DESCRIPTION Starts a HTTP CloudEvent Listener on specified Url #> -[CmdletBinding()] -param( - [Parameter( - Mandatory = $true, - ValueFromPipeline = $false, - ValueFromPipelineByPropertyName = $false)] - [ValidateNotNull()] - [string] - $Url, + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false)] + [ValidateNotNull()] + [string] + $Url, - [Parameter( - Mandatory = $false, - ValueFromPipeline = $false, - ValueFromPipelineByPropertyName = $false)] - [scriptblock] - $Handler -) + [Parameter( + Mandatory = $false, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false)] + [scriptblock] + $Handler + ) - $listener = New-Object -Type 'System.Net.HttpListener' - $listener.AuthenticationSchemes = [System.Net.AuthenticationSchemes]::Anonymous - $listener.Prefixes.Add($Url) + $listener = New-Object -Type 'System.Net.HttpListener' + $listener.AuthenticationSchemes = [System.Net.AuthenticationSchemes]::Anonymous + $listener.Prefixes.Add($Url) - try { - $listener.Start() + try { + $listener.Start() - $context = $listener.GetContext() + $context = $listener.GetContext() - # Read Input Stream - $buffer = New-Object 'byte[]' -ArgumentList 1024 - $ms = New-Object 'IO.MemoryStream' - $read = 0 - while (($read = $context.Request.InputStream.Read($buffer, 0, 1024)) -gt 0) { - $ms.Write($buffer, 0, $read); - } - $bodyData = $ms.ToArray() - $ms.Dispose() + # Read Input Stream + $buffer = New-Object 'byte[]' -ArgumentList 1024 + $ms = New-Object 'IO.MemoryStream' + $read = 0 + while (($read = $context.Request.InputStream.Read($buffer, 0, 1024)) -gt 0) { + $ms.Write($buffer, 0, $read); + } + $bodyData = $ms.ToArray() + $ms.Dispose() - # Read Headers - $headers = @{} - for($i =0; $i -lt $context.Request.Headers.Count; $i++) { - $headers[$context.Request.Headers.GetKey($i)] = $context.Request.Headers.GetValues($i) - } + # Read Headers + $headers = @{} + for ($i = 0; $i -lt $context.Request.Headers.Count; $i++) { + $headers[$context.Request.Headers.GetKey($i)] = $context.Request.Headers.GetValues($i) + } - $cloudEvent = ConvertFrom-HttpMessage -Headers $headers -Body $bodyData + $cloudEvent = ConvertFrom-HttpMessage -Headers $headers -Body $bodyData - if ( $cloudEvent -ne $null ) { - $Handler.Invoke($cloudEvent, $context.Response) - $context.Response.Close(); - } else { - $context.Response.StatusCode = [int]([System.Net.HttpStatusCode]::BadRequest) - $context.Response.Close(); - } + if ( $cloudEvent -ne $null ) { + $Handler.Invoke($cloudEvent, $context.Response) + $context.Response.Close(); + } + else { + $context.Response.StatusCode = [int]([System.Net.HttpStatusCode]::BadRequest) + $context.Response.Close(); + } - } catch { - Write-Error $_ - $context.Response.StatusCode = [int]([System.Net.HttpStatusCode]::InternalServerError) - $context.Response.Close(); - } finally { - $listener.Stop() - } + } + catch { + Write-Error $_ + $context.Response.StatusCode = [int]([System.Net.HttpStatusCode]::InternalServerError) + $context.Response.Close(); + } + finally { + $listener.Stop() + } } $global:serverStopRequested = $false while ( -not $global:serverStopRequested ) { - Start-HttpCloudEventListener -Url $ServerUrl -Handler { - $requestCloudEvent = $args[0] - $response = $args[1] - - # When CloudEvent Type is 'echo-structured' or 'echo-binary' the Server responds - # with CloudEvent in corresponding content mode - if ( $requestCloudEvent.Type -eq $script:EchoBinaryType -or ` - $requestCloudEvent.Type -eq $script:EchoStructuredType ) { - - # Create Cloud Event for the response - $cloudEvent = New-CloudEvent ` - -Type $requestCloudEvent.Type ` - -Source $script:ServerSource ` - -Time (Get-Date) ` - -Id $requestCloudEvent.Id - - # Add Data to the new Cloud Event - $requestCloudEventJsonData = $requestCloudEvent | Read-CloudEventJsonData - $requestCloudEventXmlData = $requestCloudEvent | Read-CloudEventXmlData -ConvertMode 'SkipAttributes' - if ($requestCloudEventJsonData) { - $cloudEvent = $cloudEvent | Set-CloudEventJsonData ` - -Data $requestCloudEventJsonData - } elseif ($requestCloudEventXmlData) { - $cloudEvent = $cloudEvent | Set-CloudEventXmlData ` - -Data $requestCloudEventXmlData ` - -AttributesKeysInElementAttributes $false - } else { - $requestCloudEventData = $requestCloudEvent | Read-CloudEventData - $cloudEvent = $cloudEvent | Set-CloudEventData ` - -Data $requestCloudEventData ` - -DataContentType $requestCloudEvent.DataContentType - } - - # Convert Cloud Event to HTTP Response - $contentMode = $requestCloudEvent.Type.TrimStart('echo-') - $httpMessage = $cloudEvent | ConvertTo-HttpMessage -ContentMode $contentMode - - $response.Headers = New-Object 'System.Net.WebHeaderCollection' - foreach ($keyValue in $httpMessage.Headers.GetEnumerator()) { - $response.Headers.Add($keyValue.Key, $keyValue.Value) - } - $response.ContentLength64 = $httpMessage.Body.Length - $response.OutputStream.Write($httpMessage.Body, 0, $httpMessage.Body.Length) - $response.StatusCode = [int]([System.Net.HttpStatusCode]::OK) - - } else { - # No Content in all other cases - $response.StatusCode = [int]([System.Net.HttpStatusCode]::NoContent) - } - - if ( $requestCloudEvent.Type -eq $script:ServerStopType ) { - # Server Stop is requested - $global:serverStopRequested = $true - } - } + try { + Start-HttpCloudEventListener -Url $ServerUrl -Handler { + $requestCloudEvent = $args[0] + $response = $args[1] + + # When CloudEvent Type is 'echo-structured' or 'echo-binary' the Server responds + # with CloudEvent in corresponding content mode + if ( $requestCloudEvent.Type -eq $script:EchoBinaryType -or ` + $requestCloudEvent.Type -eq $script:EchoStructuredType ) { + + # Create Cloud Event for the response + $cloudEvent = New-CloudEvent ` + -Type $requestCloudEvent.Type ` + -Source $script:ServerSource ` + -Time (Get-Date) ` + -Id $requestCloudEvent.Id + + # Add Data to the new Cloud Event + $requestCloudEventJsonData = $requestCloudEvent | Read-CloudEventJsonData + $requestCloudEventXmlData = $requestCloudEvent | Read-CloudEventXmlData -ConvertMode 'SkipAttributes' + if ($requestCloudEventJsonData) { + $cloudEvent = $cloudEvent | Set-CloudEventJsonData ` + -Data $requestCloudEventJsonData + } + elseif ($requestCloudEventXmlData) { + $cloudEvent = $cloudEvent | Set-CloudEventXmlData ` + -Data $requestCloudEventXmlData ` + -AttributesKeysInElementAttributes $false + } + else { + $requestCloudEventData = $requestCloudEvent | Read-CloudEventData + $cloudEvent = $cloudEvent | Set-CloudEventData ` + -Data $requestCloudEventData ` + -DataContentType $requestCloudEvent.DataContentType + } + + # Convert Cloud Event to HTTP Response + $contentMode = $requestCloudEvent.Type.TrimStart('echo-') + $httpMessage = $cloudEvent | ConvertTo-HttpMessage -ContentMode $contentMode + + $response.Headers = New-Object 'System.Net.WebHeaderCollection' + foreach ($keyValue in $httpMessage.Headers.GetEnumerator()) { + $response.Headers.Add($keyValue.Key, $keyValue.Value) + } + $response.ContentLength64 = $httpMessage.Body.Length + $response.OutputStream.Write($httpMessage.Body, 0, $httpMessage.Body.Length) + $response.StatusCode = [int]([System.Net.HttpStatusCode]::OK) + + } + else { + # No Content in all other cases + $response.StatusCode = [int]([System.Net.HttpStatusCode]::NoContent) + } + + if ( $requestCloudEvent.Type -eq $script:ServerStopType ) { + # Server Stop is requested + $global:serverStopRequested = $true + } + } + } catch { + Write-Error $_ + break + } } \ No newline at end of file diff --git a/test/integration/ProtocolConstants.ps1 b/test/integration/ProtocolConstants.ps1 index 45b9400..569b516 100644 --- a/test/integration/ProtocolConstants.ps1 +++ b/test/integration/ProtocolConstants.ps1 @@ -7,4 +7,5 @@ New-Variable -Option Constant -Scope 'script' -Name 'ClientSource' -Value 'ps:te New-Variable -Option Constant -Scope 'script' -Name 'ServerSource' -Value 'ps:test:server' New-Variable -Option Constant -Scope 'script' -Name 'EchoBinaryType' -Value 'echo-binary' New-Variable -Option Constant -Scope 'script' -Name 'EchoStructuredType' -Value 'echo-structured' -New-Variable -Option Constant -Scope 'script' -Name 'ServerStopType' -Value 'server-stop' \ No newline at end of file +New-Variable -Option Constant -Scope 'script' -Name 'ServerStopType' -Value 'server-stop' +New-Variable -Option Constant -Scope 'script' -Name 'ServerPingType' -Value 'server-ping' \ No newline at end of file diff --git a/test/unit/ConvertFrom-HttpMessage.Tests.ps1 b/test/unit/ConvertFrom-HttpMessage.Tests.ps1 index 145338f..fb6bc6d 100644 --- a/test/unit/ConvertFrom-HttpMessage.Tests.ps1 +++ b/test/unit/ConvertFrom-HttpMessage.Tests.ps1 @@ -30,7 +30,7 @@ Describe "ConvertFrom-HttpMessage Function Tests" { 'Content-Type' = @($expectedDataContentType, 'charset=utf-8') 'ce-specversion' = $expectedSpecVersion 'ce-type' = $expectedType - 'ce-time' = $expectedTime.ToString("u") + 'ce-time' = $expectedTime.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') 'ce-id' = $expectedId 'ce-source' = $expectedSource } @@ -139,7 +139,7 @@ Describe "ConvertFrom-HttpMessage Function Tests" { $structuredJsonBody = @{ 'specversion' = $expectedSpecVersion 'type' = $expectedType - 'time' = $expectedTime.ToString("u") + 'time' = $expectedTime.ToString('yyyy-MM-ddTHH:mm:ss.fffZ') 'id' = $expectedId 'source' = $expectedSource 'datacontenttype' = $expectedDataContentType diff --git a/test/unit/ConvertTo-HttpMessage.Tests.ps1 b/test/unit/ConvertTo-HttpMessage.Tests.ps1 index 7cec0e1..aa7b697 100644 --- a/test/unit/ConvertTo-HttpMessage.Tests.ps1 +++ b/test/unit/ConvertTo-HttpMessage.Tests.ps1 @@ -16,7 +16,7 @@ Describe "ConvertTo-HttpMessage Function Tests" { $expectedType = 'test' $expectedSource = 'urn:test' $expectedId = 'test-id-1' - $expectedTime = Get-Date -Year 2021 -Month 1 -Day 18 -Hour 12 -Minute 30 -Second 0 + $expectedTime = Get-Date -Year 2021 -Month 1 -Day 18 -Hour 12 -Minute 30 -Second 0 -Millisecond 0 $expectedDataContentType = 'application/json' $cloudEvent = New-CloudEvent ` @@ -44,7 +44,7 @@ Describe "ConvertTo-HttpMessage Function Tests" { $actual.Headers['ce-source'] | Should -Be $expectedSource $actual.Headers['ce-specversion'] | Should -Be $expectedSpecVersion $actual.Headers['ce-type'] | Should -Be $expectedType - $actual.Headers['ce-time'] | Should -Be '2021-01-18 12:30:00Z' + $actual.Headers['ce-time'] | Should -Be ($expectedTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')) $actual.Headers['ce-id'] | Should -Be $expectedId ## Assert Body @@ -110,7 +110,7 @@ Describe "ConvertTo-HttpMessage Function Tests" { $expectedType = 'test' $expectedSource = 'urn:test' $expectedId = 'test-id-1' - $expectedTime = Get-Date -Year 2021 -Month 1 -Day 18 -Hour 12 -Minute 30 -Second 0 + $expectedTime = Get-Date -Year 2021 -Month 1 -Day 18 -Hour 12 -Minute 30 -Second 0 -Millisecond 0 $expectedDataContentType = 'application/json' $cloudEvent = New-CloudEvent ` @@ -141,7 +141,7 @@ Describe "ConvertTo-HttpMessage Function Tests" { $actual.Headers['ce-source'] | Should -Be $expectedSource $actual.Headers['ce-specversion'] | Should -Be $expectedSpecVersion $actual.Headers['ce-type'] | Should -Be $expectedType - $actual.Headers['ce-time'] | Should -Be '2021-01-18 12:30:00Z' + $actual.Headers['ce-time'] | Should -Be ($expectedTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')) $actual.Headers['ce-id'] | Should -Be $expectedId ## Assert Body