| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- # Full profile domain simulation validation (Plan B P0-P3)
- param(
- [string]$ApiBase = "http://127.0.0.1:8006",
- [int]$CompanyId = 338,
- [int]$TenantId = 33,
- [string]$OpsSecret = "lobster-dev-ops",
- [switch]$SkipFullEngine
- )
- $ErrorActionPreference = "Stop"
- try {
- [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
- $OutputEncoding = [System.Text.Encoding]::UTF8
- } catch { }
- $utf8NoBom = New-Object System.Text.UTF8Encoding $false
- $reportDir = Join-Path $PSScriptRoot "reports"
- if (-not (Test-Path $reportDir)) { New-Item -ItemType Directory -Path $reportDir | Out-Null }
- $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
- $reportFile = Join-Path $reportDir "lobster-profile-full-validation-$stamp.json"
- $headers = @{
- "Content-Type" = "application/json"
- "X-Lobster-Ops-Secret" = $OpsSecret
- }
- Write-Host "=== Profile Domain Full Simulation Validation ===" -ForegroundColor Cyan
- Write-Host "ApiBase=$ApiBase CompanyId=$CompanyId TenantId=$TenantId"
- function Wait-Service {
- param([string]$Base, [int]$MaxSec = 120)
- $deadline = (Get-Date).AddSeconds($MaxSec)
- while ((Get-Date) -lt $deadline) {
- try {
- Invoke-RestMethod -Uri "$Base/api/lobster/admin/phase2/verify/$CompanyId?tenantId=$TenantId" -Headers $headers -TimeoutSec 10 | Out-Null
- Write-Host "OK service reachable" -ForegroundColor Green
- return $true
- } catch {
- Start-Sleep -Seconds 3
- }
- }
- Write-Host "FAIL service not reachable at $Base" -ForegroundColor Red
- return $false
- }
- if (-not (Wait-Service $ApiBase)) { exit 1 }
- $summary = [ordered]@{}
- $failures = New-Object System.Collections.Generic.List[string]
- # 1) Basic profile domain probe
- Write-Host "`n[1/4] profile-domain basic..." -ForegroundColor Yellow
- $basicUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/profile-domain/${CompanyId}?tenantId=${TenantId}"
- $basic = Invoke-RestMethod -Uri $basicUri -Method Post -Headers $headers -TimeoutSec 120
- $summary.basic = $basic
- if (-not $basic.passed) { $failures.Add("basic: $($basic.message)") }
- Write-Host " passed=$($basic.passed) mode=$($basic.projectionMode) beansOk=$($basic.beansOk)"
- # 2) Full simulation (write smoke + backfill sample)
- Write-Host "`n[2/4] profile-domain-full simulation..." -ForegroundColor Yellow
- $fullUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/profile-domain-full/${CompanyId}?tenantId=${TenantId}"
- $full = Invoke-RestMethod -Uri $fullUri -Method Post -Headers $headers -TimeoutSec 300
- $summary.fullSimulation = $full
- if (-not $full.passed) { $failures.Add("fullSimulation: $($full.message)") }
- if ($full.runtime) {
- Write-Host " identityCount=$($full.runtime.identityCount) searchMode=$($full.runtime.unifiedSearchMode)"
- if ($full.runtime.identityError) {
- Write-Host " WARN identity table: $($full.runtime.identityError)" -ForegroundColor Yellow
- }
- }
- if ($full.simulation) {
- $wp = $full.simulation.writePath
- if ($wp) {
- Write-Host " patchSmoke published=$($wp.published) readBack=$($wp.readBack)"
- }
- if ($full.simulation.backfillQwContacts) {
- Write-Host " backfillQwContacts published=$($full.simulation.backfillQwContacts.published)"
- }
- if ($full.simulation.backfillOrders) {
- Write-Host " backfillOrders published=$($full.simulation.backfillOrders.published)"
- }
- }
- # 3) Source hook simulation (wx_call, qw_voice, lobster_chat, order, sop, ...)
- Write-Host "`n[3/4] profile-domain-sources simulation..." -ForegroundColor Yellow
- $sourcesUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/profile-domain-sources/${CompanyId}?tenantId=${TenantId}"
- $sources = Invoke-RestMethod -Uri $sourcesUri -Method Post -Headers $headers -TimeoutSec 300
- $summary.sourceHooks = $sources
- if (-not $sources.passed) { $failures.Add("sourceHooks: $($sources.message)") }
- Write-Host " passedCount=$($sources.passedCount)/$($sources.totalCount)"
- if ($sources.sources) {
- foreach ($s in $sources.sources) {
- if (-not $s.passed) {
- $label = $s.source
- if ($s.variant) { $label = "$label/$($s.variant)" }
- Write-Host " FAIL $label error=$($s.error)" -ForegroundColor Red
- }
- }
- }
- # 4) Full engine page probes (includes userProfile + profileDomain probes)
- $profilePagePassed = $true
- $profilePageNotes = New-Object System.Collections.Generic.List[string]
- if (-not $SkipFullEngine) {
- Write-Host "`n[4/4] full-engine page probes (skip travel chain)..." -ForegroundColor Yellow
- $engineUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/full-engine/${CompanyId}?tenantId=${TenantId}&includeTravelChain=false&includeTravelStress=false"
- $engine = Invoke-RestMethod -Uri $engineUri -Method Post -Headers $headers -TimeoutSec 900
- $summary.fullEngine = @{
- passed = $engine.passed
- durationMs = $engine.durationMs
- requiredPagesPassed = $engine.requiredPagesPassed
- failures = $engine.failures
- profileDomain = $engine.sections.profileDomain
- pageLinkProbes = $engine.sections.pageLinkProbes
- }
- if ($engine.sections.pageLinkProbes.pages) {
- $profilePages = @($engine.sections.pageLinkProbes.pages | Where-Object { $_.probe -in @('userProfile','profileDomain') })
- foreach ($p in $profilePages) {
- $color = if ($p.passed) { "Green" } else { "Red" }
- Write-Host " page $($p.path) [$($p.probe)] passed=$($p.passed) $($p.message)" -ForegroundColor $color
- if ($p.probe -eq 'profileDomain' -and -not $p.passed) { $profilePagePassed = $false }
- if ($p.probe -eq 'userProfile' -and -not $p.passed) {
- $profilePageNotes.Add("userProfile legacy probe failed (lobster_user_profile); unified domain ok if profileDomain passed")
- }
- }
- }
- $engineProfileFailures = @($engine.failures | Where-Object { $_ -match 'profileDomain|profile|userProfile' })
- if ($engineProfileFailures.Count -gt 0) {
- $profilePagePassed = $false
- foreach ($f in $engineProfileFailures) { $failures.Add("engine-profile: $f") }
- }
- } else {
- Write-Host "`n[4/4] skipped full-engine (-SkipFullEngine)" -ForegroundColor DarkGray
- }
- $passed = ($failures.Count -eq 0) -and $basic.passed -and $full.passed -and $sources.passed -and $profilePagePassed
- $summary.passed = $passed
- $summary.profilePagePassed = $profilePagePassed
- $summary.profilePageNotes = $profilePageNotes
- $summary.failures = $failures
- $summary.timestamp = $stamp
- $json = $summary | ConvertTo-Json -Depth 30
- [System.IO.File]::WriteAllText($reportFile, $json, $utf8NoBom)
- Write-Host "`nReport saved: $reportFile" -ForegroundColor Green
- if ($passed) {
- Write-Host "RESULT: PASS" -ForegroundColor Green
- exit 0
- }
- Write-Host "RESULT: FAIL ($($failures.Count) issues)" -ForegroundColor Red
- foreach ($f in $failures) { Write-Host " - $f" -ForegroundColor Red }
- exit 1
|