d3ro-voice/scripts/ci/run-mobile-incoming-share-local-e2e.ps1
2026-08-29 18:33:45 +09:00

147 lines
6.6 KiB
PowerShell

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$LocalApk,
[Parameter(Mandatory = $true)]
[string]$FinalApk,
[string]$AndroidSerial = 'emulator-5554'
)
$ErrorActionPreference = 'Stop'
$root = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$maestro = Join-Path $env:USERPROFILE '.maestro\bin\maestro.bat'
$localApkPath = (Resolve-Path $LocalApk).Path
$finalApkPath = (Resolve-Path $FinalApk).Path
$canonicalBuildOutput = Join-Path $root 'apps\mobile-rn\android\app\build\outputs\apk\e2e\app-e2e.apk'
$externalProviderApk = Join-Path $root 'apps\mobile-rn\android\app\build\outputs\apk\androidTest\debug\app-debug-androidTest.apk'
if (-not (Test-Path -LiteralPath $externalProviderApk -PathType Leaf)) {
throw 'The external provider test APK is unavailable.'
}
function Invoke-Adb {
param([Parameter(Position = 0, ValueFromRemainingArguments = $true)][string[]]$Arguments)
& adb -s $AndroidSerial @Arguments
if ($LASTEXITCODE -ne 0) { throw "adb failed: $($Arguments -join ' ')" }
}
function Get-LocalSupabaseConfiguration {
$lines = & supabase status --workdir (Join-Path $root 'server') -o env 2>$null
$values = @{}
foreach ($line in $lines) {
if ($line -match '^([A-Z_]+)="(.*)"$') { $values[$matches[1]] = $matches[2] }
}
if (
$values.API_URL -ne 'http://127.0.0.1:55321' -or
$values.SECRET_KEY -notmatch '^sb_secret_[A-Za-z0-9_-]{20,}$'
) {
throw 'The disposable local Supabase boundary is unavailable.'
}
return $values
}
$config = Get-LocalSupabaseConfiguration
$baseUrl = [string]$config.API_URL
$serviceSecret = [string]$config.SECRET_KEY
$headers = @{
apikey = $serviceSecret
Authorization = "Bearer $serviceSecret"
'Content-Type' = 'application/json'
}
$nonce = [guid]::NewGuid().ToString('N')
$testDomain = @('example', 'invalid') -join '.'
$email = 'incoming-share-{0}@{1}' -f $nonce, $testDomain
$credentialPrefix = 'D3roShare'
$password = $credentialPrefix + $nonce + 'A7'
$deviceFileName = '지연된 공유 음성.wav'
$userId = $null
$primaryError = $null
try {
Write-Output 'stage=fixture-create'
$created = Invoke-RestMethod -Method Post -Uri "$baseUrl/auth/v1/admin/users" -Headers $headers -Body (@{
email = $email
password = $password
email_confirm = $true
user_metadata = @{ name = 'Incoming Share E2E'; locale = 'en' }
} | ConvertTo-Json -Depth 4)
$userId = [string]$created.id
if ($userId -notmatch '^[0-9a-f-]{36}$') { throw 'Fixture user ID is invalid.' }
$profile = @()
for ($attempt = 1; $attempt -le 30; $attempt += 1) {
$profile = @(Invoke-RestMethod -Method Get -Uri "$baseUrl/rest/v1/profiles?id=eq.$userId&select=id" -Headers $headers)
if ($profile.Count -eq 1) { break }
Start-Sleep -Milliseconds 100
}
if ($profile.Count -ne 1) { throw 'Profile trigger did not finish.' }
$patchHeaders = $headers.Clone()
$patchHeaders.Prefer = 'return=minimal'
Invoke-RestMethod -Method Patch -Uri "$baseUrl/rest/v1/profiles?id=eq.$userId" -Headers $patchHeaders -Body (@{
tier = 'pro'; locale = 'en'
} | ConvertTo-Json) | Out-Null
Invoke-RestMethod -Method Patch -Uri "$baseUrl/rest/v1/subscriptions?user_id=eq.$userId" -Headers $patchHeaders -Body (@{
tier = 'pro'; status = 'active'; provider = 'admin'; payment_provider = 'none'; overage_credits = 0
} | ConvertTo-Json) | Out-Null
$settingsHeaders = $headers.Clone()
$settingsHeaders.Prefer = 'resolution=merge-duplicates,return=minimal'
Invoke-RestMethod -Method Post -Uri "$baseUrl/rest/v1/user_settings" -Headers $settingsHeaders -Body (@{
user_id = $userId
onboarding_version = 1
locale = 'en'
} | ConvertTo-Json) | Out-Null
Write-Output 'stage=install-local-e2e'
& adb -s $AndroidSerial uninstall com.d3ro.voice.test 2>$null | Out-Null
& adb -s $AndroidSerial uninstall com.d3ro.voice 2>$null | Out-Null
Invoke-Adb -Arguments @('install', '--no-streaming', $localApkPath) | Out-Null
Invoke-Adb -Arguments @('install', '-t', '--no-streaming', $externalProviderApk) | Out-Null
$env:MAESTRO_ACTOR_EMAIL = $email
$env:MAESTRO_ACTOR_PASSWORD = $password
$env:MAESTRO_SHARED_FILE_NAME = $deviceFileName
Write-Output 'stage=login'
& $maestro test (Join-Path $root 'apps\mobile-rn\.maestro\incoming-share-local-login.yaml') `
--format JUNIT `
--output (Join-Path $root 'apps\mobile-rn\.maestro\incoming-share-local-login.junit.xml') `
--test-output-dir (Join-Path $root 'apps\mobile-rn\.maestro-output\incoming-share-local\login')
if ($LASTEXITCODE -ne 0) { throw 'Incoming share login flow failed.' }
Write-Output 'stage=external-provider-share'
$uri = 'content://com.d3ro.voice.incoming-media-test/slow-audio'
$intent = Invoke-Adb -Arguments @(
'shell', 'am', 'start', '-W', '-a', 'android.intent.action.SEND',
'-t', 'audio/wav', '--eu', 'android.intent.extra.STREAM', $uri,
'--grant-read-uri-permission', '-n', 'com.d3ro.voice/.MainActivity'
)
if (($intent -join "`n") -notmatch 'Status: ok') {
throw 'ACTION_SEND did not resolve to MainActivity.'
}
Write-Output 'stage=queue-ui-check'
& $maestro test (Join-Path $root 'apps\mobile-rn\.maestro\incoming-share-local-check.yaml') `
--format JUNIT `
--output (Join-Path $root 'apps\mobile-rn\.maestro\incoming-share-local-check.junit.xml') `
--test-output-dir (Join-Path $root 'apps\mobile-rn\.maestro-output\incoming-share-local\check')
if ($LASTEXITCODE -ne 0) { throw 'Incoming share queue flow failed.' }
Write-Output 'incoming_share_external_e2e=PASS'
} catch {
$primaryError = $_
Write-Output "incoming_share_external_e2e=FAIL:$($_.Exception.Message)"
} finally {
Remove-Item Env:MAESTRO_ACTOR_EMAIL, Env:MAESTRO_ACTOR_PASSWORD, Env:MAESTRO_SHARED_FILE_NAME -ErrorAction SilentlyContinue
if ($null -ne $userId) {
Invoke-RestMethod -Method Delete -Uri "$baseUrl/auth/v1/admin/users/$userId" -Headers $headers | Out-Null
}
Copy-Item -LiteralPath $finalApkPath -Destination $canonicalBuildOutput -Force
& adb -s $AndroidSerial uninstall com.d3ro.voice.test 2>$null | Out-Null
& adb -s $AndroidSerial uninstall com.d3ro.voice 2>$null | Out-Null
Invoke-Adb -Arguments @('install', '--no-streaming', $finalApkPath) | Out-Null
$residual = if ($null -eq $userId) { @() } else {
@(Invoke-RestMethod -Method Get -Uri "$baseUrl/rest/v1/profiles?id=eq.$userId&select=id" -Headers $headers)
}
Write-Output "fixture_residual_profiles=$($residual.Count)"
}
if ($null -ne $primaryError) { throw $primaryError }