XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
param(
    [Parameter(Mandatory=$true)][string]$DataRoot,
    [string]$Address='http://127.0.0.1:48081/api/',
    [string]$Account
)
$ErrorActionPreference='Stop'
$taskAccess=Get-Content -LiteralPath (Join-Path $DataRoot 'admin-access.json') -Raw | ConvertFrom-Json
$taskResults=[Collections.Generic.List[object]]::new()
function Call-TaskApi([string]$Operation,$Arguments=@{},[string]$Token='', [int]$Expected=200) {
    $taskHeaders=@{}
    if($Token){$taskHeaders.Authorization='Bearer '+$Token}
    $taskResponse=Invoke-WebRequest -Uri ($Address+'control') -Method Post -ContentType 'application/json' -Headers $taskHeaders -Body (@{operation=$Operation;arguments=$Arguments} | ConvertTo-Json -Depth 80 -Compress) -SkipHttpErrorCheck
    if([int]$taskResponse.StatusCode -ne $Expected){throw ($Operation+' expected '+$Expected+', received '+$taskResponse.StatusCode+': '+$taskResponse.Content)}
    $taskResults.Add(@{operation=$Operation;expected=$Expected;passed=$true})
    ConvertFrom-Json -InputObject $taskResponse.Content -AsHashtable
}
function Check-Task([bool]$Condition,[string]$Name) {
    if(-not $Condition){throw ('Check failed: '+$Name)}
    $taskResults.Add(@{check=$Name;passed=$true})
}
try {
    $taskHealth=Invoke-RestMethod -Uri ($Address+'health')
    Check-Task ($taskHealth.framework -eq 'XFEExtension.NetCore.ServerInteractive') 'Real ServerInteractive HTTP listener'
    $null=Call-TaskApi 'profile' @{} '' 401
    $null=Call-TaskApi 'auth/local-owner' @{} 'invalid-local-key' 401
    $taskOwner=Call-TaskApi 'auth/local-owner' @{} $taskAccess.key
    $taskToken=$taskOwner.token
    $taskAccounts=Call-TaskApi 'accounts' @{} $taskToken
    if(-not $Account){$Account=@($taskAccounts | Where-Object {$_.email -ne 'local-owner@xfe.local'})[0].id}
    $taskInventory=Call-TaskApi 'commander' @{accountId=$Account} $taskToken
    $taskNative=Call-TaskApi 'native/export' @{accountId=$Account} $taskToken
    $taskCredits=[long]$taskInventory.credits+12345
    $null=Call-TaskApi 'inventory/edit' @{accountId=$Account;edit='credits';values=@{delta=12345};version=$taskInventory.version} $taskToken
    $null=Call-TaskApi 'inventory/edit' @{accountId=$Account;edit='credits';values=@{delta=1};version=$taskInventory.version} $taskToken 409
    $taskInventory=Call-TaskApi 'commander' @{accountId=$Account} $taskToken
    Check-Task ($taskInventory.credits -eq $taskCredits) 'Credit edit persisted without stale overwrite'
    $null=Call-TaskApi 'inventory/edit' @{accountId=$Account;edit='cargo';values=@{itemId='platinum';category='cargo';quantity=3};version=$taskInventory.version} $taskToken
    $taskInventory=Call-TaskApi 'commander' @{accountId=$Account} $taskToken
    $null=Call-TaskApi 'materials/prepare' @{accountId=$Account;version=$taskInventory.version} $taskToken
    $taskInventory=Call-TaskApi 'commander' @{accountId=$Account} $taskToken
    $taskCatalog=Call-TaskApi 'catalog' @{accountId=$Account;search=''} $taskToken
    $taskMaterial=@($taskCatalog | Where-Object {$_.category -in @('Raw','Encoded','Manufactured')})[0]
    Check-Task ($null -ne $taskMaterial) 'Native material catalogue is available'
    $null=Call-TaskApi 'inventory/edit' @{accountId=$Account;edit='materials';values=@{itemId=$taskMaterial.id;category=$taskMaterial.category;quantity=5};version=$taskInventory.version} $taskToken
    $taskInventory=Call-TaskApi 'commander' @{accountId=$Account} $taskToken
    $null=Call-TaskApi 'inventory/edit' @{accountId=$Account;edit='materials';values=@{itemId=$taskMaterial.id;category=$taskMaterial.category;quantity=1001};version=$taskInventory.version} $taskToken 400
    $taskAfter=Call-TaskApi 'commander' @{accountId=$Account} $taskToken
    Check-Task ($taskAfter.version -eq $taskInventory.version) 'Rejected material edit is atomic'
    $taskFleet=Call-TaskApi 'fleet' @{accountId=$Account} $taskToken
    $taskShip=@($taskFleet.ships | Where-Object {$_.active})[0]
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='clone';templateShipId=$taskShip.id;name='HTTP Test Ship';ident='HTTP-01';version=$taskAfter.version} $taskToken
    $taskFleet=Call-TaskApi 'fleet' @{accountId=$Account} $taskToken
    $taskClone=@($taskFleet.ships | Where-Object {$_.label.ident -eq 'HTTP-01'})[-1]
    Check-Task ($taskClone.id -ne $taskShip.id -and -not $taskClone.active) 'New private vessel has independent identity'
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='select';shipId=$taskClone.id;version=$taskFleet.commander.version} $taskToken
    $taskFleet=Call-TaskApi 'fleet' @{accountId=$Account} $taskToken
    Check-Task (@($taskFleet.ships | Where-Object {$_.active})[0].id -eq $taskClone.id) 'Active vessel selection persisted'
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='remove';shipId=$taskClone.id;version=$taskFleet.commander.version} $taskToken 400
    $taskWeapon=@($taskClone.slots | Where-Object {$_.name -match 'Hardpoint' -and $null -ne $_.module})[0]
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='store';shipId=$taskClone.id;slot=$taskWeapon.name;version=$taskFleet.commander.version} $taskToken
    $taskFleet=Call-TaskApi 'fleet' @{accountId=$Account} $taskToken
    $taskStored=@($taskFleet.stored)[-1]
    Check-Task ($taskStored.module.name -eq $taskWeapon.module.name) 'Weapon moved into persistent module warehouse'
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='retrieve';shipId=$taskClone.id;slot=$taskWeapon.name;storageId=$taskStored.slotId;version=$taskFleet.commander.version} $taskToken
    $taskFleet=Call-TaskApi 'fleet' @{accountId=$Account} $taskToken
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='module';shipId=$taskClone.id;slot='PowerPlant';module=$taskWeapon.module.name;version=$taskFleet.commander.version} $taskToken 400
    $taskExport=Call-TaskApi 'native/export' @{accountId=$Account} $taskToken
    Check-Task ($taskExport.snapshot.credits -eq $taskCredits) 'Native snapshot contains edited credits'
    Check-Task (@($taskExport.materials | Where-Object {$_.id.ToString() -eq $taskMaterial.id})[0].quantity -eq 5) 'Native material quantity survives fleet edits'
    $taskOriginal=@($taskExport.snapshot.vessels | Where-Object {$_.id -eq $taskShip.id})[0]
    Check-Task (@($taskOriginal.cargo | Where-Object {$_.commodity -eq 'platinum' -and $_.quantity -eq 3}).Count -gt 0) 'Native cargo contains authored warehouse item'
    $taskEmail='integration-'+[Guid]::NewGuid().ToString('N')+'@example.invalid'
    $taskPassword=[Guid]::NewGuid().ToString('N')
    $null=Call-TaskApi 'auth/register' @{email=$taskEmail;name='HTTP Player';password=$taskPassword}
    $taskPlayer=Call-TaskApi 'auth/login' @{email=$taskEmail;password=$taskPassword}
    $null=Call-TaskApi 'accounts' @{} $taskPlayer.token 403
    $null=Call-TaskApi 'commander' @{accountId=$Account} $taskPlayer.token 403
    $null=Call-TaskApi 'fleet/edit' @{accountId=$Account;action='clone';templateShipId=$taskShip.id;name='Forbidden';ident='NO';version=$taskFleet.commander.version} $taskPlayer.token 403
    $null=Call-TaskApi 'auth/logout' @{} $taskPlayer.token
    $null=Call-TaskApi 'profile' @{} $taskPlayer.token 401
    $null=Call-TaskApi 'auth/logout' @{} $taskToken
    [IO.File]::WriteAllText((Join-Path $DataRoot 'integration-report.json'),(@{passed=$true;checks=$taskResults;account=$Account;expectedCredits=$taskCredits;materialId=$taskMaterial.id;selectedShipId=$taskClone.id} | ConvertTo-Json -Depth 8),[Text.UTF8Encoding]::new($false))
    Write-Output ('PASS '+$taskResults.Count+' real HTTP checks: authentication, roles, credits, cargo, materials, fleet, module storage, conflicts and atomic rejection.')
} catch {
    [IO.File]::WriteAllText((Join-Path $DataRoot 'integration-report.json'),(@{passed=$false;checks=$taskResults;error=$_.Exception.Message} | ConvertTo-Json -Depth 8),[Text.UTF8Encoding]::new($false))
    throw
}