lobster_profile_full_validation.ps1 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # Full profile domain simulation validation (Plan B P0-P3)
  2. param(
  3. [string]$ApiBase = "http://127.0.0.1:8006",
  4. [int]$CompanyId = 338,
  5. [int]$TenantId = 33,
  6. [string]$OpsSecret = "lobster-dev-ops",
  7. [switch]$SkipFullEngine
  8. )
  9. $ErrorActionPreference = "Stop"
  10. try {
  11. [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
  12. $OutputEncoding = [System.Text.Encoding]::UTF8
  13. } catch { }
  14. $utf8NoBom = New-Object System.Text.UTF8Encoding $false
  15. $reportDir = Join-Path $PSScriptRoot "reports"
  16. if (-not (Test-Path $reportDir)) { New-Item -ItemType Directory -Path $reportDir | Out-Null }
  17. $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
  18. $reportFile = Join-Path $reportDir "lobster-profile-full-validation-$stamp.json"
  19. $headers = @{
  20. "Content-Type" = "application/json"
  21. "X-Lobster-Ops-Secret" = $OpsSecret
  22. }
  23. Write-Host "=== Profile Domain Full Simulation Validation ===" -ForegroundColor Cyan
  24. Write-Host "ApiBase=$ApiBase CompanyId=$CompanyId TenantId=$TenantId"
  25. function Wait-Service {
  26. param([string]$Base, [int]$MaxSec = 120)
  27. $deadline = (Get-Date).AddSeconds($MaxSec)
  28. while ((Get-Date) -lt $deadline) {
  29. try {
  30. Invoke-RestMethod -Uri "$Base/api/lobster/admin/phase2/verify/$CompanyId?tenantId=$TenantId" -Headers $headers -TimeoutSec 10 | Out-Null
  31. Write-Host "OK service reachable" -ForegroundColor Green
  32. return $true
  33. } catch {
  34. Start-Sleep -Seconds 3
  35. }
  36. }
  37. Write-Host "FAIL service not reachable at $Base" -ForegroundColor Red
  38. return $false
  39. }
  40. if (-not (Wait-Service $ApiBase)) { exit 1 }
  41. $summary = [ordered]@{}
  42. $failures = New-Object System.Collections.Generic.List[string]
  43. # 1) Basic profile domain probe
  44. Write-Host "`n[1/4] profile-domain basic..." -ForegroundColor Yellow
  45. $basicUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/profile-domain/${CompanyId}?tenantId=${TenantId}"
  46. $basic = Invoke-RestMethod -Uri $basicUri -Method Post -Headers $headers -TimeoutSec 120
  47. $summary.basic = $basic
  48. if (-not $basic.passed) { $failures.Add("basic: $($basic.message)") }
  49. Write-Host " passed=$($basic.passed) mode=$($basic.projectionMode) beansOk=$($basic.beansOk)"
  50. # 2) Full simulation (write smoke + backfill sample)
  51. Write-Host "`n[2/4] profile-domain-full simulation..." -ForegroundColor Yellow
  52. $fullUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/profile-domain-full/${CompanyId}?tenantId=${TenantId}"
  53. $full = Invoke-RestMethod -Uri $fullUri -Method Post -Headers $headers -TimeoutSec 300
  54. $summary.fullSimulation = $full
  55. if (-not $full.passed) { $failures.Add("fullSimulation: $($full.message)") }
  56. if ($full.runtime) {
  57. Write-Host " identityCount=$($full.runtime.identityCount) searchMode=$($full.runtime.unifiedSearchMode)"
  58. if ($full.runtime.identityError) {
  59. Write-Host " WARN identity table: $($full.runtime.identityError)" -ForegroundColor Yellow
  60. }
  61. }
  62. if ($full.simulation) {
  63. $wp = $full.simulation.writePath
  64. if ($wp) {
  65. Write-Host " patchSmoke published=$($wp.published) readBack=$($wp.readBack)"
  66. }
  67. if ($full.simulation.backfillQwContacts) {
  68. Write-Host " backfillQwContacts published=$($full.simulation.backfillQwContacts.published)"
  69. }
  70. if ($full.simulation.backfillOrders) {
  71. Write-Host " backfillOrders published=$($full.simulation.backfillOrders.published)"
  72. }
  73. }
  74. # 3) Source hook simulation (wx_call, qw_voice, lobster_chat, order, sop, ...)
  75. Write-Host "`n[3/4] profile-domain-sources simulation..." -ForegroundColor Yellow
  76. $sourcesUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/profile-domain-sources/${CompanyId}?tenantId=${TenantId}"
  77. $sources = Invoke-RestMethod -Uri $sourcesUri -Method Post -Headers $headers -TimeoutSec 300
  78. $summary.sourceHooks = $sources
  79. if (-not $sources.passed) { $failures.Add("sourceHooks: $($sources.message)") }
  80. Write-Host " passedCount=$($sources.passedCount)/$($sources.totalCount)"
  81. if ($sources.sources) {
  82. foreach ($s in $sources.sources) {
  83. if (-not $s.passed) {
  84. $label = $s.source
  85. if ($s.variant) { $label = "$label/$($s.variant)" }
  86. Write-Host " FAIL $label error=$($s.error)" -ForegroundColor Red
  87. }
  88. }
  89. }
  90. # 4) Full engine page probes (includes userProfile + profileDomain probes)
  91. $profilePagePassed = $true
  92. $profilePageNotes = New-Object System.Collections.Generic.List[string]
  93. if (-not $SkipFullEngine) {
  94. Write-Host "`n[4/4] full-engine page probes (skip travel chain)..." -ForegroundColor Yellow
  95. $engineUri = "$($ApiBase.TrimEnd('/'))/api/lobster/admin/validation/full-engine/${CompanyId}?tenantId=${TenantId}&includeTravelChain=false&includeTravelStress=false"
  96. $engine = Invoke-RestMethod -Uri $engineUri -Method Post -Headers $headers -TimeoutSec 900
  97. $summary.fullEngine = @{
  98. passed = $engine.passed
  99. durationMs = $engine.durationMs
  100. requiredPagesPassed = $engine.requiredPagesPassed
  101. failures = $engine.failures
  102. profileDomain = $engine.sections.profileDomain
  103. pageLinkProbes = $engine.sections.pageLinkProbes
  104. }
  105. if ($engine.sections.pageLinkProbes.pages) {
  106. $profilePages = @($engine.sections.pageLinkProbes.pages | Where-Object { $_.probe -in @('userProfile','profileDomain') })
  107. foreach ($p in $profilePages) {
  108. $color = if ($p.passed) { "Green" } else { "Red" }
  109. Write-Host " page $($p.path) [$($p.probe)] passed=$($p.passed) $($p.message)" -ForegroundColor $color
  110. if ($p.probe -eq 'profileDomain' -and -not $p.passed) { $profilePagePassed = $false }
  111. if ($p.probe -eq 'userProfile' -and -not $p.passed) {
  112. $profilePageNotes.Add("userProfile legacy probe failed (lobster_user_profile); unified domain ok if profileDomain passed")
  113. }
  114. }
  115. }
  116. $engineProfileFailures = @($engine.failures | Where-Object { $_ -match 'profileDomain|profile|userProfile' })
  117. if ($engineProfileFailures.Count -gt 0) {
  118. $profilePagePassed = $false
  119. foreach ($f in $engineProfileFailures) { $failures.Add("engine-profile: $f") }
  120. }
  121. } else {
  122. Write-Host "`n[4/4] skipped full-engine (-SkipFullEngine)" -ForegroundColor DarkGray
  123. }
  124. $passed = ($failures.Count -eq 0) -and $basic.passed -and $full.passed -and $sources.passed -and $profilePagePassed
  125. $summary.passed = $passed
  126. $summary.profilePagePassed = $profilePagePassed
  127. $summary.profilePageNotes = $profilePageNotes
  128. $summary.failures = $failures
  129. $summary.timestamp = $stamp
  130. $json = $summary | ConvertTo-Json -Depth 30
  131. [System.IO.File]::WriteAllText($reportFile, $json, $utf8NoBom)
  132. Write-Host "`nReport saved: $reportFile" -ForegroundColor Green
  133. if ($passed) {
  134. Write-Host "RESULT: PASS" -ForegroundColor Green
  135. exit 0
  136. }
  137. Write-Host "RESULT: FAIL ($($failures.Count) issues)" -ForegroundColor Red
  138. foreach ($f in $failures) { Write-Host " - $f" -ForegroundColor Red }
  139. exit 1