Skip to content

Commit 9163d56

Browse files
authored
Build and execute tvOS Testapps on custom trigger (#559)
Add the ability for CI to execute tvOS builds and vet them with integeration tests on Apple TV simulators. They will not execute as part of the nightly until we include tvOS as a shippable target (ie when we add it to the nightly packaged builds).
1 parent a67198d commit 9163d56

File tree

12 files changed

+133
-86
lines changed

12 files changed

+133
-86
lines changed

.github/workflows/build_starter.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,18 @@ jobs:
200200
unity_platform_name: iOS
201201
additional_cmake_flags: ${{ needs.check_and_prepare.outputs.additional_cmake_flags }}
202202

203+
build_tvos:
204+
name: build-tvos-unity${{ needs.check_and_prepare.outputs.unity_version }}-CPP${{ needs.check_and_prepare.outputs.firebase_cpp_sdk_version }}
205+
uses: ./.github/workflows/build_tvos.yml
206+
needs: [check_and_prepare, decide_build_branch]
207+
if: always() && contains(needs.check_and_prepare.outputs.platform, 'tvOS')
208+
with:
209+
unity_version: ${{needs.check_and_prepare.outputs.unity_version }}
210+
firebase_cpp_sdk_version: ${{ needs.check_and_prepare.outputs.firebase_cpp_sdk_version }}
211+
unity_branch: ${{ needs.decide_build_branch.outputs.build_branch }}
212+
apis: ${{ needs.check_and_prepare.outputs.apis }}
213+
unity_platform_name: 'tvOS,iOS'
214+
203215
build_linux:
204216
name: build-linux-unity${{ needs.check_and_prepare.outputs.unity_version }}-CPP${{ needs.check_and_prepare.outputs.firebase_cpp_sdk_version }}
205217
uses: ./.github/workflows/build_linux.yml

.github/workflows/integration_tests.yml

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -248,35 +248,24 @@ jobs:
248248
name: build_and_test_results
249249
path: build-results-${{ steps.matrix_info.outputs.info }}*
250250
retention-days: ${{ env.artifactRetentionDays }}
251-
- name: Upload build logs artifact
251+
- name: Upload Mobile integration tests artifact
252252
uses: actions/upload-artifact@v3
253-
if: ${{ !cancelled() }}
254-
with:
255-
name: testapps-build-logs-${{ steps.matrix_info.outputs.info }}
256-
path: testapps-${{ steps.matrix_info.outputs.info }}/build-logs
257-
retention-days: ${{ env.artifactRetentionDays }}
258-
- name: Upload Android integration tests artifact
259-
uses: actions/upload-artifact@v3
260-
if: ${{ contains(matrix.platform, 'Android') && !cancelled() }}
253+
if: ${{ contains('Android,iOS,tvOS', matrix.platform) && !cancelled() }}
261254
with:
262-
name: testapps-Android-${{ steps.matrix_info.outputs.artifact_suffix }}
263-
path: testapps-${{ steps.matrix_info.outputs.info }}/Android
255+
name: testapps-${{ matrix.platform }}-${{ steps.matrix_info.outputs.artifact_suffix }}
256+
path: testapps-${{ steps.matrix_info.outputs.info }}
264257
retention-days: ${{ env.artifactRetentionDays }}
265-
- name: Delete Android integration tests artifact
266-
if: ${{ contains(matrix.platform, 'Android') && !cancelled() }}
258+
- name: Delete Mobile integration tests artifact
259+
if: ${{ contains('Android,iOS,tvOS', matrix.platform) && !cancelled() }}
267260
shell: bash
268-
run: rm -rf testapps-${{ steps.matrix_info.outputs.info }}/Android || true
269-
- name: Upload iOS integration tests artifact
261+
run: rm -rf testapps-${{ steps.matrix_info.outputs.info }} || true
262+
- name: Upload Desktop build logs artifact # Mobile build logs are uploaded with integration tests artifact
270263
uses: actions/upload-artifact@v3
271-
if: ${{ contains(matrix.platform, 'iOS') && !cancelled() }}
264+
if: ${{ !contains('Android,iOS,tvOS', matrix.platform) && !cancelled() }}
272265
with:
273-
name: testapps-iOS-${{ steps.matrix_info.outputs.artifact_suffix }}
274-
path: testapps-${{ steps.matrix_info.outputs.info }}/iOS
266+
name: testapps-build-logs-${{ steps.matrix_info.outputs.info }}
267+
path: testapps-${{ steps.matrix_info.outputs.info }}/build-logs
275268
retention-days: ${{ env.artifactRetentionDays }}
276-
- name: Delete iOS integration tests artifact
277-
if: ${{ contains(matrix.platform, 'iOS') && !cancelled() }}
278-
shell: bash
279-
run: rm -rf testapps-${{ steps.matrix_info.outputs.info }}/iOS || true
280269
- name: Upload Linux integration tests artifact
281270
uses: actions/upload-artifact@v3
282271
if: ${{ contains(matrix.platform, 'Linux') && !cancelled() }}
@@ -492,10 +481,11 @@ jobs:
492481
python scripts/gha/read_ftl_test_result.py --test_result '${{ steps.ftl_test.outputs.test_summary }}' \
493482
--output_path testapps/test-results-"${{ steps.matrix_info.outputs.info }}".log
494483
- name: Run Mobile integration tests on virtual device locally
495-
timeout-minutes: 60
484+
timeout-minutes: 120
496485
if: ${{ matrix.device_type == 'virtual' && !cancelled() }}
497486
run: |
498487
python scripts/gha/test_simulator.py --testapp_dir testapps \
488+
--tvos_device "${{ matrix.test_device }}" \
499489
--ios_device "${{ matrix.test_device }}" \
500490
--android_device "${{ matrix.test_device }}" \
501491
--logfile_name ""${{ steps.matrix_info.outputs.info }}"" \

scripts/build_scripts/build_zips.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ def get_targets_args(targets):
193193
support_targets = TVOS_SUPPORT_TARGETS
194194
if not targets:
195195
targets = TVOS_SUPPORT_TARGETS
196+
else:
197+
if 'dynamic_links' in targets:
198+
logging.warning("Dynamic Links is not supported on tvOS. " +
199+
"Removing it from the api build list.")
200+
targets.remove('dynamic_links')
196201

197202
if targets:
198203
# check if all the entries are valid

scripts/gha/build_testapps.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,10 @@ def perform_in_editor_tests(dir_helper, retry_on_license_check=True):
620620

621621
def run_xcodebuild(dir_helper, ios_config, device_type, target_os):
622622
"""Uses xcode project generated by Unity to build an iOS or tvOS binary."""
623-
build_output_dir = os.path.join(dir_helper.output_dir, "ios_output_"+device_type)
623+
if target_os == _TVOS:
624+
build_output_dir = os.path.join(dir_helper.output_dir, "tvos_output_"+device_type)
625+
else:
626+
build_output_dir = os.path.join(dir_helper.output_dir, "ios_output_"+device_type)
624627
_run(
625628
xcodebuild.get_args_for_build(
626629
path=dir_helper.xcode_path,
@@ -668,6 +671,8 @@ def _collect_integration_tests(config, testapps, root_output_dir, output_dir, ar
668671
android_testapp_extension = ".apk"
669672
ios_testapp_dir = "ios_output_" + _DEVICE_REAL
670673
ios_simualtor_testapp_dir = "ios_output_" + _DEVICE_VIRTUAL
674+
tvos_testapp_dir = "tvos_output_" + _DEVICE_REAL
675+
tvos_simulator_testapp_dir = "tvos_output_" + _DEVICE_VIRTUAL
671676
ios_testapp_extension = ".ipa"
672677
ios_simualtor_testapp_extension = ".app"
673678
windows_testapp_dir = "WindowsTestapp"
@@ -676,6 +681,7 @@ def _collect_integration_tests(config, testapps, root_output_dir, output_dir, ar
676681

677682
android_testapp_paths = []
678683
ios_testapp_paths = []
684+
tvos_testapp_paths = []
679685
windows_testapp_paths = []
680686
macos_testapp_paths = []
681687
linux_testapp_paths = []
@@ -689,11 +695,15 @@ def _collect_integration_tests(config, testapps, root_output_dir, output_dir, ar
689695
linux_testapp_paths.append(os.path.join(file_dir, directory))
690696
elif ios_simualtor_testapp_dir in file_dir and directory.endswith(ios_simualtor_testapp_extension):
691697
ios_testapp_paths.append(os.path.join(file_dir, directory))
698+
elif tvos_simulator_testapp_dir in file_dir and directory.endswith(ios_simualtor_testapp_extension):
699+
tvos_testapp_paths.append(os.path.join(file_dir, directory))
692700
for file_name in file_names:
693701
if file_name.endswith(android_testapp_extension):
694702
android_testapp_paths.append(os.path.join(file_dir, file_name))
695703
elif ios_testapp_dir in file_dir and file_name.endswith(ios_testapp_extension):
696704
ios_testapp_paths.append(os.path.join(file_dir, file_name))
705+
elif tvos_testapp_dir in file_dir and file_name.endswith(ios_testapp_extension):
706+
tvos_testapp_paths.append(os.path.join(file_dir, file_name))
697707

698708
artifact_path = os.path.join(root_output_dir, testapps_artifact_dir)
699709
logging.info("Collecting artifacts to: %s", artifact_path)
@@ -704,6 +714,7 @@ def _collect_integration_tests(config, testapps, root_output_dir, output_dir, ar
704714

705715
_collect_integration_tests_platform(config, testapps, artifact_path, android_testapp_paths, _ANDROID)
706716
_collect_integration_tests_platform(config, testapps, artifact_path, ios_testapp_paths, _IOS)
717+
_collect_integration_tests_platform(config, testapps, artifact_path, tvos_testapp_paths, _TVOS)
707718
_collect_integration_tests_platform(config, testapps, artifact_path, windows_testapp_paths, _WINDOWS)
708719
_collect_integration_tests_platform(config, testapps, artifact_path, macos_testapp_paths, _MACOS)
709720
_collect_integration_tests_platform(config, testapps, artifact_path, linux_testapp_paths, _LINUX)
@@ -715,12 +726,13 @@ def _collect_integration_tests_platform(config, testapps, artifact_path, testapp
715726
return
716727

717728
for testapp in testapps:
718-
os.makedirs(os.path.join(artifact_path, platform ,testapp))
729+
os.makedirs(os.path.join(artifact_path, platform, testapp))
730+
719731
for path in testapp_paths:
720732
for testapp in testapps:
721733
if config.get_api(testapp).full_name in path:
722734
if os.path.isfile(path):
723-
shutil.move(path, os.path.join(artifact_path, platform ,testapp))
735+
shutil.move(path, os.path.join(artifact_path, platform, testapp))
724736
else:
725737
shutil.move(path, os.path.join(artifact_path, platform ,testapp, os.path.basename(path)), copy_function = shutil.copytree)
726738
break

scripts/gha/integration_testing/automated_testapp/ftl_testapp_files/IOSPluginWrapper.cs renamed to scripts/gha/integration_testing/automated_testapp/ftl_testapp_files/ApplePluginWrapper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
namespace Firebase.TestLab {
2222
/// <summary>
23-
/// Provides access to the native iOS plugin for Game Loops.
23+
/// Provides access to the native iOS/tvOS plugin for Game Loops.
2424
/// </summary>
25-
internal sealed class IOSPluginWrapper {
25+
internal sealed class ApplePluginWrapper {
2626
public static int GetScenario() {
2727
// Not yet hooked up to a native plugin. Return 1 for now, so that we treat the testapps
2828
// as always running on Game Loops. This is 'harmless', since this assumption currently

scripts/gha/integration_testing/automated_testapp/ftl_testapp_files/IOSTestLabManager.cs renamed to scripts/gha/integration_testing/automated_testapp/ftl_testapp_files/AppleTestLabManager.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,24 @@
1717
using UnityEngine;
1818

1919
namespace Firebase.TestLab {
20-
internal sealed class IOSTestLabManager : TestLabManager {
20+
internal sealed class AppleTestLabManager : TestLabManager {
2121

2222
public override int ScenarioNumber { get { return scenario; } }
2323

2424
readonly int scenario;
2525
readonly StreamWriter logWriter;
2626

27-
private IOSTestLabManager(int scenario, StreamWriter logWriter) {
27+
private AppleTestLabManager(int scenario, StreamWriter logWriter) {
2828
this.scenario = scenario;
2929
this.logWriter = logWriter;
3030
}
3131

3232
protected override void OnFinishTest() {
3333
logWriter.Close();
34-
Application.OpenURL("firebase-game-loop-complete://");
34+
if (Application.platform == RuntimePlatform.IPhonePlayer) {
35+
// OpenURL function doesn't exist on tvOS
36+
Application.OpenURL("firebase-game-loop-complete://");
37+
}
3538
}
3639

3740
public override void LogToResults(string s) {
@@ -40,21 +43,28 @@ public override void LogToResults(string s) {
4043
}
4144

4245
/// <summary>
43-
/// Attempts to create a TestLabManager for an iOS build. If running with Game Loops,
46+
/// Attempts to create a TestLabManager for an iOS/tvOS build. If running with Game Loops,
4447
/// and all necessary information is found in the custom url, this will return a functional
45-
/// IOSTestLabManager. If not running with Game Loops, this will return a dummy.
48+
/// AppleTestLabManager. If not running with Game Loops, this will return a dummy.
4649
/// </summary>
4750
public static TestLabManager Create() {
48-
int scenario = IOSPluginWrapper.GetScenario();
51+
int scenario = ApplePluginWrapper.GetScenario();
4952
if (scenario == -1) { // Not using Game Loops: return dummy.
5053
return new DummyTestLabManager();
5154
}
52-
string logDir = Application.persistentDataPath + "/GameLoopResults";
55+
string logDir = "";
56+
if (Application.platform == RuntimePlatform.IPhonePlayer) {
57+
logDir = Application.persistentDataPath + "/GameLoopResults";
58+
} else if (Application.platform == RuntimePlatform.tvOS) {
59+
// persistentDataPath doesn't exist on tvOS
60+
// files under temporaryCachePath may be cleared at anytime
61+
logDir = Application.temporaryCachePath + "/GameLoopResults";
62+
}
5363
string logPath = string.Format("{0}/Results{1}.json", logDir, scenario);
5464
Directory.CreateDirectory(logDir);
5565
// Logs will be appended, so we need to clear the file first.
5666
File.Delete(logPath);
57-
return new IOSTestLabManager(scenario, File.AppendText(logPath));
67+
return new AppleTestLabManager(scenario, File.AppendText(logPath));
5868
}
5969
}
6070
}

scripts/gha/integration_testing/automated_testapp/ftl_testapp_files/Firebase.TestLabManager.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
<Compile Include="AndroidTestLabManager.cs" />
3939
<Compile Include="DesktopTestLabManager.cs" />
4040
<Compile Include="DummyTestLabManager.cs" />
41-
<Compile Include="IOSPluginWrapper.cs" />
42-
<Compile Include="IOSTestLabManager.cs" />
41+
<Compile Include="ApplePluginWrapper.cs" />
42+
<Compile Include="AppleTestLabManager.cs" />
4343
<Compile Include="LibcWrapper.cs" />
4444
<Compile Include="TestLabManager.cs" />
4545
</ItemGroup>

scripts/gha/integration_testing/automated_testapp/ftl_testapp_files/TestLabManager.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,20 @@ public void NotifyHarnessTestIsComplete() {
5858
public static TestLabManager Instantiate() {
5959
if (Application.platform == RuntimePlatform.Android) {
6060
return AndroidTestLabManager.Create();
61-
} else if (Application.platform == RuntimePlatform.IPhonePlayer) {
62-
return IOSTestLabManager.Create();
61+
} else if (IsApplePlatform(Application.platform)) {
62+
return AppleTestLabManager.Create();
6363
} else if (IsDesktopPlatform(Application.platform)) {
6464
return DesktopTestLabManager.Create();
6565
} else {
6666
return new DummyTestLabManager();
6767
}
6868
}
6969

70+
static bool IsApplePlatform(RuntimePlatform platform) {
71+
return platform == RuntimePlatform.IPhonePlayer
72+
|| platform == RuntimePlatform.tvOS;
73+
}
74+
7075
static bool IsDesktopPlatform(RuntimePlatform platform) {
7176
return platform == RuntimePlatform.OSXPlayer
7277
|| platform == RuntimePlatform.WindowsPlayer

scripts/gha/integration_testing/gameloop_apple/gameloop.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@
404404
SWIFT_EMIT_LOC_STRINGS = YES;
405405
SWIFT_VERSION = 5.0;
406406
TARGETED_DEVICE_FAMILY = 3;
407-
TVOS_DEPLOYMENT_TARGET = 10.1;
407+
TVOS_DEPLOYMENT_TARGET = 12.0;
408408
};
409409
name = Debug;
410410
};
@@ -431,7 +431,7 @@
431431
SWIFT_EMIT_LOC_STRINGS = YES;
432432
SWIFT_VERSION = 5.0;
433433
TARGETED_DEVICE_FAMILY = 3;
434-
TVOS_DEPLOYMENT_TARGET = 10.1;
434+
TVOS_DEPLOYMENT_TARGET = 12.0;
435435
};
436436
name = Release;
437437
};
@@ -454,7 +454,7 @@
454454
SWIFT_VERSION = 5.0;
455455
TARGETED_DEVICE_FAMILY = 3;
456456
TEST_TARGET_NAME = gameloop_tvos;
457-
TVOS_DEPLOYMENT_TARGET = 10.1;
457+
TVOS_DEPLOYMENT_TARGET = 12.0;
458458
};
459459
name = Debug;
460460
};
@@ -477,7 +477,7 @@
477477
SWIFT_VERSION = 5.0;
478478
TARGETED_DEVICE_FAMILY = 3;
479479
TEST_TARGET_NAME = gameloop_tvos;
480-
TVOS_DEPLOYMENT_TARGET = 10.1;
480+
TVOS_DEPLOYMENT_TARGET = 12.0;
481481
};
482482
name = Release;
483483
};

scripts/gha/integration_testing/xcodebuild.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,19 @@
1313
# limitations under the License.
1414

1515
"""Helper module for working with xcode projects.
16-
1716
The tool xcodebuild provides support to build xcode projects from the command
1817
line. The motivation was to simplify usage of xcodebuild, since it was
1918
non-trivial to figure out which flags were needed to get it working in a CI
2019
environment. The options required by the methods in this module were found to
2120
work both locally and on CI, with both the Unity and C++ projects.
22-
2321
get_args_for_build() doesn't perform operations with xcodebuild directly,
2422
instead returning arg sequences. These sequences can be passed to e.g.
2523
subprocess.run to execute the operations.
26-
2724
get_args_for_build() supports both device and simulator builds. For simulator
2825
builds, it suffices to use get_args_for_build() to create a .app that can be
2926
used with simulators. For unsigned device builds, generate .app via
3027
get_args_for_build() step and then use generate_unsigned_ipa() to package
3128
the .app to .ipa.
32-
3329
"""
3430

3531
import os
@@ -38,7 +34,6 @@
3834

3935
def get_args_for_build(path, scheme, output_dir, ios_sdk, target_os, configuration):
4036
"""Constructs subprocess args for an unsigned xcode build.
41-
4237
Args:
4338
path (str): Full path to the project or workspace to build. Must end in
4439
either .xcodeproj or .xcworkspace.
@@ -48,10 +43,8 @@ def get_args_for_build(path, scheme, output_dir, ios_sdk, target_os, configurati
4843
ios_sdk (str): Where this build will be run: "device" or "simulator".
4944
target_os (str): one of "iOS" or "tvOS".
5045
configuration (str): Value for the -configuration flag.
51-
5246
Returns:
5347
Sequence of strings, corresponding to valid args for a subprocess call.
54-
5548
"""
5649
args = [
5750
"xcodebuild",
@@ -102,7 +95,6 @@ def _get_ios_env_from_target(ios_sdk, target_os):
10295

10396
def generate_unsigned_ipa(output_dir, configuration):
10497
"""Creates an unsigned .ipa from an existing .app.
105-
10698
Args:
10799
output_dir (str): Same value as get_args_for_build. The generated unsigned
108100
.ipa will be placed within the subdirectory "<configuration>-iphoneos".

0 commit comments

Comments
 (0)