671 lines
26 KiB
PowerShell
671 lines
26 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[string[]]$Clients = @("dotnet", "go", "rust", "python", "java"),
|
|
[int]$MachineStart = 1,
|
|
[int]$MachineEnd = 20,
|
|
[string[]]$Attributes = @(
|
|
"ProtectedValue",
|
|
"TestChangingInt",
|
|
"TestBoolArray",
|
|
"TestIntArray",
|
|
"TestDateTimeArray",
|
|
"TestStringArray"
|
|
),
|
|
[string]$Endpoint = "localhost:5000",
|
|
[string]$ApiKeyEnv = "MXGATEWAY_API_KEY",
|
|
[string]$SqlServer = "localhost",
|
|
[string]$Database = "ZB",
|
|
[int]$EventLimit = 5,
|
|
[int]$BulkTagCount = 6,
|
|
[switch]$SkipStream,
|
|
[switch]$SkipBulk,
|
|
[switch]$DryRun,
|
|
[string]$ReportPath
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
|
$discoveryScript = Join-Path $PSScriptRoot "discover-testmachine-tags.ps1"
|
|
$validClients = @("dotnet", "go", "rust", "python", "java")
|
|
$Clients = @($Clients | ForEach-Object {
|
|
$_ -split ","
|
|
} | ForEach-Object {
|
|
$_.Trim().ToLowerInvariant()
|
|
} | Where-Object {
|
|
-not [string]::IsNullOrWhiteSpace($_)
|
|
})
|
|
$Attributes = @($Attributes | ForEach-Object {
|
|
$_ -split ","
|
|
} | ForEach-Object {
|
|
$_.Trim()
|
|
} | Where-Object {
|
|
-not [string]::IsNullOrWhiteSpace($_)
|
|
})
|
|
|
|
if ($Clients.Count -eq 0) {
|
|
throw "At least one client is required."
|
|
}
|
|
|
|
if ($Attributes.Count -eq 0) {
|
|
throw "At least one attribute is required."
|
|
}
|
|
|
|
if ($BulkTagCount -lt 1) {
|
|
throw "BulkTagCount must be greater than zero."
|
|
}
|
|
|
|
foreach ($client in $Clients) {
|
|
if ($validClients -notcontains $client) {
|
|
throw "Unsupported client '$client'. Supported clients: $($validClients -join ', ')."
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($ReportPath)) {
|
|
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
$ReportPath = Join-Path $repoRoot "artifacts/e2e/testmachine-client-e2e-$timestamp.json"
|
|
}
|
|
|
|
function ConvertTo-HttpEndpoint {
|
|
param([string]$Value)
|
|
|
|
if ($Value.StartsWith("http://", [StringComparison]::OrdinalIgnoreCase) -or
|
|
$Value.StartsWith("https://", [StringComparison]::OrdinalIgnoreCase)) {
|
|
return $Value
|
|
}
|
|
|
|
return "http://$Value"
|
|
}
|
|
|
|
function ConvertTo-HostEndpoint {
|
|
param([string]$Value)
|
|
|
|
$hostValue = $Value
|
|
if ($hostValue.StartsWith("http://", [StringComparison]::OrdinalIgnoreCase)) {
|
|
$hostValue = $hostValue.Substring(7)
|
|
} elseif ($hostValue.StartsWith("https://", [StringComparison]::OrdinalIgnoreCase)) {
|
|
$hostValue = $hostValue.Substring(8)
|
|
}
|
|
|
|
return $hostValue.TrimEnd("/")
|
|
}
|
|
|
|
function Join-CommandLine {
|
|
param(
|
|
[string]$FilePath,
|
|
[string[]]$Arguments
|
|
)
|
|
|
|
$parts = @($FilePath) + $Arguments
|
|
return ($parts | ForEach-Object { ConvertTo-NativeArgument -Value $_ }) -join " "
|
|
}
|
|
|
|
function ConvertTo-NativeArgument {
|
|
param([string]$Value)
|
|
|
|
if ($Value -notmatch '[\s"]') {
|
|
return $Value
|
|
}
|
|
|
|
return '"' + $Value.Replace('\', '\\').Replace('"', '\"') + '"'
|
|
}
|
|
|
|
function Invoke-NativeCommand {
|
|
param(
|
|
[string]$FilePath,
|
|
[string[]]$Arguments,
|
|
[string]$WorkingDirectory,
|
|
[hashtable]$Environment = @{}
|
|
)
|
|
|
|
$process = [System.Diagnostics.Process]::new()
|
|
$process.StartInfo.FileName = $FilePath
|
|
$process.StartInfo.Arguments = ($Arguments | ForEach-Object {
|
|
ConvertTo-NativeArgument -Value $_
|
|
}) -join " "
|
|
$process.StartInfo.WorkingDirectory = $WorkingDirectory
|
|
$process.StartInfo.RedirectStandardOutput = $true
|
|
$process.StartInfo.RedirectStandardError = $true
|
|
$process.StartInfo.UseShellExecute = $false
|
|
foreach ($entry in $Environment.GetEnumerator()) {
|
|
$process.StartInfo.Environment[$entry.Key] = [string]$entry.Value
|
|
}
|
|
|
|
$commandLine = Join-CommandLine -FilePath $FilePath -Arguments $Arguments
|
|
if ($DryRun) {
|
|
Write-Host "[dry-run] $commandLine"
|
|
return [pscustomobject]@{
|
|
commandLine = $commandLine
|
|
exitCode = 0
|
|
stdout = "{}"
|
|
stderr = ""
|
|
}
|
|
}
|
|
|
|
[void]$process.Start()
|
|
$stdout = $process.StandardOutput.ReadToEnd()
|
|
$stderr = $process.StandardError.ReadToEnd()
|
|
$process.WaitForExit()
|
|
|
|
$result = [pscustomobject]@{
|
|
commandLine = $commandLine
|
|
exitCode = $process.ExitCode
|
|
stdout = $stdout
|
|
stderr = $stderr
|
|
}
|
|
|
|
if ($result.exitCode -ne 0) {
|
|
throw "Command failed with exit code $($result.exitCode): $commandLine`n$stderr`n$stdout"
|
|
}
|
|
|
|
return $result
|
|
}
|
|
|
|
function Read-JsonObject {
|
|
param([string]$Text)
|
|
|
|
if ([string]::IsNullOrWhiteSpace($Text)) {
|
|
return $null
|
|
}
|
|
|
|
try {
|
|
return $Text | ConvertFrom-Json
|
|
} catch {
|
|
$jsonLines = @()
|
|
foreach ($line in ($Text -split "`r?`n")) {
|
|
$trimmed = $line.Trim()
|
|
if ($trimmed.StartsWith("{") -and $trimmed.EndsWith("}")) {
|
|
$jsonLines += ($trimmed | ConvertFrom-Json)
|
|
}
|
|
}
|
|
return $jsonLines
|
|
}
|
|
}
|
|
|
|
function Get-OpenSessionId {
|
|
param(
|
|
[string]$Client,
|
|
[object]$Json
|
|
)
|
|
|
|
switch ($Client) {
|
|
"dotnet" { return $Json.sessionId }
|
|
"go" { return $Json.reply.sessionId }
|
|
"rust" { return $Json.sessionId }
|
|
"python" { return $Json.sessionId }
|
|
"java" { return $Json.reply.sessionId }
|
|
}
|
|
}
|
|
|
|
function Get-ServerHandle {
|
|
param(
|
|
[string]$Client,
|
|
[object]$Json
|
|
)
|
|
|
|
switch ($Client) {
|
|
"dotnet" { return [int]$Json.register.serverHandle }
|
|
"go" { return [int]$Json.reply.register.serverHandle }
|
|
"rust" { return [int]$Json.serverHandle }
|
|
"python" { return [int]$Json.serverHandle }
|
|
"java" { return [int]$Json.reply.register.serverHandle }
|
|
}
|
|
}
|
|
|
|
function Get-ItemHandle {
|
|
param(
|
|
[string]$Client,
|
|
[object]$Json
|
|
)
|
|
|
|
switch ($Client) {
|
|
"dotnet" { return [int]$Json.addItem.itemHandle }
|
|
"go" { return [int]$Json.reply.addItem.itemHandle }
|
|
"rust" { return [int]$Json.itemHandle }
|
|
"python" { return [int]$Json.itemHandle }
|
|
"java" { return [int]$Json.reply.addItem.itemHandle }
|
|
}
|
|
}
|
|
|
|
function Get-StreamEventCount {
|
|
param(
|
|
[string]$Client,
|
|
[object]$Json
|
|
)
|
|
|
|
switch ($Client) {
|
|
"dotnet" { return @($Json.events).Count }
|
|
"go" { return @($Json).Count }
|
|
"rust" { return [int]$Json.eventCount }
|
|
"python" { return @($Json.events).Count }
|
|
"java" { return @($Json).Count }
|
|
}
|
|
}
|
|
|
|
function Get-PropertyValue {
|
|
param(
|
|
[object]$Object,
|
|
[string[]]$Names
|
|
)
|
|
|
|
if ($null -eq $Object) {
|
|
return $null
|
|
}
|
|
|
|
foreach ($name in $Names) {
|
|
$property = $Object.PSObject.Properties[$name]
|
|
if ($null -ne $property) {
|
|
return $property.Value
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Get-BulkResults {
|
|
param(
|
|
[string]$Client,
|
|
[string]$Operation,
|
|
[object]$Json
|
|
)
|
|
|
|
if ($Client -in @("go", "rust", "python", "java")) {
|
|
return @(Get-PropertyValue -Object $Json -Names @("results"))
|
|
}
|
|
|
|
$replyName = if ($Operation -eq "subscribe-bulk") { "subscribeBulk" } else { "unsubscribeBulk" }
|
|
$reply = Get-PropertyValue -Object $Json -Names @($replyName)
|
|
return @(Get-PropertyValue -Object $reply -Names @("results"))
|
|
}
|
|
|
|
function Get-BulkItemHandles {
|
|
param([object[]]$Results)
|
|
|
|
return @($Results | ForEach-Object {
|
|
[int](Get-PropertyValue -Object $_ -Names @("itemHandle", "item_handle"))
|
|
} | Where-Object {
|
|
$_ -gt 0
|
|
})
|
|
}
|
|
|
|
function Assert-BulkResults {
|
|
param(
|
|
[string]$Client,
|
|
[string]$Operation,
|
|
[object[]]$Results,
|
|
[int]$ExpectedCount
|
|
)
|
|
|
|
if ($Results.Count -ne $ExpectedCount) {
|
|
throw "$Client $Operation returned $($Results.Count) result(s); expected $ExpectedCount."
|
|
}
|
|
|
|
foreach ($result in $Results) {
|
|
$success = Get-PropertyValue -Object $result -Names @("wasSuccessful", "was_successful")
|
|
if ($null -ne $success -and -not [bool]$success) {
|
|
$tagAddress = Get-PropertyValue -Object $result -Names @("tagAddress", "tag_address")
|
|
$errorMessage = Get-PropertyValue -Object $result -Names @("errorMessage", "error_message")
|
|
throw "$Client $Operation failed for '$tagAddress': $errorMessage"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-ClientCommand {
|
|
param(
|
|
[string]$Client,
|
|
[string]$Operation,
|
|
[hashtable]$Values
|
|
)
|
|
|
|
$httpEndpoint = ConvertTo-HttpEndpoint -Value $Endpoint
|
|
$hostEndpoint = ConvertTo-HostEndpoint -Value $Endpoint
|
|
$clientName = "mxgw-$Client-e2e"
|
|
|
|
switch ($Client) {
|
|
"dotnet" {
|
|
$arguments = @(
|
|
"run", "--project", "clients/dotnet/MxGateway.Client.Cli", "--",
|
|
$Operation,
|
|
"--endpoint", $httpEndpoint,
|
|
"--api-key-env", $ApiKeyEnv,
|
|
"--timeout", "60s",
|
|
"--json"
|
|
)
|
|
if ($Operation -eq "open-session") {
|
|
$arguments += @("--client-name", $clientName)
|
|
} elseif ($Operation -eq "register") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--client-name", $clientName)
|
|
} elseif ($Operation -eq "add-item") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item", $Values.item)
|
|
} elseif ($Operation -eq "advise") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handle", "$($Values.itemHandle)")
|
|
} elseif ($Operation -eq "subscribe-bulk") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--items", $Values.items)
|
|
} elseif ($Operation -eq "unsubscribe-bulk") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handles", $Values.itemHandles)
|
|
} elseif ($Operation -eq "stream-events") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--max-events", "$EventLimit")
|
|
} elseif ($Operation -eq "close-session") {
|
|
$arguments += @("--session-id", $Values.sessionId)
|
|
}
|
|
return [pscustomobject]@{ file = "dotnet"; args = $arguments; cwd = $repoRoot; env = @{} }
|
|
}
|
|
"go" {
|
|
$arguments = @(
|
|
"run", "./cmd/mxgw-go", $Operation,
|
|
"-endpoint", $hostEndpoint,
|
|
"-api-key-env", $ApiKeyEnv,
|
|
"-plaintext",
|
|
"-json"
|
|
)
|
|
if ($Operation -eq "open-session") {
|
|
$arguments += @("-client-session-name", $clientName)
|
|
} elseif ($Operation -eq "register") {
|
|
$arguments += @("-session-id", $Values.sessionId, "-client-name", $clientName)
|
|
} elseif ($Operation -eq "add-item") {
|
|
$arguments += @("-session-id", $Values.sessionId, "-server-handle", "$($Values.serverHandle)", "-item", $Values.item)
|
|
} elseif ($Operation -eq "advise") {
|
|
$arguments += @("-session-id", $Values.sessionId, "-server-handle", "$($Values.serverHandle)", "-item-handle", "$($Values.itemHandle)")
|
|
} elseif ($Operation -eq "subscribe-bulk") {
|
|
$arguments += @("-session-id", $Values.sessionId, "-server-handle", "$($Values.serverHandle)", "-items", $Values.items)
|
|
} elseif ($Operation -eq "unsubscribe-bulk") {
|
|
$arguments += @("-session-id", $Values.sessionId, "-server-handle", "$($Values.serverHandle)", "-item-handles", $Values.itemHandles)
|
|
} elseif ($Operation -eq "stream-events") {
|
|
$arguments += @("-session-id", $Values.sessionId, "-limit", "$EventLimit")
|
|
} elseif ($Operation -eq "close-session") {
|
|
$arguments += @("-session-id", $Values.sessionId)
|
|
}
|
|
return [pscustomobject]@{ file = "go"; args = $arguments; cwd = (Join-Path $repoRoot "clients/go"); env = @{} }
|
|
}
|
|
"rust" {
|
|
$arguments = @(
|
|
"run", "-p", "mxgw-cli", "--", $Operation,
|
|
"--endpoint", $httpEndpoint,
|
|
"--api-key-env", $ApiKeyEnv,
|
|
"--json"
|
|
)
|
|
if ($Operation -eq "open-session") {
|
|
$arguments += @("--client-name", $clientName)
|
|
} elseif ($Operation -eq "register") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--client-name", $clientName)
|
|
} elseif ($Operation -eq "add-item") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item", $Values.item)
|
|
} elseif ($Operation -eq "advise") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handle", "$($Values.itemHandle)")
|
|
} elseif ($Operation -eq "subscribe-bulk") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--items", $Values.items)
|
|
} elseif ($Operation -eq "unsubscribe-bulk") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handles", $Values.itemHandles)
|
|
} elseif ($Operation -eq "stream-events") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--max-events", "$EventLimit")
|
|
} elseif ($Operation -eq "close-session") {
|
|
$arguments += @("--session-id", $Values.sessionId)
|
|
}
|
|
return [pscustomobject]@{ file = "cargo"; args = $arguments; cwd = (Join-Path $repoRoot "clients/rust"); env = @{} }
|
|
}
|
|
"python" {
|
|
$arguments = @(
|
|
"-m", "mxgateway_cli", $Operation,
|
|
"--endpoint", $hostEndpoint,
|
|
"--api-key-env", $ApiKeyEnv,
|
|
"--plaintext",
|
|
"--json"
|
|
)
|
|
if ($Operation -eq "open-session") {
|
|
$arguments += @("--client-name", $clientName)
|
|
} elseif ($Operation -eq "register") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--client-name", $clientName)
|
|
} elseif ($Operation -eq "add-item") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item", $Values.item)
|
|
} elseif ($Operation -eq "advise") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handle", "$($Values.itemHandle)")
|
|
} elseif ($Operation -eq "subscribe-bulk") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--items", $Values.items)
|
|
} elseif ($Operation -eq "unsubscribe-bulk") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handles", $Values.itemHandles)
|
|
} elseif ($Operation -eq "stream-events") {
|
|
$arguments += @("--session-id", $Values.sessionId, "--max-events", "$EventLimit", "--timeout", "15")
|
|
} elseif ($Operation -eq "close-session") {
|
|
$arguments += @("--session-id", $Values.sessionId)
|
|
}
|
|
$env = @{
|
|
PYTHONPATH = Join-Path $repoRoot "clients/python/src"
|
|
}
|
|
return [pscustomobject]@{ file = "py"; args = @("-3.12") + $arguments; cwd = (Join-Path $repoRoot "clients/python"); env = $env }
|
|
}
|
|
"java" {
|
|
$cliArgs = @(
|
|
$Operation,
|
|
"--endpoint", $hostEndpoint,
|
|
"--api-key-env", $ApiKeyEnv,
|
|
"--plaintext",
|
|
"--json"
|
|
)
|
|
if ($Operation -eq "open-session") {
|
|
$cliArgs += @("--client-session-name", $clientName)
|
|
} elseif ($Operation -eq "register") {
|
|
$cliArgs += @("--session-id", $Values.sessionId, "--client-name", $clientName)
|
|
} elseif ($Operation -eq "add-item") {
|
|
$cliArgs += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item", $Values.item)
|
|
} elseif ($Operation -eq "advise") {
|
|
$cliArgs += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handle", "$($Values.itemHandle)")
|
|
} elseif ($Operation -eq "subscribe-bulk") {
|
|
$cliArgs += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--items", $Values.items)
|
|
} elseif ($Operation -eq "unsubscribe-bulk") {
|
|
$cliArgs += @("--session-id", $Values.sessionId, "--server-handle", "$($Values.serverHandle)", "--item-handles", $Values.itemHandles)
|
|
} elseif ($Operation -eq "stream-events") {
|
|
$cliArgs += @("--session-id", $Values.sessionId, "--limit", "$EventLimit")
|
|
} elseif ($Operation -eq "close-session") {
|
|
$cliArgs += @("--session-id", $Values.sessionId)
|
|
}
|
|
$arguments = @("--quiet", ":mxgateway-cli:run", "--args=$($cliArgs -join ' ')")
|
|
return [pscustomobject]@{ file = "gradle"; args = $arguments; cwd = (Join-Path $repoRoot "clients/java"); env = @{} }
|
|
}
|
|
}
|
|
}
|
|
|
|
function Invoke-ClientOperation {
|
|
param(
|
|
[string]$Client,
|
|
[string]$Operation,
|
|
[hashtable]$Values = @{}
|
|
)
|
|
|
|
$command = Get-ClientCommand -Client $Client -Operation $Operation -Values $Values
|
|
$result = Invoke-NativeCommand `
|
|
-FilePath $command.file `
|
|
-Arguments $command.args `
|
|
-WorkingDirectory $command.cwd `
|
|
-Environment $command.env
|
|
if ($DryRun) {
|
|
switch ($Operation) {
|
|
"open-session" { return [pscustomobject]@{ sessionId = "dry-run-session-$Client"; reply = [pscustomobject]@{ sessionId = "dry-run-session-$Client" } } }
|
|
"register" { return [pscustomobject]@{ serverHandle = 1; register = [pscustomobject]@{ serverHandle = 1 }; reply = [pscustomobject]@{ register = [pscustomobject]@{ serverHandle = 1 } } } }
|
|
"add-item" { return [pscustomobject]@{ itemHandle = 1; addItem = [pscustomobject]@{ itemHandle = 1 }; reply = [pscustomobject]@{ addItem = [pscustomobject]@{ itemHandle = 1 } } } }
|
|
"subscribe-bulk" {
|
|
$results = @($Values.items -split "," | ForEach-Object -Begin { $index = 1 } -Process {
|
|
[pscustomobject]@{ itemHandle = $index++; tagAddress = $_; wasSuccessful = $true }
|
|
})
|
|
return [pscustomobject]@{ subscribeBulk = [pscustomobject]@{ results = $results }; results = $results }
|
|
}
|
|
"unsubscribe-bulk" {
|
|
$results = @($Values.itemHandles -split "," | ForEach-Object {
|
|
[pscustomobject]@{ itemHandle = [int]$_; wasSuccessful = $true }
|
|
})
|
|
return [pscustomobject]@{ unsubscribeBulk = [pscustomobject]@{ results = $results }; results = $results }
|
|
}
|
|
"stream-events" { return [pscustomobject]@{ eventCount = 1; events = @([pscustomobject]@{ workerSequence = 1 }) } }
|
|
default { return [pscustomobject]@{ ok = $true; reply = [pscustomobject]@{} } }
|
|
}
|
|
}
|
|
return Read-JsonObject -Text $result.stdout
|
|
}
|
|
|
|
$discoveryJson = & $discoveryScript `
|
|
-MachineStart $MachineStart `
|
|
-MachineEnd $MachineEnd `
|
|
-Attributes $Attributes `
|
|
-SqlServer $SqlServer `
|
|
-Database $Database `
|
|
-Json
|
|
$convertedTags = $discoveryJson | ConvertFrom-Json
|
|
$tags = @($convertedTags)
|
|
if ($tags.Count -eq 1 -and $tags[0] -is [System.Array]) {
|
|
$tags = @($tags[0])
|
|
}
|
|
$expectedTagCount = (($MachineEnd - $MachineStart + 1) * $Attributes.Count)
|
|
|
|
if ($tags.Count -ne $expectedTagCount) {
|
|
$found = $tags | Group-Object -Property tagName | ForEach-Object {
|
|
"$($_.Name)=$($_.Count)"
|
|
}
|
|
throw "Expected $expectedTagCount discovered test tags, found $($tags.Count): $($found -join ', ')"
|
|
}
|
|
|
|
$run = [ordered]@{
|
|
schemaVersion = 1
|
|
endpoint = $Endpoint
|
|
apiKeyEnv = $ApiKeyEnv
|
|
machineStart = $MachineStart
|
|
machineEnd = $MachineEnd
|
|
attributes = $Attributes
|
|
eventLimit = $EventLimit
|
|
bulkTagCount = $BulkTagCount
|
|
skipStream = [bool]$SkipStream
|
|
skipBulk = [bool]$SkipBulk
|
|
startedAt = (Get-Date).ToUniversalTime().ToString("O")
|
|
discoveredTags = $tags
|
|
clients = @()
|
|
}
|
|
|
|
$hadFailure = $false
|
|
|
|
foreach ($client in $Clients) {
|
|
Write-Host "Running $client client e2e flow against $($tags.Count) discovered tags."
|
|
$sessionId = $null
|
|
$serverHandle = $null
|
|
$clientResult = [ordered]@{
|
|
language = $client
|
|
sessionId = $null
|
|
serverHandle = $null
|
|
bulk = $null
|
|
addedItems = @()
|
|
eventCount = 0
|
|
closed = $false
|
|
error = $null
|
|
}
|
|
|
|
try {
|
|
$openJson = Invoke-ClientOperation -Client $client -Operation "open-session"
|
|
$sessionId = Get-OpenSessionId -Client $client -Json $openJson
|
|
if ([string]::IsNullOrWhiteSpace($sessionId)) {
|
|
throw "The $client open-session command did not return a session id."
|
|
}
|
|
$clientResult.sessionId = $sessionId
|
|
|
|
$registerJson = Invoke-ClientOperation -Client $client -Operation "register" -Values @{
|
|
sessionId = $sessionId
|
|
}
|
|
$serverHandle = Get-ServerHandle -Client $client -Json $registerJson
|
|
$clientResult.serverHandle = $serverHandle
|
|
|
|
if (-not $SkipBulk) {
|
|
$bulkTags = @($tags | Select-Object -First ([Math]::Min($BulkTagCount, $tags.Count)))
|
|
$bulkItems = ($bulkTags | ForEach-Object { $_.fullTagReference }) -join ","
|
|
$subscribeBulkJson = Invoke-ClientOperation -Client $client -Operation "subscribe-bulk" -Values @{
|
|
sessionId = $sessionId
|
|
serverHandle = $serverHandle
|
|
items = $bulkItems
|
|
}
|
|
$subscribeResults = @(Get-BulkResults -Client $client -Operation "subscribe-bulk" -Json $subscribeBulkJson)
|
|
Assert-BulkResults -Client $client -Operation "subscribe-bulk" -Results $subscribeResults -ExpectedCount $bulkTags.Count
|
|
$bulkItemHandles = @(Get-BulkItemHandles -Results $subscribeResults)
|
|
if ($bulkItemHandles.Count -ne $bulkTags.Count) {
|
|
throw "$client subscribe-bulk returned $($bulkItemHandles.Count) usable item handle(s); expected $($bulkTags.Count)."
|
|
}
|
|
|
|
$unsubscribeBulkJson = Invoke-ClientOperation -Client $client -Operation "unsubscribe-bulk" -Values @{
|
|
sessionId = $sessionId
|
|
serverHandle = $serverHandle
|
|
itemHandles = $bulkItemHandles -join ","
|
|
}
|
|
$unsubscribeResults = @(Get-BulkResults -Client $client -Operation "unsubscribe-bulk" -Json $unsubscribeBulkJson)
|
|
Assert-BulkResults -Client $client -Operation "unsubscribe-bulk" -Results $unsubscribeResults -ExpectedCount $bulkItemHandles.Count
|
|
|
|
$clientResult.bulk = [ordered]@{
|
|
tagCount = $bulkTags.Count
|
|
subscribedCount = $subscribeResults.Count
|
|
unsubscribedCount = $unsubscribeResults.Count
|
|
itemHandles = $bulkItemHandles
|
|
}
|
|
}
|
|
|
|
foreach ($tag in $tags) {
|
|
$addJson = Invoke-ClientOperation -Client $client -Operation "add-item" -Values @{
|
|
sessionId = $sessionId
|
|
serverHandle = $serverHandle
|
|
item = $tag.fullTagReference
|
|
}
|
|
$itemHandle = Get-ItemHandle -Client $client -Json $addJson
|
|
Invoke-ClientOperation -Client $client -Operation "advise" -Values @{
|
|
sessionId = $sessionId
|
|
serverHandle = $serverHandle
|
|
itemHandle = $itemHandle
|
|
} | Out-Null
|
|
|
|
$clientResult.addedItems += [ordered]@{
|
|
tagName = $tag.tagName
|
|
attributeName = $tag.attributeName
|
|
fullTagReference = $tag.fullTagReference
|
|
itemHandle = $itemHandle
|
|
protectedWriteRequired = $tag.attributeName -eq "ProtectedValue"
|
|
}
|
|
}
|
|
|
|
if (-not $SkipStream) {
|
|
$streamJson = Invoke-ClientOperation -Client $client -Operation "stream-events" -Values @{
|
|
sessionId = $sessionId
|
|
}
|
|
$clientResult.eventCount = Get-StreamEventCount -Client $client -Json $streamJson
|
|
if ($clientResult.eventCount -lt 1) {
|
|
throw "The $client stream-events command returned no events."
|
|
}
|
|
}
|
|
} catch {
|
|
$hadFailure = $true
|
|
$clientResult.error = $_.Exception.Message
|
|
Write-Warning "$client e2e flow failed: $($clientResult.error)"
|
|
} finally {
|
|
if (-not [string]::IsNullOrWhiteSpace($sessionId)) {
|
|
try {
|
|
Invoke-ClientOperation -Client $client -Operation "close-session" -Values @{
|
|
sessionId = $sessionId
|
|
} | Out-Null
|
|
$clientResult.closed = $true
|
|
} catch {
|
|
$hadFailure = $true
|
|
$clientResult.error = "$($clientResult.error) close-session failed: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
}
|
|
|
|
$run.clients += $clientResult
|
|
}
|
|
|
|
$run.completedAt = (Get-Date).ToUniversalTime().ToString("O")
|
|
$run.success = -not $hadFailure
|
|
|
|
if (-not $DryRun) {
|
|
$reportDirectory = Split-Path -Parent $ReportPath
|
|
if (-not [string]::IsNullOrWhiteSpace($reportDirectory)) {
|
|
New-Item -ItemType Directory -Path $reportDirectory -Force | Out-Null
|
|
}
|
|
$run | ConvertTo-Json -Depth 8 | Set-Content -Path $ReportPath -Encoding UTF8
|
|
Write-Host "Wrote e2e report to $ReportPath"
|
|
}
|
|
|
|
if ($hadFailure) {
|
|
exit 1
|
|
}
|