Skip to content

Commit b50057e

Browse files
authored
Distribute FTL tests amongst different device models (#1468)
* Modify TEST_DEVICES to have a list of device models for each device_type. This allows us to randomly select FTL devices to distribute the load. * Remove saving the random device selections per-machine * Fix typo * Use random device selection in firebase-test-lab action. * Format. * Add quotes. * Add warning. * Add --get_ftl_device_list to get the full device list. * Fix device list and add more devices. * Use new tagged version of firebase-test-lab action.
1 parent 314ac67 commit b50057e

File tree

4 files changed

+170
-91
lines changed

4 files changed

+170
-91
lines changed

.github/workflows/integration_tests.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ jobs:
10201020
id: device-info
10211021
run: |
10221022
echo "device_type=$( python scripts/gha/print_matrix_configuration.py -k ${{ matrix.android_device }} -get_device_type)" >> $GITHUB_OUTPUT
1023-
echo "device=$( python scripts/gha/print_matrix_configuration.py -k ${{ matrix.android_device }} -get_ftl_device)" >> $GITHUB_OUTPUT
1023+
echo "device=$( python scripts/gha/print_matrix_configuration.py -k ${{ matrix.android_device }} -get_ftl_device_list)" >> $GITHUB_OUTPUT
10241024
- name: Setup java 8 for test_simulator.py
10251025
uses: actions/setup-java@v3
10261026
with:
@@ -1037,13 +1037,14 @@ jobs:
10371037
--ci
10381038
- id: ftl_test
10391039
if: steps.device-info.outputs.device_type == 'ftl'
1040-
uses: FirebaseExtended/github-actions/firebase-test-lab@v1.2
1040+
uses: FirebaseExtended/github-actions/firebase-test-lab@v1.3
10411041
timeout-minutes: 90
10421042
with:
10431043
credentials_json: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIALS }}
10441044
testapp_dir: testapps
10451045
test_type: "game-loop"
1046-
test_devices: ${{ steps.device-info.outputs.device }}
1046+
test_devices: '${{ steps.device-info.outputs.device }}'
1047+
test_device_selection: random
10471048
max_attempts: 3
10481049
validator: ${GITHUB_WORKSPACE}/scripts/gha/integration_testing/ftl_gha_validator.py
10491050
additional_flags: '--client-details matrixLabel=android-${{ github.run_id }}-${{ matrix.build_os }}-${{ matrix.android_device }}'
@@ -1148,7 +1149,7 @@ jobs:
11481149
id: device-info
11491150
run: |
11501151
echo "device_type=$( python scripts/gha/print_matrix_configuration.py -k ${{ matrix.ios_device }} -get_device_type)" >> $GITHUB_OUTPUT
1151-
echo "device=$( python scripts/gha/print_matrix_configuration.py -k ${{ matrix.ios_device }} -get_ftl_device)" >> $GITHUB_OUTPUT
1152+
echo "device=$( python scripts/gha/print_matrix_configuration.py -k ${{ matrix.ios_device }} -get_ftl_device_list)" >> $GITHUB_OUTPUT
11521153
- name: Set up Node (16)
11531154
uses: actions/setup-node@v3
11541155
with:
@@ -1181,13 +1182,14 @@ jobs:
11811182
--ci
11821183
- id: ftl_test
11831184
if: steps.device-info.outputs.device_type == 'ftl'
1184-
uses: FirebaseExtended/github-actions/firebase-test-lab@v1.2
1185+
uses: FirebaseExtended/github-actions/firebase-test-lab@v1.3
11851186
timeout-minutes: 90
11861187
with:
11871188
credentials_json: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIALS }}
11881189
testapp_dir: testapps
11891190
test_type: "game-loop"
1190-
test_devices: ${{ steps.device-info.outputs.device }}
1191+
test_devices: '${{ steps.device-info.outputs.device }}'
1192+
test_device_selection: random
11911193
max_attempts: 3
11921194
validator: ${GITHUB_WORKSPACE}/scripts/gha/integration_testing/ftl_gha_validator.py
11931195
additional_flags: '--client-details matrixLabel=ios-${{ github.run_id }}-${{ matrix.build_os }}-${{ matrix.ios_device }}'

