Files
jiapuapp/tests/lineage-openapi-contract.ps1
T
2026-07-28 07:58:30 +08:00

72 lines
3.6 KiB
PowerShell

$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$documents = @(Get-ChildItem -LiteralPath $root -File -Filter '*.openapi.json')
if ($documents.Count -ne 1) { throw 'Exactly one current OpenAPI JSON export is required at the repository root' }
$documentPath = $documents[0].FullName
$document = Get-Content -Raw -Encoding UTF8 -LiteralPath $documentPath | ConvertFrom-Json
function Get-Operation {
param([string]$Path, [string]$Method)
$pathProperty = $document.paths.PSObject.Properties[$Path]
if (-not $pathProperty) { throw "Missing lineage path: $Path" }
$operation = $pathProperty.Value.PSObject.Properties[$Method]
if (-not $operation) { throw "Missing lineage operation: $Method $Path" }
return $operation.Value
}
function Assert-ClientHeader {
param([object]$Operation, [string]$Label)
$clientId = @($Operation.parameters | Where-Object { $_.in -eq 'header' -and $_.name -eq 'clientid' -and $_.required -eq $true })
if ($clientId.Count -ne 1) { throw "$Label must require the clientid header" }
$hasSaToken = @($Operation.security | Where-Object { $_.PSObject.Properties.Name -contains 'SaToken' }).Count -gt 0
if (-not $hasSaToken) { throw "$Label must require SaToken" }
}
$listPath = '/genealogy/app/genealogies/{genealogyId}/lineage/persons'
$detailPath = '/genealogy/app/genealogies/{genealogyId}/lineage/persons/{personId}'
$pagePath = '/genealogy/app/genealogies/{genealogyId}/lineage/persons/page'
foreach ($target in @(
@{ Path = $listPath; Method = 'get' },
@{ Path = $listPath; Method = 'post' },
@{ Path = $detailPath; Method = 'get' },
@{ Path = $detailPath; Method = 'put' },
@{ Path = $pagePath; Method = 'get' }
)) {
$operation = Get-Operation -Path $target.Path -Method $target.Method
Assert-ClientHeader -Operation $operation -Label "$($target.Method.ToUpper()) $($target.Path)"
}
$create = Get-Operation -Path $listPath -Method 'post'
$requestSchema = $create.requestBody.content.'application/json'.schema
if ($requestSchema.'$ref' -ne '#/components/schemas/LineagePersonBody') {
throw 'Lineage person create must consume LineagePersonBody'
}
$body = $document.components.schemas.LineagePersonBody
if (@($body.required) -notcontains 'name') { throw 'LineagePersonBody must require name' }
foreach ($field in @('name', 'generation', 'appUserId', 'fatherId', 'motherId', 'avatarOssId', 'birthLunar', 'deathLunar', 'personStatus')) {
if (-not $body.properties.PSObject.Properties[$field]) { throw "LineagePersonBody is missing $field" }
}
$avatar = $body.properties.avatarOssId
if (($avatar.type -join ',') -ne 'string,null' -or $avatar.pattern -ne '^[1-9][0-9]*$') {
throw 'LineagePersonBody.avatarOssId must use the decimal string OSS ID contract'
}
foreach ($field in @('birthLunar', 'deathLunar', 'personStatus', 'sex')) {
$schema = $body.properties.$field
if ($schema.type -ne 'string') { throw "LineagePersonBody.$field must be a dictionary string" }
}
if ((@($body.properties.sex.enum) -join ',') -ne '0,1,2') { throw 'LineagePersonBody.sex must use 0,1,2' }
if ((@($body.properties.birthLunar.enum) -join ',') -ne '0,1') { throw 'LineagePersonBody.birthLunar must use 0,1' }
if ((@($body.properties.deathLunar.enum) -join ',') -ne '0,1') { throw 'LineagePersonBody.deathLunar must use 0,1' }
if ((@($body.properties.personStatus.enum) -join ',') -ne '0,1,2') { throw 'LineagePersonBody.personStatus must use 0,1,2' }
if ((@($body.required) -notcontains 'bindingMode' -or (@($body.properties.bindingMode.enum) -join ',') -ne 'NONE,SELF,SPECIFIED')) {
throw 'LineagePersonBody.bindingMode must be required and use NONE,SELF,SPECIFIED'
}
Write-Output 'LINEAGE-OPENAPI-CONTRACT PASS'