param( [ValidateSet('smoke','acceptance')][string]$Profile='smoke', [string]$Duration='', [int]$Rate=0, [int]$DuplicateWindow=0, [int]$ConversationPool=50 ) $ErrorActionPreference='Stop' $PSNativeCommandUseErrorActionPreference=$true $root=Split-Path -Parent $PSScriptRoot Set-Location -LiteralPath $root $run=[Guid]::NewGuid().ToString('N') $model="load-callback-$run" $prefix="load-callback-$run-" $tenant='10000000-0000-0000-0000-000000000001' $fixtures=$null if($ConversationPool-lt1-or$ConversationPool-gt500){throw 'ConversationPool must be between 1 and 500'} function Sql([string]$statement){ $result=$statement|docker compose exec -T postgres psql -U voice -d voice_platform -v ON_ERROR_STOP=1 -q -t -A if($LASTEXITCODE-ne0){throw 'Provider callback load SQL failed'} return ($result|Out-String).Trim() } try{ $setup=@" BEGIN; WITH selected AS ( SELECT household_id,id subject_id,tenant_id,profile_version FROM subject_profile WHERE tenant_id='$tenant'::uuid AND status='active' ORDER BY created_at LIMIT 1 ), consent AS ( INSERT INTO consent_snapshot(tenant_id,subject_id,snapshot_version,effective_consents,source_consent_ids) SELECT tenant_id,subject_id,profile_version,'{}'::jsonb,jsonb_build_array('$model') FROM selected RETURNING id,tenant_id,subject_id ), context AS ( INSERT INTO context_snapshot(tenant_id,subject_id,profile_version,consent_snapshot_id,memory_versions,prompt_bundle_version,engine_mode,content_digest,sanitized_summary) SELECT c.tenant_id,c.subject_id,s.profile_version,c.id,'[]'::jsonb,'$model','s2s_hybrid',encode(digest('$model','sha256'),'hex'),'供应商通知负载夹具' FROM consent c JOIN selected s ON s.subject_id=c.subject_id RETURNING id,tenant_id,subject_id,consent_snapshot_id ), device_rows AS ( INSERT INTO device(tenant_id,serial_digest,model,hardware_revision,credential_ref,minimum_security_version) SELECT '$tenant'::uuid,encode(digest('$run-device-'||g,'sha256'),'hex'),'$model','load','load://callback/'||g,'load' FROM generate_series(1,$ConversationPool) g RETURNING id ), numbered_devices AS ( SELECT id,row_number() OVER(ORDER BY id) n FROM device_rows ), conversation_row AS ( INSERT INTO conversation(tenant_id,household_id,subject_id,device_id,consent_snapshot_id,context_snapshot_id,provider_task_ref,engine_mode,retention_mode,status,allocation_expires_at,lease_expires_at,started_at) SELECT '$tenant'::uuid,s.household_id,s.subject_id,d.id,c.consent_snapshot_id,c.id,'$prefix'||d.n,'s2s_hybrid','none','ACTIVE',now()+interval '15 minutes',now()+interval '15 minutes',now() FROM selected s CROSS JOIN context c CROSS JOIN numbered_devices d RETURNING id,public_id,provider_task_ref ), task AS ( INSERT INTO rtc_task(conversation_id,provider,provider_task_ref,room_id,device_rtc_user_id,agent_rtc_user_id,status,lease_expires_at) SELECT id,'mock',provider_task_ref,'room-'||provider_task_ref,'device-'||provider_task_ref,'agent-'||provider_task_ref,'ACTIVE',now()+interval '15 minutes' FROM conversation_row ) SELECT string_agg(public_id::text||'|'||provider_task_ref,',' ORDER BY provider_task_ref) FROM conversation_row; COMMIT; "@ $fixtures=((Sql $setup)-split"`n"|Select-Object -Last 1).Trim() if(($fixtures-split',').Count-ne$ConversationPool-or$fixtures-notmatch'^[A-Za-z0-9|,\-]+$'){throw "Invalid provider load fixture pool"} $fixedOccurredAt=[DateTime]::UtcNow.ToString('o') $arguments=@('run','--rm','-v',"${PWD}/test/load:/scripts:ro",'grafana/k6','run','-e','CALLBACK_URL=http://host.docker.internal:58081','-e',"PROFILE=$Profile",'-e',"PROVIDER_CALLBACK_SECRET=local-provider-callback-secret-32-bytes-minimum",'-e',"PROVIDER_FIXTURES=$fixtures",'-e',"OCCURRED_AT=$fixedOccurredAt") if($Duration){$arguments+=@('-e',"DURATION=$Duration")} if($Rate-gt0){$arguments+=@('-e',"RATE=$Rate")} if($DuplicateWindow-gt0){$arguments+=@('-e',"DUPLICATE_WINDOW=$DuplicateWindow")} $arguments+='/scripts/provider-callbacks.js' docker @arguments if($LASTEXITCODE-ne0){throw 'Provider callback k6 thresholds failed'} $minimumUnique=if($DuplicateWindow-gt0){$DuplicateWindow}elseif($Profile-eq'smoke'){100}else{300000} $evidence=Sql "SELECT count(*)||'|'||count(*) FILTER(WHERE processing_status IN('processed','ignored'))||'|'||(SELECT count(*) FROM conversation WHERE provider_task_ref LIKE '$prefix%' AND status='ACTIVE')||'|'||(SELECT count(*) FROM rtc_task rt JOIN conversation c ON c.id=rt.conversation_id WHERE c.provider_task_ref LIKE '$prefix%' AND rt.status='ACTIVE') FROM provider_event WHERE conversation_id IN(SELECT id FROM conversation WHERE provider_task_ref LIKE '$prefix%');" $parts=$evidence-split'\|' if($parts.Count-ne4-or[int]$parts[0]-lt$minimumUnique-or$parts[0]-ne$parts[1]-or[int]$parts[2]-ne$ConversationPool-or[int]$parts[3]-ne$ConversationPool){throw "Provider callback persistence mismatch: $evidence"} Write-Host "Provider callback load passed: profile=$Profile, conversations=$ConversationPool, unique_events=$($parts[0]), all_processed_or_ignored=true, conversation_tasks_active=$($parts[3])" }finally{ if($fixtures){ $cleanup=@" BEGIN; CREATE TEMP TABLE load_conversation ON COMMIT DROP AS SELECT id,public_id,context_snapshot_id,consent_snapshot_id,device_id FROM conversation WHERE provider_task_ref LIKE '$prefix%'; DELETE FROM alert_incident WHERE resource_type='conversation' AND resource_public_id IN(SELECT public_id FROM load_conversation); DELETE FROM web_event WHERE resource_type='conversation' AND resource_public_id IN(SELECT public_id FROM load_conversation); DELETE FROM audit_event WHERE resource_id IN(SELECT id FROM load_conversation); DELETE FROM outbox_event WHERE aggregate_id IN(SELECT id FROM load_conversation); DELETE FROM alert_incident WHERE tenant_id='$tenant'::uuid AND fingerprint='outbox-dead' AND NOT EXISTS(SELECT 1 FROM outbox_event WHERE tenant_id='$tenant'::uuid AND status='dead'); DELETE FROM conversation_state_history WHERE conversation_id IN(SELECT id FROM load_conversation); DELETE FROM provider_event WHERE conversation_id IN(SELECT id FROM load_conversation); DELETE FROM rtc_task WHERE conversation_id IN(SELECT id FROM load_conversation); DELETE FROM conversation WHERE id IN(SELECT id FROM load_conversation); DELETE FROM device WHERE id IN(SELECT device_id FROM load_conversation); DELETE FROM context_snapshot WHERE id IN(SELECT context_snapshot_id FROM load_conversation); DELETE FROM consent_snapshot WHERE id IN(SELECT consent_snapshot_id FROM load_conversation); COMMIT; "@ try{Sql $cleanup|Out-Null}catch{Write-Warning $_} } }