scripts/gha/print_matrix_configuration.py

Lines changed: 100 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import argparse
5858
import json
5959
import os
60+
import random
6061
import re
6162
import subprocess
6263
import sys
@@ -164,23 +165,94 @@
164165
# Check currently supported models and versions with the following commands:
165166
# gcloud firebase test android models list
166167
# gcloud firebase test ios models list
168+
169+
# For each device type, one entry from the list will be used for each
170+
# run. If there is only one device type listed, it will be chosen by
171+
# default.
172+
#
173+
# Note: All entries in a given list must have the same type, (ftl or virtual).
167174
TEST_DEVICES = {
168-
"android_target": {"type": "ftl", "device": "model=blueline,version=28"},
169-
"android_latest": {"type": "ftl", "device": "model=oriole,version=33"},
170-
"emulator_ftl_target": {"type": "ftl", "device": "model=Pixel2,version=28"},
171-
"emulator_ftl_latest": {"type": "ftl", "device": "model=Pixel2.arm,version=32"},
172-
"emulator_target": {"type": "virtual", "image":"system-images;android-30;google_apis;x86_64"},
173-
"emulator_latest": {"type": "virtual", "image":"system-images;android-32;google_apis;x86_64"},
174-
"emulator_32bit": {"type": "virtual", "image":"system-images;android-30;google_apis;x86"},
175-
"ios_min": {"type": "ftl", "device": "model=iphone8,version=14.7"},
176-
"ios_target": {"type": "ftl", "device": "model=iphone13pro,version=15.7"},
177-
"ios_latest": {"type": "ftl", "device": "model=iphone11pro,version=16.6"},
178-
"simulator_min": {"type": "virtual", "name":"iPhone 8", "version":"15.2"},
179-
"simulator_target": {"type": "virtual", "name":"iPhone 8", "version":"16.1"},
180-
"simulator_latest": {"type": "virtual", "name":"iPhone 11", "version":"16.1"},
181-
"tvos_simulator": {"type": "virtual", "name":"Apple TV", "version":"16.1"},
175+
"android_target": [
176+
{"type": "ftl", "device": "model=blueline,version=28"}, # Pixel 3
177+
{"type": "ftl", "device": "model=dreamlte,version=28"}, # Galaxy S8
178+
{"type": "ftl", "device": "model=gts3lltevzw,version=28"}, # Galaxy Tab S3
179+
{"type": "ftl", "device": "model=vivo_1906,version=28"}, # vivo 1906
180+
{"type": "ftl", "device": "model=SH-01L,version=28"}, # AQUOS sense2 SH-01L
181+
{"type": "ftl", "device": "model=PD1901,version=28"}, # VIVO 1901
182+
],
183+
"android_latest": [
184+
{"type": "ftl", "device": "model=oriole,version=33"}, # Pixel 6
185+
{"type": "ftl", "device": "model=panther,version=33"}, # Pixel 7
186+
{"type": "ftl", "device": "model=lynx,version=33"}, # Pixel 7a
187+
{"type": "ftl", "device": "model=cheetah,version=33"}, # Pixel 7 Pro
188+
{"type": "ftl", "device": "model=felix,version=33"}, # Pixel Fold
189+
{"type": "ftl", "device": "model=tangorpro,version=33"}, # Pixel Tablet
190+
{"type": "ftl", "device": "model=gts8uwifi,version=33"}, # Galaxy Tab S8 Ultra
191+
{"type": "ftl", "device": "model=b0q,version=33"}, # Galaxy S22 Ultra
192+
{"type": "ftl", "device": "model=b4q,version=33"}, # Galaxy Z Flip4
193+
],
194+
"emulator_ftl_target": [
195+
{"type": "ftl", "device": "model=Pixel2,version=28"},
196+
{"type": "ftl", "device": "model=Pixel2.arm,version=28"},
197+
{"type": "ftl", "device": "model=MediumPhone.arm,version=28"},
198+
{"type": "ftl", "device": "model=MediumTablet.arm,version=28"},
199+
{"type": "ftl", "device": "model=SmallPhone.arm,version=28"},
200+
],
201+
"emulator_ftl_latest": [
202+
{"type": "ftl", "device": "model=Pixel2.arm,version=32"},
203+
{"type": "ftl", "device": "model=MediumPhone.arm,version=32"},
204+
{"type": "ftl", "device": "model=MediumTablet.arm,version=32"},
205+
{"type": "ftl", "device": "model=SmallPhone.arm,version=32"},
206+
],
207+
"emulator_target": [ {"type": "virtual", "image":"system-images;android-30;google_apis;x86_64"} ],
208+
"emulator_latest": [ {"type": "virtual", "image":"system-images;android-32;google_apis;x86_64"} ],
209+
"emulator_32bit": [ {"type": "virtual", "image":"system-images;android-30;google_apis;x86"} ],
210+
"ios_min": [
211+
# Slightly different OS versions because of limited FTL selection.
212+
{"type": "ftl", "device": "model=iphone8,version=14.7"},
213+
{"type": "ftl", "device": "model=iphone11pro,version=14.7"},
214+
{"type": "ftl", "device": "model=iphone12pro,version=14.8"},
215+
],
216+
"ios_target": [
217+
# Slightly different OS versions because of limited FTL selection.
218+
{"type": "ftl", "device": "model=iphone13pro,version=15.7"},
219+
{"type": "ftl", "device": "model=iphone8,version=15.7"},
220+
{"type": "ftl", "device": "model=ipadmini4,version=15.4"},
221+
],
222+
"ios_latest": [
223+
{"type": "ftl", "device": "model=iphone14pro,version=16.6"},
224+
{"type": "ftl", "device": "model=iphone11pro,version=16.6"},
225+
{"type": "ftl", "device": "model=iphone8,version=16.6"},
226+
{"type": "ftl", "device": "model=ipad10,version=16.6"},
227+
],
228+
"simulator_min": [ {"type": "virtual", "name":"iPhone 8", "version":"15.2"} ],
229+
"simulator_target": [ {"type": "virtual", "name":"iPhone 8", "version":"16.1"} ],
230+
"simulator_latest": [ {"type": "virtual", "name":"iPhone 11", "version":"16.1"} ],
231+
"tvos_simulator": [ {"type": "virtual", "name":"Apple TV", "version":"16.1"} ],
182232
}
183233

