diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48ed6340..d9e50b13 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -161,7 +161,6 @@ Install-Module -Name Pester -Force -SkipPublisherCheck - `SENTRY_TEST_PLATFORM`: Target platform: Linux, macOS, Windows, Android, etc (see [`app-runner`](https://github.com/getsentry/app-runner) submodule) - `SENTRY_TEST_DSN`: Sentry project DSN where test events will be sent (defaults to reading from project.godot) - `SENTRY_TEST_EXECUTABLE`: Path to test executable (defaults to `$env:GODOT`) -- `SENTRY_TEST_ARGS`: Extra command line arguments for the executable **Sauce Labs:** - `SAUCE_USERNAME`: Sauce Labs username for authentication diff --git a/exports/export_presets.cfg b/exports/export_presets.cfg index 446c5d21..a44d17ca 100644 --- a/exports/export_presets.cfg +++ b/exports/export_presets.cfg @@ -218,3 +218,266 @@ permissions/write_sms=false permissions/write_social_stream=false permissions/write_sync_settings=false permissions/write_user_dictionary=false + +[preset.1] + +name="iOS Tests" +platform="iOS" +runnable=false +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=0 + +[preset.1.options] + +custom_template/debug="" +custom_template/release="" +architectures/arm64=true +application/app_store_team_id="APP_STORE_TEAM_ID" +application/export_method_debug=1 +application/code_sign_identity_debug="" +application/code_sign_identity_release="" +application/provisioning_profile_specifier_debug="" +application/provisioning_profile_specifier_release="" +application/export_method_release=0 +application/bundle_identifier="io.sentry.godot.project" +application/signature="" +application/short_version="" +application/version="" +application/additional_plist_content="" +application/icon_interpolation=4 +application/export_project_only=false +application/delete_old_export_files_unconditionally=false +entitlements/increased_memory_limit=false +entitlements/game_center=false +entitlements/push_notifications="Disabled" +entitlements/additional="" +capabilities/access_wifi=false +capabilities/performance_gaming_tier=false +capabilities/performance_a12=false +capabilities/additional=PackedStringArray() +shader_baker/enabled=false +user_data/accessible_from_files_app=false +user_data/accessible_from_itunes_sharing=false +privacy/camera_usage_description="" +privacy/camera_usage_description_localized={} +privacy/microphone_usage_description="" +privacy/microphone_usage_description_localized={} +privacy/photolibrary_usage_description="" +privacy/photolibrary_usage_description_localized={} +privacy/file_timestamp_access_reasons=3 +privacy/system_boot_time_access_reasons=1 +privacy/disk_space_access_reasons=3 +privacy/active_keyboard_access_reasons=0 +privacy/user_defaults_access_reasons=0 +privacy/tracking_enabled=false +privacy/tracking_domains=PackedStringArray() +privacy/collected_data/name/collected=false +privacy/collected_data/name/linked_to_user=false +privacy/collected_data/name/used_for_tracking=false +privacy/collected_data/name/collection_purposes=0 +privacy/collected_data/email_address/collected=false +privacy/collected_data/email_address/linked_to_user=false +privacy/collected_data/email_address/used_for_tracking=false +privacy/collected_data/email_address/collection_purposes=0 +privacy/collected_data/phone_number/collected=false +privacy/collected_data/phone_number/linked_to_user=false +privacy/collected_data/phone_number/used_for_tracking=false +privacy/collected_data/phone_number/collection_purposes=0 +privacy/collected_data/physical_address/collected=false +privacy/collected_data/physical_address/linked_to_user=false +privacy/collected_data/physical_address/used_for_tracking=false +privacy/collected_data/physical_address/collection_purposes=0 +privacy/collected_data/other_contact_info/collected=false +privacy/collected_data/other_contact_info/linked_to_user=false +privacy/collected_data/other_contact_info/used_for_tracking=false +privacy/collected_data/other_contact_info/collection_purposes=0 +privacy/collected_data/health/collected=false +privacy/collected_data/health/linked_to_user=false +privacy/collected_data/health/used_for_tracking=false +privacy/collected_data/health/collection_purposes=0 +privacy/collected_data/fitness/collected=false +privacy/collected_data/fitness/linked_to_user=false +privacy/collected_data/fitness/used_for_tracking=false +privacy/collected_data/fitness/collection_purposes=0 +privacy/collected_data/payment_info/collected=false +privacy/collected_data/payment_info/linked_to_user=false +privacy/collected_data/payment_info/used_for_tracking=false +privacy/collected_data/payment_info/collection_purposes=0 +privacy/collected_data/credit_info/collected=false +privacy/collected_data/credit_info/linked_to_user=false +privacy/collected_data/credit_info/used_for_tracking=false +privacy/collected_data/credit_info/collection_purposes=0 +privacy/collected_data/other_financial_info/collected=false +privacy/collected_data/other_financial_info/linked_to_user=false +privacy/collected_data/other_financial_info/used_for_tracking=false +privacy/collected_data/other_financial_info/collection_purposes=0 +privacy/collected_data/precise_location/collected=false +privacy/collected_data/precise_location/linked_to_user=false +privacy/collected_data/precise_location/used_for_tracking=false +privacy/collected_data/precise_location/collection_purposes=0 +privacy/collected_data/coarse_location/collected=false +privacy/collected_data/coarse_location/linked_to_user=false +privacy/collected_data/coarse_location/used_for_tracking=false +privacy/collected_data/coarse_location/collection_purposes=0 +privacy/collected_data/sensitive_info/collected=false +privacy/collected_data/sensitive_info/linked_to_user=false +privacy/collected_data/sensitive_info/used_for_tracking=false +privacy/collected_data/sensitive_info/collection_purposes=0 +privacy/collected_data/contacts/collected=false +privacy/collected_data/contacts/linked_to_user=false +privacy/collected_data/contacts/used_for_tracking=false +privacy/collected_data/contacts/collection_purposes=0 +privacy/collected_data/emails_or_text_messages/collected=false +privacy/collected_data/emails_or_text_messages/linked_to_user=false +privacy/collected_data/emails_or_text_messages/used_for_tracking=false +privacy/collected_data/emails_or_text_messages/collection_purposes=0 +privacy/collected_data/photos_or_videos/collected=false +privacy/collected_data/photos_or_videos/linked_to_user=false +privacy/collected_data/photos_or_videos/used_for_tracking=false +privacy/collected_data/photos_or_videos/collection_purposes=0 +privacy/collected_data/audio_data/collected=false +privacy/collected_data/audio_data/linked_to_user=false +privacy/collected_data/audio_data/used_for_tracking=false +privacy/collected_data/audio_data/collection_purposes=0 +privacy/collected_data/gameplay_content/collected=false +privacy/collected_data/gameplay_content/linked_to_user=false +privacy/collected_data/gameplay_content/used_for_tracking=false +privacy/collected_data/gameplay_content/collection_purposes=0 +privacy/collected_data/customer_support/collected=false +privacy/collected_data/customer_support/linked_to_user=false +privacy/collected_data/customer_support/used_for_tracking=false +privacy/collected_data/customer_support/collection_purposes=0 +privacy/collected_data/other_user_content/collected=false +privacy/collected_data/other_user_content/linked_to_user=false +privacy/collected_data/other_user_content/used_for_tracking=false +privacy/collected_data/other_user_content/collection_purposes=0 +privacy/collected_data/browsing_history/collected=false +privacy/collected_data/browsing_history/linked_to_user=false +privacy/collected_data/browsing_history/used_for_tracking=false +privacy/collected_data/browsing_history/collection_purposes=0 +privacy/collected_data/search_hhistory/collected=false +privacy/collected_data/search_hhistory/linked_to_user=false +privacy/collected_data/search_hhistory/used_for_tracking=false +privacy/collected_data/search_hhistory/collection_purposes=0 +privacy/collected_data/user_id/collected=false +privacy/collected_data/user_id/linked_to_user=false +privacy/collected_data/user_id/used_for_tracking=false +privacy/collected_data/user_id/collection_purposes=0 +privacy/collected_data/device_id/collected=false +privacy/collected_data/device_id/linked_to_user=false +privacy/collected_data/device_id/used_for_tracking=false +privacy/collected_data/device_id/collection_purposes=0 +privacy/collected_data/purchase_history/collected=false +privacy/collected_data/purchase_history/linked_to_user=false +privacy/collected_data/purchase_history/used_for_tracking=false +privacy/collected_data/purchase_history/collection_purposes=0 +privacy/collected_data/product_interaction/collected=false +privacy/collected_data/product_interaction/linked_to_user=false +privacy/collected_data/product_interaction/used_for_tracking=false +privacy/collected_data/product_interaction/collection_purposes=0 +privacy/collected_data/advertising_data/collected=false +privacy/collected_data/advertising_data/linked_to_user=false +privacy/collected_data/advertising_data/used_for_tracking=false +privacy/collected_data/advertising_data/collection_purposes=0 +privacy/collected_data/other_usage_data/collected=false +privacy/collected_data/other_usage_data/linked_to_user=false +privacy/collected_data/other_usage_data/used_for_tracking=false +privacy/collected_data/other_usage_data/collection_purposes=0 +privacy/collected_data/crash_data/collected=false +privacy/collected_data/crash_data/linked_to_user=false +privacy/collected_data/crash_data/used_for_tracking=false +privacy/collected_data/crash_data/collection_purposes=0 +privacy/collected_data/performance_data/collected=false +privacy/collected_data/performance_data/linked_to_user=false +privacy/collected_data/performance_data/used_for_tracking=false +privacy/collected_data/performance_data/collection_purposes=0 +privacy/collected_data/other_diagnostic_data/collected=false +privacy/collected_data/other_diagnostic_data/linked_to_user=false +privacy/collected_data/other_diagnostic_data/used_for_tracking=false +privacy/collected_data/other_diagnostic_data/collection_purposes=0 +privacy/collected_data/environment_scanning/collected=false +privacy/collected_data/environment_scanning/linked_to_user=false +privacy/collected_data/environment_scanning/used_for_tracking=false +privacy/collected_data/environment_scanning/collection_purposes=0 +privacy/collected_data/hands/collected=false +privacy/collected_data/hands/linked_to_user=false +privacy/collected_data/hands/used_for_tracking=false +privacy/collected_data/hands/collection_purposes=0 +privacy/collected_data/head/collected=false +privacy/collected_data/head/linked_to_user=false +privacy/collected_data/head/used_for_tracking=false +privacy/collected_data/head/collection_purposes=0 +privacy/collected_data/other_data_types/collected=false +privacy/collected_data/other_data_types/linked_to_user=false +privacy/collected_data/other_data_types/used_for_tracking=false +privacy/collected_data/other_data_types/collection_purposes=0 +icons/icon_1024x1024="" +icons/icon_1024x1024_dark="" +icons/icon_1024x1024_tinted="" +icons/settings_58x58="" +icons/settings_58x58_dark="" +icons/settings_58x58_tinted="" +icons/settings_87x87="" +icons/settings_87x87_dark="" +icons/settings_87x87_tinted="" +icons/notification_40x40="" +icons/notification_40x40_dark="" +icons/notification_40x40_tinted="" +icons/notification_60x60="" +icons/notification_60x60_dark="" +icons/notification_60x60_tinted="" +icons/notification_76x76="" +icons/notification_76x76_dark="" +icons/notification_76x76_tinted="" +icons/notification_114x114="" +icons/notification_114x114_dark="" +icons/notification_114x114_tinted="" +icons/spotlight_80x80="" +icons/spotlight_80x80_dark="" +icons/spotlight_80x80_tinted="" +icons/spotlight_120x120="" +icons/spotlight_120x120_dark="" +icons/spotlight_120x120_tinted="" +icons/iphone_120x120="" +icons/iphone_120x120_dark="" +icons/iphone_120x120_tinted="" +icons/iphone_180x180="" +icons/iphone_180x180_dark="" +icons/iphone_180x180_tinted="" +icons/ipad_167x167="" +icons/ipad_167x167_dark="" +icons/ipad_167x167_tinted="" +icons/ipad_152x152="" +icons/ipad_152x152_dark="" +icons/ipad_152x152_tinted="" +icons/ios_128x128="" +icons/ios_128x128_dark="" +icons/ios_128x128_tinted="" +icons/ios_192x192="" +icons/ios_192x192_dark="" +icons/ios_192x192_tinted="" +icons/ios_136x136="" +icons/ios_136x136_dark="" +icons/ios_136x136_tinted="" +icons/app_store_1024x1024="" +icons/app_store_1024x1024_dark="" +icons/app_store_1024x1024_tinted="" +application/targeted_device_family=2 +application/min_ios_version="14.0" +storyboard/image_scale_mode=0 +storyboard/custom_image@2x="" +storyboard/custom_image@3x="" +storyboard/use_custom_bg_color=false +storyboard/custom_bg_color=Color(0, 0, 0, 1) diff --git a/integration_tests/Integration.Tests.ps1 b/integration_tests/Integration.Tests.ps1 index 9b6385be..b1edac14 100644 --- a/integration_tests/Integration.Tests.ps1 +++ b/integration_tests/Integration.Tests.ps1 @@ -29,21 +29,26 @@ BeforeAll { param ( [Parameter(Mandatory=$true)] [string]$Action, - [string]$AdditionalArgs = "" + [string[]]$AdditionalArgs = @() ) # ACT: Run test action in application on device - Write-Debug "Running $Action..." - $arguments = $script:TestSetup.Args + " $Action $AdditionalArgs" + Write-Host "Running $Action..." + + $args = $script:TestSetup.Args + @($Action) + $AdditionalArgs $execPath = $script:TestSetup.Executable # Convert arguments to Android extras if necessary if ($script:TestSetup.IsAndroid) { - $arguments = ConvertTo-AndroidExtras -Arguments $arguments + $args = ConvertTo-AndroidExtras -Argument $args $execPath = $script:TestSetup.AndroidComponent + } elseif ($script:TestSetup.Platform -match "iOS") { + $execPath = $script:TestSetup.iOSBundleId } - $runResult = Invoke-DeviceApp -ExecutablePath $execPath -Arguments $arguments + # Use log file override for iOS SauceLabs, null for other providers (fallback to system logs) + $logFilePath = if ($script:TestSetup.Platform -eq "iOSSauceLabs") { $script:TestSetup.iOSApplicationLogFile } else { $null } + $runResult = Invoke-DeviceApp -ExecutablePath $execPath -Arguments $args -LogFilePath $logFilePath # Save result to JSON file $runResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "${Action}-result.json") @@ -52,15 +57,18 @@ BeforeAll { # NOTE: On Cocoa & Android, crashes are sent during the next app launch. if ( ($Action -eq "crash-capture" -or $runResult.ExitCode -ne 0) -and - $script:TestSetup.Platform -in @("macOS", "Local", "Adb", "AndroidSauceLabs") + $script:TestSetup.Platform -in @("macOS", "Local", "Adb", "AndroidSauceLabs", "iOSSauceLabs") ) { - Write-Debug "Running crash-send to ensure crash report is sent..." + Write-Host "Running crash-send to ensure crash report is sent..." Write-GitHub "::group::Log of crash-send" - $arguments = ($script:TestSetup.Args + " crash-send") + + $args = $script:TestSetup.Args + @("crash-send") + if ($script:TestSetup.IsAndroid) { - $arguments = ConvertTo-AndroidExtras -Arguments $arguments + $args = ConvertTo-AndroidExtras -Arguments $args } - Invoke-DeviceApp -ExecutablePath $execPath -Arguments $arguments + + Invoke-DeviceApp -ExecutablePath $execPath -Arguments $args -LogFilePath $logFilePath Write-GitHub "::endgroup::" } @@ -74,12 +82,14 @@ BeforeAll { # Initialize test parameters object $script:TestSetup = [PSCustomObject]@{ Executable = $env:SENTRY_TEST_EXECUTABLE - Args = $env:SENTRY_TEST_ARGS + Args = @() Dsn = $env:SENTRY_TEST_DSN AuthToken = $env:SENTRY_AUTH_TOKEN Platform = $env:SENTRY_TEST_PLATFORM AndroidComponent = "io.sentry.godot.project/com.godot.game.GodotApp" IsAndroid = ($env:SENTRY_TEST_PLATFORM -in @("Adb", "AndroidSauceLabs")) + iOSBundleId = "io.sentry.godot.project" + iOSApplicationLogFile = "@io.sentry.godot.project:documents/logs/godot.log" } # Check executable and arguments @@ -87,7 +97,9 @@ BeforeAll { Write-Warning "SENTRY_TEST_EXECUTABLE environment variable is not set. Defaulting to env:GODOT." $script:TestSetup.Executable = $env:GODOT # For running with Godot binary, we need to add these flags... - $script:TestSetup.Args += " --disable-crash-handler --headless --path project --" + $script:TestSetup.Args += @("--disable-crash-handler", "--headless", "--path", "project", "--") + } else { + $script:TestSetup.Args += @("--") } # Validate executable if (-not (Test-Path $script:TestSetup.Executable)) { @@ -144,8 +156,6 @@ Describe "Platform Integration Tests" { Context "Crash Capture" { BeforeAll { - Write-Host "Testing crash-capture..." - $runResult = Invoke-TestAction -Action "crash-capture" $eventId = Get-EventIds -appOutput $runResult.Output -expectedCount 1 @@ -230,11 +240,11 @@ Describe "Platform Integration Tests" { BeforeAll { $script:TEST_MESSAGE = "TestMessage" - $runResult = Invoke-TestAction -Action "message-capture" -AdditionalArgs "`"$TEST_MESSAGE`"" + $runResult = Invoke-TestAction -Action "message-capture" -AdditionalArgs @("$TEST_MESSAGE") $eventId = Get-EventIds -AppOutput $runResult.Output -ExpectedCount 1 if ($eventId) { - Write-GitHub "::group::Getting event content" + Write-GitHub "::group::Getting event content" $script:runEvent = Get-SentryTestEvent -EventId "$eventId" Write-GitHub "::endgroup::" } diff --git a/integration_tests/Utils.ps1 b/integration_tests/Utils.ps1 index a0197bf4..fe366ecb 100644 --- a/integration_tests/Utils.ps1 +++ b/integration_tests/Utils.ps1 @@ -15,60 +15,26 @@ function script:Write-GitHub { function script:ConvertTo-AndroidExtras { param ( [Parameter(Mandatory=$true)] - [string]$Arguments + [AllowEmptyCollection()] + [AllowEmptyString()] + [string[]]$Arguments ) - if ([string]::IsNullOrWhiteSpace($Arguments)) { - return "" + if (-not $Arguments -or $Arguments.Count -eq 0) { + return @() } - # Split arguments into tokens, respecting quoted strings - $tokens = @() - $current = "" - $inQuotes = $false - $quoteChar = $null - $escapeNext = $false - - for ($i = 0; $i -lt $Arguments.Length; $i++) { - $char = $Arguments[$i] - - if ($escapeNext) { - $current += $char - $escapeNext = $false - } - elseif ($char -eq '\') { - $escapeNext = $true - } - elseif (($char -eq '"' -or $char -eq "'") -and -not $inQuotes) { - $inQuotes = $true - $quoteChar = $char - } - elseif ($char -eq $quoteChar -and $inQuotes) { - $inQuotes = $false - $quoteChar = $null + # Convert argument array to Android intent extras format + $extras = @() + for ($i = 0; $i -lt $Arguments.Count; $i++) { + $arg = $Arguments[$i] + if (-not ($arg[0] -eq '"' -and $arg[-1] -eq '"')) { + $arg = "$arg" -replace '"', '\"' + $arg = "`"$arg`"" } - elseif ($char -eq ' ' -and -not $inQuotes) { - if ($current.Length -gt 0) { - $tokens += $current - $current = "" - } - } - else { - $current += $char - } - } - - # Add the last token if it exists - if ($current.Length -gt 0) { - $tokens += $current - } - # Convert tokens to Android intent extras format - $extras = "" - for ($i = 0; $i -lt $tokens.Count; $i++) { - $escapedToken = $tokens[$i] -replace '"', '\"' - $extras += " --es arg$i `"$escapedToken`"" + $extras += @("--es", "arg$i", $arg) } - return $extras.TrimStart() + return $extras } diff --git a/modules/app-runner b/modules/app-runner index 2f5268c4..dbbcac88 160000 --- a/modules/app-runner +++ b/modules/app-runner @@ -1 +1 @@ -Subproject commit 2f5268c4c27d435417cdf1dadc8980126b9bd64f +Subproject commit dbbcac88ea9cf755a79dd67a611fdba7a998316b diff --git a/project/cli/android_cli_adapter.gd b/project/cli/android_cli_adapter.gd index 1d7a7ae9..0439620a 100644 --- a/project/cli/android_cli_adapter.gd +++ b/project/cli/android_cli_adapter.gd @@ -18,6 +18,16 @@ static func get_command_argv() -> PackedStringArray: var key := "arg%d" % i if extras.has(key): rv.append(extras[key]) + + # If rv contains "--", return only the subset after "--" + var separator_index: int = rv.find("--") + if separator_index != -1: + # Print which flags were ignored (everything before "--") + if separator_index > 0: + var ignored_flags = rv.slice(0, separator_index) + print("Ignoring flags passed before '--': ", ignored_flags) + return rv.slice(separator_index + 1) + return rv diff --git a/project/main.gd b/project/main.gd index 3b4d4394..cb016e99 100644 --- a/project/main.gd +++ b/project/main.gd @@ -8,7 +8,12 @@ func _ready() -> void: if await cli_commands.check_and_execute_cli(): # Quit if a CLI command was executed - get_tree().quit(cli_commands.exit_code) + if OS.get_name() == "iOS": + # NOTE: This is a workaround -- quit() doesn't work on iOS. + # See: https://github.com/godotengine/godot/issues/110626 + OS.kill(OS.get_process_id()) + else: + get_tree().quit(cli_commands.exit_code) elif OS.get_name() in ["Android", "iOS"]: # Continue with mobile UI get_tree().change_scene_to_file.call_deferred("res://mobile.tscn")