From 098e74d08f7e604323fcd057febda2d4d0aded8f Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 28 Apr 2022 14:47:21 +0100 Subject: [PATCH 01/10] dep: bump bugsnag-android dependency to 5.22.1 --- CHANGELOG.md | 4 ++++ Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml | 2 +- deps/bugsnag-plugin-android-unreal/build.gradle | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e12d6e6..a4faa2bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Changelog ========= +## TBD + +* Updates the bugsnag-android dependency from v5.22.0 to [v5.22.1](https://github.com/bugsnag/bugsnag-android/blob/master/CHANGELOG.md#5221-2022-04-28) + ## 1.3.1 (2022-04-26) * Fixes `java.lang.ClassNotFoundException` in minified Android builds. diff --git a/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml b/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml index 46c3396d..c3826c09 100644 --- a/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml +++ b/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml @@ -74,7 +74,7 @@ com.bugsnag,bugsnag-plugin-android-unreal,1.3.1 - com.bugsnag,bugsnag-android,5.22.0 + com.bugsnag,bugsnag-android,5.22.1 diff --git a/deps/bugsnag-plugin-android-unreal/build.gradle b/deps/bugsnag-plugin-android-unreal/build.gradle index 937c5ceb..23f98f2c 100644 --- a/deps/bugsnag-plugin-android-unreal/build.gradle +++ b/deps/bugsnag-plugin-android-unreal/build.gradle @@ -28,7 +28,7 @@ android { } dependencies { - api "com.bugsnag:bugsnag-android-core:5.22.0" + api "com.bugsnag:bugsnag-android-core:5.22.1" androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' androidTestImplementation 'junit:junit:4.12' From 942b5ce4f67a23e57932b3dffe2085a59cbd1f72 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 5 May 2022 15:06:44 +0100 Subject: [PATCH 02/10] Fix building iOS fixture via Makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6bdbd986..1f2ded9e 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ UE_RUNUAT=$(UE_HOME)/Engine/Build/BatchFiles/RunUAT.sh UE_EDITOR=$(UE_HOME)/Engine/Binaries/Mac/UE4Editor.app/Contents/MacOS/UE4Editor UE_BUILDCOOK_ARGS=BuildCookRun -nocompileeditor -nop4 -stage -package \ -clientconfig=Shipping -compressed -pak -prereqs \ - -build -utf8output -cook -distribution + -build -utf8output -cook UPROJECT=$(PWD)/BugsnagExample.uproject EXAMPLE_MAC_LIB=Binaries/Mac/UE4Editor-BugsnagExample.dylib @@ -134,7 +134,7 @@ e2e_mac: $(TEST_MAC_APP) .PHONY: build_example_android build_example_android: $(EXAMPLE_MAC_LIB) - "$(UE_RUNUAT)" $(UE_BUILDCOOK_ARGS) -project="$(UPROJECT)" -targetplatform=Android + "$(UE_RUNUAT)" $(UE_BUILDCOOK_ARGS) -project="$(UPROJECT)" -targetplatform=Android -distribution .PHONY: install_example_android install_example_android: build_example_android @@ -177,7 +177,7 @@ $(EXAMPLE_MAC_LIB): $(shell find Plugins/Bugsnag/Source Source -type f) #------------------------------------------------------------------------------- $(TEST_ANDROID_APP): $(TEST_MAC_LIB) - "$(UE_RUNUAT)" $(UE_BUILDCOOK_ARGS) -project="$(TESTPROJ)" -targetplatform=Android + "$(UE_RUNUAT)" $(UE_BUILDCOOK_ARGS) -project="$(TESTPROJ)" -targetplatform=Android -distribution $(TEST_IOS_APP): $(TEST_MAC_LIB) "$(UE_RUNUAT)" $(UE_BUILDCOOK_ARGS) -project="$(TESTPROJ)" -targetplatform=IOS From 3ebb4ab94efb0554724e68a65b23a76c47f93bdf Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 5 May 2022 15:12:48 +0100 Subject: [PATCH 03/10] Use GET /command to drive E2E tests --- .../generic/Content/MainWidget.uasset | Bin 133369 -> 18437 bytes .../Source/TestFixture/MainWidgetBase.cpp | 92 +++++++++++++++++ .../Source/TestFixture/MainWidgetBase.h | 17 ++++ .../Source/TestFixture/TestFixture.Build.cs | 2 +- .../Source/TestFixture/TestFixture.cpp | 56 +---------- .../TestFixtureBlueprintFunctionLibrary.cpp | 40 -------- .../TestFixtureBlueprintFunctionLibrary.h | 25 ----- features/steps/unreal_steps.rb | 94 +++++++----------- 8 files changed, 146 insertions(+), 180 deletions(-) create mode 100644 features/fixtures/generic/Source/TestFixture/MainWidgetBase.cpp create mode 100644 features/fixtures/generic/Source/TestFixture/MainWidgetBase.h delete mode 100644 features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.cpp delete mode 100644 features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.h diff --git a/features/fixtures/generic/Content/MainWidget.uasset b/features/fixtures/generic/Content/MainWidget.uasset index 185e725fd0d35c006ec67a9e2c1f695c5d97c404..815222680eff93dacdc312ff7df669b1ad8c9725 100644 GIT binary patch literal 18437 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 + + if (FApp::IsGame()) + { + // Wait for map loading to prevent unexpected breadcrumbs when running scenarios. + FCoreUObjectDelegates::PostLoadMapWithWorld.AddLambda([this](UWorld* World) + { + static bool once; + if (!once) + { + once = true; + ExecuteMazeRunnerCommand(); + } + }); + } +#endif +} + +void UMainWidgetBase::ExecuteMazeRunnerCommand() +{ + TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); + HttpRequest->SetVerb("GET"); + HttpRequest->SetURL(TEXT(MAZE_RUNNER_URL_BASE "/command")); + HttpRequest->OnProcessRequestComplete().BindLambda([](FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bConnectedSuccessfully) + { + if (!bConnectedSuccessfully || !HttpResponse.IsValid()) + { + UE_LOG(LogTestFixture, Error, TEXT("ExecuteMazeRunnerCommand: no response")); + return; + } + + int32 StatusCode = HttpResponse->GetResponseCode(); + if (StatusCode != 200) + { + UE_LOG(LogTestFixture, Error, TEXT("ExecuteMazeRunnerCommand: status code %d"), StatusCode); + return; + } + + UE_LOG(LogTestFixture, Display, TEXT("ExecuteMazeRunnerCommand: %s"), *(HttpResponse->GetContentAsString())); + + TSharedPtr JsonObject; + const TArray& Content = HttpResponse->GetContent(); + FLargeMemoryReader Archive((const uint8*)Content.GetData(), Content.Num()); + if (!FJsonSerializer::Deserialize(TJsonReaderFactory::Create(&Archive), JsonObject)) + { + UE_LOG(LogTestFixture, Error, TEXT("ExecuteMazeRunnerCommand: Could not deserialize Maze Runner command")); + return; + } + + const FString& Action = JsonObject->GetStringField(TEXT("action")); + const FString& ScenarioName = JsonObject->GetStringField(TEXT("scenario_name")); + + if (Action == TEXT("run_scenario")) + { + Scenario::Run(ScenarioName); + } + else if (Action == TEXT("start_bugsnag")) + { + Scenario::Start(ScenarioName); + } + else + { + UE_LOG(LogTestFixture, Error, TEXT("ExecuteMazeRunnerCommand: bad action: \"%s\""), *Action); + } + }); + HttpRequest->ProcessRequest(); +} diff --git a/features/fixtures/generic/Source/TestFixture/MainWidgetBase.h b/features/fixtures/generic/Source/TestFixture/MainWidgetBase.h new file mode 100644 index 00000000..e694a424 --- /dev/null +++ b/features/fixtures/generic/Source/TestFixture/MainWidgetBase.h @@ -0,0 +1,17 @@ +// Copyright 2022 Bugsnag. All Rights Reserved. + +#pragma once + +#include "Blueprint/UserWidget.h" +#include "MainWidgetBase.generated.h" + +UCLASS() +class TESTFIXTURE_API UMainWidgetBase : public UUserWidget +{ + GENERATED_BODY() + + void NativeOnInitialized() override; + + UFUNCTION(BlueprintCallable) + void ExecuteMazeRunnerCommand(); +}; diff --git a/features/fixtures/generic/Source/TestFixture/TestFixture.Build.cs b/features/fixtures/generic/Source/TestFixture/TestFixture.Build.cs index 87cb0aa3..fe990cd8 100644 --- a/features/fixtures/generic/Source/TestFixture/TestFixture.Build.cs +++ b/features/fixtures/generic/Source/TestFixture/TestFixture.Build.cs @@ -6,7 +6,7 @@ public TestFixture(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "SlateCore", "Json" }); + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "Http", "SlateCore", "Json" }); PrivateDependencyModuleNames.AddRange(new string[] { "Bugsnag" }); } diff --git a/features/fixtures/generic/Source/TestFixture/TestFixture.cpp b/features/fixtures/generic/Source/TestFixture/TestFixture.cpp index 361414fc..431803e7 100644 --- a/features/fixtures/generic/Source/TestFixture/TestFixture.cpp +++ b/features/fixtures/generic/Source/TestFixture/TestFixture.cpp @@ -2,58 +2,4 @@ #include "Scenarios/Scenario.h" -class TESTFIXTURE_API FTestFixtureModule : public IModuleInterface -{ -public: - void StartupModule() override - { - FCoreUObjectDelegates::PostLoadMapWithWorld.AddRaw(this, &FTestFixtureModule::OnMapLoaded); - } - - void OnMapLoaded(UWorld* World) - { - FCoreUObjectDelegates::PostLoadMapWithWorld.RemoveAll(this); - -#if PLATFORM_MAC && !UE_EDITOR - // Wait for map loading to prevent unexpected breadcrumbs when running scenarios. - EvaluateCommandLine(); -#endif - } - - void EvaluateCommandLine() - { - const TCHAR* CommandLine = FCommandLine::GetOriginal(); - UE_LOG(LogTestFixture, Display, TEXT("Command line = %s"), CommandLine); - - FString Action; - if (!FParse::Value(CommandLine, TEXT("action"), Action)) - { - UE_LOG(LogTestFixture, Error, TEXT("No Action passed on command line")); - return; - } - - FString ScenarioName; - if (!FParse::Value(CommandLine, TEXT("scenario_name"), ScenarioName)) - { - UE_LOG(LogTestFixture, Error, TEXT("No ScenarioName passed on command line")); - return; - } - - UE_LOG(LogTestFixture, Display, TEXT("Action = \"%s\" ScenarioName = \"%s\""), *Action, *ScenarioName); - - if (Action == TEXT("run_scenario")) - { - Scenario::Run(ScenarioName); - } - else if (Action == TEXT("start_bugsnag")) - { - Scenario::Start(ScenarioName); - } - else - { - UE_LOG(LogTestFixture, Error, TEXT("Unrecognized action: \"%s\""), *Action); - } - } -}; - -IMPLEMENT_PRIMARY_GAME_MODULE(FTestFixtureModule, TestFixture, "TestFixture"); +IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, TestFixture, "TestFixture"); diff --git a/features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.cpp b/features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.cpp deleted file mode 100644 index e4725307..00000000 --- a/features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "TestFixtureBlueprintFunctionLibrary.h" - -#include "ScenarioNames.h" -#include "Scenarios/Scenario.h" - -#include "Http.h" - -static FString DisplayText; - -static FString GetScenarioName() -{ - int32 ScenarioIndex = -1; - LexFromString(ScenarioIndex, *DisplayText); - UE_LOG(LogTestFixture, Display, TEXT("ScenarioIndex = %d"), ScenarioIndex); - return ScenarioNames[ScenarioIndex]; -} - -void UTestFixtureBlueprintFunctionLibrary::AppendText(const FString& Text) -{ - DisplayText += Text; -} - -FString UTestFixtureBlueprintFunctionLibrary::GetDisplayText() -{ - return DisplayText; -} - -void UTestFixtureBlueprintFunctionLibrary::Run() -{ - FString ScenarioName = GetScenarioName(); - Scenario::Run(ScenarioName); - DisplayText.Reset(); -} - -void UTestFixtureBlueprintFunctionLibrary::Start() -{ - FString ScenarioName = GetScenarioName(); - Scenario::Start(ScenarioName); - DisplayText.Reset(); -} diff --git a/features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.h b/features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.h deleted file mode 100644 index e3d6dec0..00000000 --- a/features/fixtures/generic/Source/TestFixture/TestFixtureBlueprintFunctionLibrary.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "TestFixtureBlueprintFunctionLibrary.generated.h" - -UCLASS() -class TESTFIXTURE_API UTestFixtureBlueprintFunctionLibrary - : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - UFUNCTION(BlueprintCallable, Category = "Maze Runner Fixture") - static void AppendText(const FString& Text); - - UFUNCTION(BlueprintCallable, Category = "Maze Runner Fixture") - static FString GetDisplayText(); - - UFUNCTION(BlueprintCallable, Category = "Maze Runner Fixture") - static void Run(); - - UFUNCTION(BlueprintCallable, Category = "Maze Runner Fixture") - static void Start(); -}; diff --git a/features/steps/unreal_steps.rb b/features/steps/unreal_steps.rb index 56bb49b2..4ad0ea63 100644 --- a/features/steps/unreal_steps.rb +++ b/features/steps/unreal_steps.rb @@ -1,28 +1,15 @@ +# frozen_string_literal: true + require 'rbconfig' HOST_OS = RbConfig::CONFIG['host_os'] -When('I relaunch the mobile app') do - Maze.driver.launch_app - sleep 3 -end - When('I run {string}') do |scenario_name| - if is_platform? :macos - run_mac_fixture(:run_scenario, scenario_name) - else - dial_number_for scenario_name - tap_button 10 - end + run_fixture(:run_scenario, scenario_name) end When('I configure Bugsnag for {string}') do |scenario_name| - if is_platform? :macos - run_mac_fixture(:start_bugsnag, scenario_name) - else - dial_number_for scenario_name - tap_button 11 - end + run_fixture(:start_bugsnag, scenario_name) end When('I run {string} and restart the crashed app') do |scenario_name| @@ -30,17 +17,8 @@ end When('I run {string} and restart the crashed app for {string}') do |scenario_1, scenario_2| - if is_platform? :macos - run_mac_fixture(:run_scenario, scenario_1, wait: true) - run_mac_fixture(:start_bugsnag, scenario_2) - else - steps %( - Given I run "#{scenario_1}" - And the mobile app is not running - And I relaunch the mobile app - And I configure Bugsnag for "#{scenario_2}" - ) - end + run_fixture(:run_scenario, scenario_1, wait_for_crash: true) + run_fixture(:start_bugsnag, scenario_2) end When('I background the app for {int} seconds') do |duration| @@ -53,30 +31,6 @@ end end -def dial_number_for(scenario_name) - number = $scenario_names.index scenario_name - raise "Scenario name #{scenario_name} is not in the list; try running update-scenario-names.sh" if number.nil? - "#{number}".each_char do |button_number| - tap_button button_number.to_i - end -end - -def tap_button(button_number) - row_count = 13 # 0-9, run, start, text box - button_height = window_height / row_count - y = (button_height * button_number) + (button_height / 2) - Appium::TouchAction.new.tap({:x => 50, :y => y}).perform - sleep 0.5 -end - -def window_height - if is_platform? 'Android' - Maze.driver.window_size['height'] + Maze.driver.get_system_bars['navigationBar']['height'] - else - Maze.driver.window_size['height'] - end -end - Then('the mobile app is not running') do wait_for_true do state = app_state() @@ -130,18 +84,40 @@ def wait_for_true raise 'Assertion not passed within 5 seconds' unless assertion_passed end -def run_mac_fixture(action, scenario_name, wait: false) +def run_fixture(action, scenario_name, wait_for_crash: false) + Maze::Server.commands.add({ action: action, scenario_name: scenario_name }) + case Maze::Helper.get_current_platform + when 'android', 'ios' + Appium::TouchAction.new.tap({ x: 200, y: 200 }).perform + wait_for_get_command + if wait_for_crash + step 'the mobile app is not running' + Maze.driver.launch_app + sleep 3 + end + when 'macos' + run_mac_fixture(wait_for_crash) + else + raise 'Unsupported platform' + end +end + +def run_mac_fixture(wait_for_crash) $fixture_pid = Process.spawn( 'features/fixtures/generic/ArchivedBuilds/MacNoEditor/TestFixture-Mac-Shipping.app/Contents/MacOS/TestFixture-Mac-Shipping', - '-action', action.to_s, '-scenario_name', scenario_name, '-windowed', '-resx=720', '-resy=1080', '-unattended', # Prevents "Please update to the latest version of macOS" alert on macOS < 10.15.5 - [:out, :err]=>'TestFixture-Mac-Shipping.log') - if wait + %i[out err] => 'TestFixture-Mac-Shipping.log' + ) + wait_for_get_command + if wait_for_crash Process.wait $fixture_pid $fixture_pid = nil - else - # Ideally we would wait until we know the Scenario::Run() method has been executed - sleep 1 end end + +def wait_for_get_command + count = 100 + sleep 0.1 until Maze::Server.commands.remaining.empty? || (count -= 1) < 1 + raise 'Test fixture did not GET /command' unless Maze::Server.commands.remaining.empty? +end From 34acd3af16e080b86fbfe7b5eeb6e55b5ada2a8f Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 5 May 2022 15:38:25 +0100 Subject: [PATCH 04/10] Capture richer E2E logs on macOS --- features/steps/unreal_steps.rb | 2 +- features/support/env.rb | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/features/steps/unreal_steps.rb b/features/steps/unreal_steps.rb index 4ad0ea63..23892481 100644 --- a/features/steps/unreal_steps.rb +++ b/features/steps/unreal_steps.rb @@ -107,7 +107,7 @@ def run_mac_fixture(wait_for_crash) 'features/fixtures/generic/ArchivedBuilds/MacNoEditor/TestFixture-Mac-Shipping.app/Contents/MacOS/TestFixture-Mac-Shipping', '-windowed', '-resx=720', '-resy=1080', '-unattended', # Prevents "Please update to the latest version of macOS" alert on macOS < 10.15.5 - %i[out err] => 'TestFixture-Mac-Shipping.log' + %i[out err] => :close ) wait_for_get_command if wait_for_crash diff --git a/features/support/env.rb b/features/support/env.rb index aaf2fe8d..0634ca99 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -61,7 +61,29 @@ def app_state Maze.driver.app_state('com.bugsnag.TestFixture') end +Maze.hooks.before do + $started_at = Time.now +end + Maze.hooks.after do |scenario| - Process.kill('KILL', $fixture_pid) if $fixture_pid - $fixture_pid = nil + folder1 = File.join(Dir.pwd, 'maze_output') + folder2 = scenario.failed? ? 'failed' : 'passed' + folder3 = scenario.name.gsub(/[:"& ]/, '_').gsub(/_+/, '_') + + path = File.join(folder1, folder2, folder3) + + FileUtils.makedirs(path) + + case Maze::Helper.get_current_platform + when 'macos' + Process.kill('KILL', $fixture_pid) if $fixture_pid + $fixture_pid = nil + Process.wait( + Process.spawn( + '/usr/bin/log', 'show', '--predicate', 'process == "TestFixture-Mac-Shipping"', + '--style', 'syslog', '--start', $started_at.strftime('%Y-%m-%d %H:%M:%S%z'), + out: File.open(File.join(path, 'TestFixture-Mac-Shipping.log'), 'w') + ) + ) + end end From 1f4935c0ce546b9e9aac99a297bf7b521bcef9ee Mon Sep 17 00:00:00 2001 From: Steve Kirkland-Walton Date: Fri, 6 May 2022 09:13:28 +0100 Subject: [PATCH 05/10] Move Android fixture build to ARM [full ci] --- .buildkite/pipeline.full.yml | 15 +++------------ .buildkite/pipeline.yml | 15 ++++----------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/.buildkite/pipeline.full.yml b/.buildkite/pipeline.full.yml index ef53e5f2..9b45e5f1 100644 --- a/.buildkite/pipeline.full.yml +++ b/.buildkite/pipeline.full.yml @@ -1,3 +1,6 @@ +agents: + queue: macos-12-arm + steps: # # Build Plugins @@ -23,8 +26,6 @@ steps: # UE 4.26 - label: 'Build Plugin - 4.26 Mac' - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "4.26" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -41,8 +42,6 @@ steps: # UE 5.0 - label: 'Build Plugin - 5.0 Mac' - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "5.0" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -64,8 +63,6 @@ steps: # UE 5.0EA - name: ':android: Build E2E - 5.0 Android' depends_on: plugin_5_0 - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "5.0" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -84,8 +81,6 @@ steps: - name: ':ios: Build E2E - 5.0 iOS' depends_on: plugin_5_0 - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "5.0" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -104,8 +99,6 @@ steps: - name: ':mac: Build E2E - 5.0 Mac' depends_on: plugin_5_0 - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "5.0" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -209,8 +202,6 @@ steps: - label: 'E2E Tests - 5.0 macOS 12' depends_on: mac_fixture_5_0 timeout_in_minutes: 10 - agents: - queue: opensource-arm-mac-cocoa-12 plugins: artifacts#v1.5.0: download: diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 7dccc39d..e5439f3e 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,3 +1,6 @@ +agents: + queue: macos-12-arm + steps: # # Build Plugins @@ -24,8 +27,6 @@ steps: # UE 4.27 - label: 'Build Plugin - 4.27 Mac' - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "4.27" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -56,11 +57,9 @@ steps: # UE 4.27 - name: ':android: Build E2E - 4.27 Android' depends_on: plugin_4_27 - agents: - queue: opensource-mac-cocoa-10.15 env: UE_VERSION: "4.27" - DEVELOPER_DIR: "/Applications/Xcode12.app" + DEVELOPER_DIR: "/Applications/Xcode13.app" plugins: artifacts#v1.5.0: download: Build/Plugin/Bugsnag-*-UE_4.27-macOS.zip @@ -76,8 +75,6 @@ steps: - name: ':ios: Build E2E - 4.27 iOS' depends_on: plugin_4_27 - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "4.27" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -96,8 +93,6 @@ steps: - name: ':mac: Build E2E - 4.27 Mac' depends_on: plugin_4_27 - agents: - queue: opensource-arm-mac-cocoa-12 env: UE_VERSION: "4.27" DEVELOPER_DIR: "/Applications/Xcode13.app" @@ -174,8 +169,6 @@ steps: - label: 'E2E Tests - 4.27 macOS 12' depends_on: mac_fixture_4_27 timeout_in_minutes: 10 - agents: - queue: opensource-arm-mac-cocoa-12 plugins: artifacts#v1.5.0: download: From 5a04c3448185d7bffebadcd1f0e8d7624dc72575 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 6 May 2022 10:42:50 +0100 Subject: [PATCH 06/10] Fix improper use of TCHAR_TO_UTF8 --- .../Source/Bugsnag/Private/Android/JNIUtilities.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Plugins/Bugsnag/Source/Bugsnag/Private/Android/JNIUtilities.cpp b/Plugins/Bugsnag/Source/Bugsnag/Private/Android/JNIUtilities.cpp index eee8b4b9..32ddc594 100644 --- a/Plugins/Bugsnag/Source/Bugsnag/Private/Android/JNIUtilities.cpp +++ b/Plugins/Bugsnag/Source/Bugsnag/Private/Android/JNIUtilities.cpp @@ -376,17 +376,12 @@ bool FAndroidPlatformJNI::LoadReferenceCache(JNIEnv* env, JNIReferenceCache* cac jstring FAndroidPlatformJNI::ParseFString(JNIEnv* Env, const FString& Text) { - const char* rawText = TCHAR_TO_UTF8(*Text); - if (rawText) + jstring jText = (*Env).NewStringUTF(TCHAR_TO_UTF8(*Text)); + if (FAndroidPlatformJNI::CheckAndClearException(Env)) { - jstring jText = (*Env).NewStringUTF(rawText); - if (FAndroidPlatformJNI::CheckAndClearException(Env)) - { - return NULL; - } - return jText; + return NULL; } - return NULL; + return jText; } FString FAndroidPlatformJNI::ParseJavaString(JNIEnv* Env, const JNIReferenceCache* Cache, jobject Value) From 1a19d044cf26c1865bcb98d893b66d5abdfef9b6 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 6 May 2022 13:14:40 +0100 Subject: [PATCH 07/10] Test large strings in E2E NotifyScenario --- .../Source/TestFixture/Scenarios/NotifyScenario.cpp | 13 ++++++++++++- features/handled_errors.feature | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/features/fixtures/generic/Source/TestFixture/Scenarios/NotifyScenario.cpp b/features/fixtures/generic/Source/TestFixture/Scenarios/NotifyScenario.cpp index 42bec8d1..c7e0b825 100644 --- a/features/fixtures/generic/Source/TestFixture/Scenarios/NotifyScenario.cpp +++ b/features/fixtures/generic/Source/TestFixture/Scenarios/NotifyScenario.cpp @@ -60,7 +60,18 @@ class NotifyScenario : public Scenario return true; }); - UBugsnagFunctionLibrary::SetContext("pause menu"); + // Check that a large (> 128 byte) string can be safely handled without crashing + UBugsnagFunctionLibrary::SetContext(TEXT(/* spell-checker: disable */ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque gravida sodales" + " nisl, at scelerisque lectus ullamcorper vitae. Integer congue nunc sed gravida " + "ultricies. Donec posuere erat tellus, vel tempus nisl sodales at. Sed nibh turpi" + "s, mollis nec turpis a, cursus tincidunt ipsum. Donec nec sagittis magna. Aliqua" + "m sit amet tellus maximus, vehicula enim ac, tincidunt tortor. Sed eu enim et ma" + "ssa volutpat auctor. Praesent facilisis diam ultricies pharetra dapibus. Pellent" + "esque sit amet ex congue, pharetra felis eu, mollis ligula. Etiam non turpis a t" + "urpis maximus facilisis sed vitae nisi. Curabitur scelerisque ultrices scelerisq" + "ue. Integer semper leo volutpat, venenatis orci ac, facilisis mauris. Curabitur " + "luctus urna a orci lacinia ornare.")); UBugsnagFunctionLibrary::AddFeatureFlag(TEXT("Bugsnag")); diff --git a/features/handled_errors.feature b/features/handled_errors.feature index 339274a6..a7bba4ed 100644 --- a/features/handled_errors.feature +++ b/features/handled_errors.feature @@ -9,7 +9,7 @@ Feature: Reporting handled errors And the error payload field "notifier.dependencies.0.name" is not null And the error payload field "notifier.dependencies.0.url" is not null And the error payload field "notifier.dependencies.0.version" is not null - And the event "context" equals "pause menu" + And the event "context" starts with "Lorem ipsum dolor sit amet" And the event "app.duration" equals 37 And the event "app.durationInForeground" is not null And the event "app.id" equals "com.bugsnag.TestFixture" From a59718d21e587ea19d66c52a0b42b2bb91f33793 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 9 May 2022 11:59:30 +0100 Subject: [PATCH 08/10] Add UE 5.0 support to Makefile (#158) --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 1f2ded9e..0b2ba1db 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,11 @@ UE_VERSION?=4.27 UE_HOME?=/Users/Shared/Epic Games/UE_$(UE_VERSION) UE_BUILD=$(UE_HOME)/Engine/Build/BatchFiles/Mac/Build.sh UE_RUNUAT=$(UE_HOME)/Engine/Build/BatchFiles/RunUAT.sh +ifeq ($(findstring 5.,$(UE_VERSION)),5.) +UE_EDITOR=$(UE_HOME)/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor +else UE_EDITOR=$(UE_HOME)/Engine/Binaries/Mac/UE4Editor.app/Contents/MacOS/UE4Editor +endif UE_BUILDCOOK_ARGS=BuildCookRun -nocompileeditor -nop4 -stage -package \ -clientconfig=Shipping -compressed -pak -prereqs \ -build -utf8output -cook From c06e61c3b551c3ac91792e7ecc96ec4863bf6993 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 11 May 2022 10:05:10 +0100 Subject: [PATCH 09/10] Bump bugsnag-cocoa to v6.16.8 --- CHANGELOG.md | 1 + deps/bugsnag-cocoa | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4faa2bd..acab6f74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Changelog ## TBD * Updates the bugsnag-android dependency from v5.22.0 to [v5.22.1](https://github.com/bugsnag/bugsnag-android/blob/master/CHANGELOG.md#5221-2022-04-28) +* Updates the bugsnag-cocoa dependency from v6.16.6 to [v6.16.8](https://github.com/bugsnag/bugsnag-cocoa/blob/master/CHANGELOG.md#6168-2022-05-04) ## 1.3.1 (2022-04-26) diff --git a/deps/bugsnag-cocoa b/deps/bugsnag-cocoa index 318aae7b..450d2172 160000 --- a/deps/bugsnag-cocoa +++ b/deps/bugsnag-cocoa @@ -1 +1 @@ -Subproject commit 318aae7b05695145cea34aa6bea0616388ee0e77 +Subproject commit 450d21727f99727d42d5d484b5c07df16c119b16 From 6d693f193f51645d65ee3d1ce49703c103504c5f Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 11 May 2022 10:05:43 +0100 Subject: [PATCH 10/10] Release v1.4.0 --- CHANGELOG.md | 5 ++++- Plugins/Bugsnag/Bugsnag.uplugin | 4 ++-- Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml | 2 +- Plugins/Bugsnag/Source/Bugsnag/Private/Version.h | 2 +- VERSION | 2 +- deps/bugsnag-plugin-android-unreal/build.gradle | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acab6f74..bcd7713f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ Changelog ========= -## TBD +## 1.4.0 (2022-05-11) +* Adds official support for Unreal Engine 5.0 🚀 +* Fixes improper use of `TCHAR_TO_UTF8()` that could result in use-after-free on Android. + [#157](https://github.com/bugsnag/bugsnag-unreal/pull/157) * Updates the bugsnag-android dependency from v5.22.0 to [v5.22.1](https://github.com/bugsnag/bugsnag-android/blob/master/CHANGELOG.md#5221-2022-04-28) * Updates the bugsnag-cocoa dependency from v6.16.6 to [v6.16.8](https://github.com/bugsnag/bugsnag-cocoa/blob/master/CHANGELOG.md#6168-2022-05-04) diff --git a/Plugins/Bugsnag/Bugsnag.uplugin b/Plugins/Bugsnag/Bugsnag.uplugin index e0bae6a2..02d1ce18 100644 --- a/Plugins/Bugsnag/Bugsnag.uplugin +++ b/Plugins/Bugsnag/Bugsnag.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 7, - "VersionName": "1.3.1", + "Version": 8, + "VersionName": "1.4.0", "FriendlyName": "Bugsnag", "Description": "Bugsnag is an error monitoring and application stability management solution.", "Category": "Developer", diff --git a/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml b/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml index c3826c09..de349266 100644 --- a/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml +++ b/Plugins/Bugsnag/Source/Bugsnag/Bugsnag_UPL.xml @@ -73,7 +73,7 @@ - com.bugsnag,bugsnag-plugin-android-unreal,1.3.1 + com.bugsnag,bugsnag-plugin-android-unreal,1.4.0 com.bugsnag,bugsnag-android,5.22.1 diff --git a/Plugins/Bugsnag/Source/Bugsnag/Private/Version.h b/Plugins/Bugsnag/Source/Bugsnag/Private/Version.h index 394d8cd5..4ea30b1c 100644 --- a/Plugins/Bugsnag/Source/Bugsnag/Private/Version.h +++ b/Plugins/Bugsnag/Source/Bugsnag/Private/Version.h @@ -4,4 +4,4 @@ #define BUGSNAG_UNREAL_NAME "Unreal Bugsnag Notifier" #define BUGSNAG_UNREAL_URL "https://github.com/bugsnag/bugsnag-unreal" -#define BUGSNAG_UNREAL_VERSION_STRING "1.3.1" +#define BUGSNAG_UNREAL_VERSION_STRING "1.4.0" diff --git a/VERSION b/VERSION index 3a3cd8cc..88c5fb89 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.1 +1.4.0 diff --git a/deps/bugsnag-plugin-android-unreal/build.gradle b/deps/bugsnag-plugin-android-unreal/build.gradle index 23f98f2c..d7177ace 100644 --- a/deps/bugsnag-plugin-android-unreal/build.gradle +++ b/deps/bugsnag-plugin-android-unreal/build.gradle @@ -40,7 +40,7 @@ task generatePom { pom { project { groupId 'com.bugsnag' - version '1.3.1' + version '1.4.0' packaging 'aar' } }.writeTo("$buildDir/outputs/aar/bugsnag-plugin-android-unreal-release.pom")