234+
# Easy accesssor for getting a TEST_DEVICES entry. Note that once a device model
235+
# is chosen on a specific machine, it will be maintained on that same machine.
236+
def get_test_device(device_type):
237+
"""Get a TEST_DEVICES entry for the given device type.
238+
239+
If there is more than one entry listed for the given device type, one will be
240+
selected randomly. Once a selection is made for a given device_type, the same
241+
selection will be returned on subsequent calls.
242+
243+
Args:
244+
device_type(str): Device type (key for TEST_DEVICES dictionary)
245+
246+
Returns:
247+
A single entry from TEST_DEVICES (dictionary), or None if the key is not
248+
found.
249+
250+
"""
251+
device_entry = TEST_DEVICES.get(device_type)
252+
if not isinstance(device_entry, list):
253+
# If None or just a dictionary (not in an array)
254+
return device_entry
255+
return random.choice(device_entry)
184256

185257

186258
def get_value(workflow, test_matrix, parm_key, config_parms_only=False):
@@ -208,7 +280,7 @@ def get_value(workflow, test_matrix, parm_key, config_parms_only=False):
208280
if test_matrix and test_matrix in workflow_block["matrix"]:
209281
if parm_key in workflow_block["matrix"][test_matrix]:
210282
return workflow_block["matrix"][test_matrix][parm_key]
211-
283+
212284
return workflow_block[parm_type_key][parm_key]
213285

214286
else:
@@ -223,8 +295,8 @@ def filter_devices(devices, device_type):
223295
""" Filter device by device_type
224296
"""
225297
device_type = device_type.replace("real","ftl")
226-
filtered_value = filter(lambda device: TEST_DEVICES.get(device).get("type") in device_type, devices)
227-
return list(filtered_value)
298+
filtered_value = filter(lambda device: get_test_device(device).get("type") in device_type, devices)
299+
return list(filtered_value)
228300

229301

230302
def print_value(value):
@@ -343,7 +415,7 @@ def filter_platforms_on_apis(platforms, apis):
343415
supported_apis = [api for api in apis if config.get_api(api).tvos_target]
344416
if not supported_apis:
345417
platforms.remove("tvOS")
346-
418+
347419
return platforms
348420

349421

@@ -361,11 +433,14 @@ def main():
361433
return
362434

363435
if args.get_device_type:
364-
print(TEST_DEVICES.get(args.parm_key).get("type"))
365-
return
436+
print(get_test_device(args.parm_key).get("type"))
437+
return
366438
if args.get_ftl_device:
367-
print(TEST_DEVICES.get(args.parm_key).get("device"))
368-
return
439+
print(get_test_device(args.parm_key).get("device"))
440+
return
441+
if args.get_ftl_device_list:
442+
print(";".join([entry.get("device") for entry in TEST_DEVICES.get(args.parm_key)]))
443+
return
369444

370445
if args.expanded:
371446
test_matrix = EXPANDED_KEY
@@ -395,8 +470,10 @@ def parse_cmdline_args():
395470
parser.add_argument('-o', '--override', help='Override existing value with provided value')
396471
parser.add_argument('-get_device_type', action='store_true', help='Get the device type, used with -k $device')
397472
parser.add_argument('-get_ftl_device', action='store_true', help='Get the ftl test device, used with -k $device')
473+
parser.add_argument('-get_ftl_device_list', action='store_true',
474+
help='Get the FTL device list (semicolon-delimited) for the given -k $device')
398475
parser.add_argument('-t', '--device_type', default=['real', 'virtual'], help='Test on which type of mobile devices')
399-
parser.add_argument('--apis', default=PARAMETERS["integration_tests"]["config"]["apis"],
476+
parser.add_argument('--apis', default=PARAMETERS["integration_tests"]["config"]["apis"],
400477
help='Exclude platform based on apis. Certain platform does not support all apis. e.g. tvOS does not support messaging')
401478
args = parser.parse_args()
402479
return args

scripts/gha/summarize_test_results.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
from absl import logging
5050
from print_matrix_configuration import PARAMETERS
5151
from print_matrix_configuration import BUILD_CONFIGS
52-
from print_matrix_configuration import TEST_DEVICES
52+
from print_matrix_configuration import get_test_device
5353

5454
import glob
5555
import re
@@ -388,17 +388,17 @@ def combine_config(platform, config, config_value, k):
388388
if len(config_value) > 1 and len(config) == len(config_value):
389389
config = ["All %d %s" % (len(config_value), config_name)]
390390
elif config_name == "ios_device":
391-
ftl_devices = set(filter(lambda device: TEST_DEVICES.get(device).get("type") in "ftl", config_value))
392-
simulators = set(filter(lambda device: TEST_DEVICES.get(device).get("type") in "virtual", config_value))
391+
ftl_devices = set(filter(lambda device: get_test_device(device).get("type") in "ftl", config_value))
392+
simulators = set(filter(lambda device: get_test_device(device).get("type") in "virtual", config_value))
393393
if len(ftl_devices) > 1 and ftl_devices.issubset(set(config)):
394394
config.insert(0, "All %d FTL Devices" % len(ftl_devices))
395395
config = [x for x in config if (x not in ftl_devices)]
396396
if len(simulators) > 1 and simulators.issubset(set(config)):
397397
config.insert(0, "All %d Local Simulators" % len(simulators))
398398
config = [x for x in config if (x not in simulators)]
399399
elif config_name == "android_device":
400-
ftl_devices = set(filter(lambda device: TEST_DEVICES.get(device).get("type") in "ftl", config_value))
401-
emulators = set(filter(lambda device: TEST_DEVICES.get(device).get("type") in "virtual", config_value))
400+
ftl_devices = set(filter(lambda device: get_test_device(device).get("type") in "ftl", config_value))
401+
emulators = set(filter(lambda device: get_test_device(device).get("type") in "virtual", config_value))
402402
if len(ftl_devices) > 1 and ftl_devices.issubset(set(config)):
403403
config.insert(0, "All %d FTL Devices" % len(ftl_devices))
404404
config = [x for x in config if (x not in ftl_devices)]

0 commit comments

Comments
 (0)