Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
47ebaf3
Add Android tests to integration tests workflow
anonymous-akorn Sep 9, 2020
2b69d2b
Fix flag names in integration test workflow
anonymous-akorn Sep 9, 2020
c2ebb08
Merge branch 'dev' into feature/ak-integration-tests
anonymous-akorn Sep 9, 2020
e1c690a
Catch timeouts as normal testapp failures
anonymous-akorn Sep 10, 2020
ab71fe5
Merge branch 'feature/ak-integration-tests' of https://github.com/fir…
anonymous-akorn Sep 10, 2020
6c6d6e5
Run Android integration tests even on a failed prior step
anonymous-akorn Sep 10, 2020
cbd594a
Merge branch 'dev' into feature/ak-integration-tests
anonymous-akorn Sep 10, 2020
5ba6280
Run tests when not cancelled instead of success+failure.
anonymous-akorn Sep 11, 2020
15059fc
Merge branch 'feature/ak-integration-tests' of https://github.com/fir…
anonymous-akorn Sep 11, 2020
998740b
Add Windows support to Android integration tests
anonymous-akorn Sep 23, 2020
9b006df
Merge remote-tracking branch 'origin/dev' into feature/ak-integration…
anonymous-akorn Sep 24, 2020
6fb2a08
Use Windows gradle wrapper on Windows.
anonymous-akorn Sep 24, 2020
3529f61
Remove ./ from path in Windows
anonymous-akorn Sep 24, 2020
0744963
Fix paths on windows
anonymous-akorn Sep 24, 2020
83481dd
Remove backslashes from path written to gradle settings.
anonymous-akorn Sep 25, 2020
299c3d7
Assign modified string for sdk directory
anonymous-akorn Sep 25, 2020
23b8aa4
Handle permission errors when deleting intermediate directories
anonymous-akorn Sep 25, 2020
65df902
Workaround Windows Cloud SDK bug on GHA
anonymous-akorn Oct 2, 2020
e4e875c
Fix test lab paths on Windows and add checks
anonymous-akorn Oct 2, 2020
d7709f5
Merge branch 'dev' into feature/ak-integration-tests
anonymous-akorn Oct 5, 2020
5a0b83d
Fix missing tools on Windows
anonymous-akorn Oct 5, 2020
7456d69
Set CLOUDSDK_PYTHON env var even on failure
anonymous-akorn Oct 5, 2020
a2a3238
Minor formatting
anonymous-akorn Oct 7, 2020
d1ff242
Merge branch 'dev' into feature/ak-integration-tests
anonymous-akorn Oct 7, 2020
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ jobs:
- name: Set env vars(all)
run: echo "::set-env name=VCPKG_RESPONSE_FILE::external/vcpkg_${{ env.VCPKG_TRIPLET }}_response_file.txt"

- name: Add msbuild to PATH (windows)
if: startsWith(matrix.os, 'windows')
uses: microsoft/setup-msbuild@v1.0.1

- name: Cache vcpkg C++ dependencies
if: matrix.target_platform == 'Desktop'
id: cache_vcpkg
Expand All @@ -91,6 +95,7 @@ jobs:

- name: Install SDK Android prerequisites
if: matrix.target_platform == 'Android'
shell: bash
run: |
build_scripts/android/install_prereqs.sh

Expand All @@ -105,6 +110,12 @@ jobs:
NDK_ROOT: '/tmp/android-ndk-r16b'
run: |
python scripts/gha/build_testapps.py --t ${{ github.event.inputs.apis }} --p ${{ matrix.target_platform }} --output_directory ${{ github.workspace }} --use_vcpkg --execute_desktop_testapp --noadd_timestamp

# Workaround for https://github.com/GoogleCloudPlatform/github-actions/issues/100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: add a new line above

# Must be run after the Python setup action
- name: Set CLOUDSDK_PYTHON (Windows)
if: startsWith(matrix.os, 'windows') && !cancelled()
run: echo "::set-env name=CLOUDSDK_PYTHON::${{env.pythonLocation}}\python.exe"
- name: Install Cloud SDK for mobile integration tests
if: matrix.target_platform != 'Desktop' && !cancelled()
uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
Expand Down
39 changes: 28 additions & 11 deletions scripts/gha/build_testapps.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ def main(argv):
platforms = FLAGS.platforms
testapps = FLAGS.testapps

sdk_dir = _fix_path(FLAGS.sdk_dir)
output_dir = _fix_path(FLAGS.output_directory)
root_dir = _fix_path(FLAGS.root_dir)
provisions_dir = _fix_path(FLAGS.provisions_dir)

update_pod_repo = FLAGS.update_pod_repo
if FLAGS.add_timestamp:
timestamp = datetime.datetime.now().strftime("%Y_%m_%d-%H_%M_%S")
Expand All @@ -204,7 +209,7 @@ def main(argv):
config = config_reader.read_config()
cmake_flags = _get_desktop_compiler_flags(FLAGS.compiler, config.compilers)
if FLAGS.use_vcpkg:
vcpkg = Vcpkg.generate(os.path.join(FLAGS.sdk_dir, config.vcpkg_dir))
vcpkg = Vcpkg.generate(os.path.join(sdk_dir, config.vcpkg_dir))
vcpkg.install_and_run()
cmake_flags.extend(vcpkg.cmake_flags)

Expand All @@ -215,12 +220,12 @@ def main(argv):
testapp=testapp,
platforms=platforms,
api_config=config.get_api(testapp),
output_dir=os.path.expanduser(FLAGS.output_directory),
sdk_dir=os.path.expanduser(FLAGS.sdk_dir),
output_dir=output_dir,
sdk_dir=sdk_dir,
timestamp=timestamp,
builder_dir=pathlib.Path(__file__).parent.absolute(),
root_dir=os.path.expanduser(FLAGS.root_dir),
provisions_dir=os.path.expanduser(FLAGS.provisions_dir),
root_dir=root_dir,
provisions_dir=provisions_dir,
ios_sdk=FLAGS.ios_sdk,
dev_team=config.apple_team_id,
cmake_flags=cmake_flags,
Expand Down Expand Up @@ -339,17 +344,21 @@ def _get_desktop_compiler_flags(compiler, compiler_table):

def _build_android(project_dir, sdk_dir):
"""Builds an Android binary (apk)."""
if platform.system() == "Windows":
gradlew = "gradlew.bat"
sdk_dir = sdk_dir.replace("\\", "/") # Gradle misinterprets backslashes.
else:
gradlew = "./gradlew"
logging.info("Patching gradle properties with path to SDK")
gradle_properties = os.path.join(project_dir, "gradle.properties")
with open(gradle_properties, "a+") as f:
f.write("systemProp.firebase_cpp_sdk.dir=" + sdk_dir + "\n")
# This will log the versions of dependencies for debugging purposes.
_run(
["./gradlew", "dependencies", "--configuration", "debugCompileClasspath"])
_run([gradlew, "dependencies", "--configuration", "debugCompileClasspath"])
# Building for Android has a known issue that can be worked around by
# simply building again. Since building from source takes a while, we don't
# want to retry the build if a different error occurred.
build_args = ["./gradlew", "assembleDebug", "--stacktrace"]
build_args = [gradlew, "assembleDebug", "--stacktrace"]
result = _run(args=build_args, capture_output=True, text=True, check=False)
if result.returncode:
if "Execution failed for task ':generateJsonModel" in result.stderr:
Expand Down Expand Up @@ -485,11 +494,19 @@ def _run(args, timeout=2400, capture_output=False, text=None, check=True):

def _rm_dir_safe(directory_path):
"""Removes directory at given path. No error if dir doesn't exist."""
logging.info("Deleting %s...", directory_path)
try:
shutil.rmtree(directory_path)
logging.info("Deleted %s", directory_path)
except FileNotFoundError:
logging.warning("Tried to delete %s, but it doesn't exist.", directory_path)
except OSError as e:
# There are two known cases where this can happen:
# The directory doesn't exist (FileNotFoundError)
# A file in the directory is open in another process (PermissionError)
logging.warning("Failed to remove directory:\n%s", e)


def _fix_path(path):
"""Expands ~, normalizes slashes, and converts relative paths to absolute."""
return os.path.abspath(os.path.expanduser(path))


@attr.s(frozen=True, eq=False)
Expand Down
48 changes: 40 additions & 8 deletions scripts/gha/test_lab.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import os
import random
import string
import shutil
import subprocess
import threading

Expand Down Expand Up @@ -86,13 +87,26 @@
" to find available values. If none, will use FTL's default.")


# Full paths to the gCloud SDK tools. On Windows, subprocess.run does not check
# the PATH, so we need to find and supply the full paths.
# shutil.which returns None if it doesn't find a tool.
_GCLOUD = shutil.which("gcloud")
_GSUTIL = shutil.which("gsutil")


def main(argv):
if len(argv) > 1:
raise app.UsageError("Too many command-line arguments.")

testapp_dir = FLAGS.testapp_dir
_verify_gcloud_sdk_command_line_tools()

testapp_dir = _fix_path(FLAGS.testapp_dir)
key_file_path = _fix_path(FLAGS.key_file)
code_platform = FLAGS.code_platform

if not os.path.exists(key_file_path):
raise ValueError("Key file path does not exist: %s" % key_file_path)

android_device = Device(model=FLAGS.android_model, version=FLAGS.android_api)
ios_device = Device(model=FLAGS.ios_model, version=FLAGS.ios_version)

Expand All @@ -111,7 +125,7 @@ def main(argv):

logging.info("Testapps found: %s", "\n".join(path for _, _, path in testapps))

_authorize_gcs(FLAGS.key_file)
_authorize_gcs(key_file_path)

gcs_base_dir = _get_base_results_dir()
logging.info("Storing results in %s", _relative_path_to_gs_uri(gcs_base_dir))
Expand Down Expand Up @@ -148,6 +162,19 @@ def main(argv):
return 0 if all_success else 1


def _verify_gcloud_sdk_command_line_tools():
"""Verifies the presence of the gCloud SDK's command line tools."""
logging.info("Looking for gcloud and gsutil tools...")
if not _GCLOUD:
logging.error("gcloud not on path")
if not _GSUTIL:
logging.error("gsutil not on path")
if not _GCLOUD or not _GSUTIL:
raise RuntimeError("Could not find required gCloud SDK tool(s)")
subprocess.run([_GCLOUD, "version"], check=True)
subprocess.run([_GSUTIL, "version"], check=True)


def _get_base_results_dir():
"""Defines the object used on GCS for all tests in this run."""
# We generate a unique directory to store the results by appending 4
Expand All @@ -162,12 +189,12 @@ def _authorize_gcs(key_file):
"""Activates the service account on GCS and specifies the project."""
subprocess.run(
args=[
"gcloud", "auth", "activate-service-account", "--key-file", key_file
_GCLOUD, "auth", "activate-service-account", "--key-file", key_file
],
check=True)
# Keep using this project for subsequent gcloud commands.
subprocess.run(
args=["gcloud", "config", "set", "project", _PROJECT_ID],
args=[_GCLOUD, "config", "set", "project", _PROJECT_ID],
check=True)


Expand Down Expand Up @@ -250,20 +277,25 @@ def _relative_path_to_gs_uri(path):

def _gcs_list_dir(gcs_path):
"""Recursively returns a list of contents for a directory on GCS."""
args = ["gsutil", "ls", "-r", gcs_path]
args = [_GSUTIL, "ls", "-r", gcs_path]
logging.info("Listing GCS contents: %s", " ".join(args))
result = subprocess.run(args=args, capture_output=True, text=True, check=True)
return result.stdout.splitlines()


def _gcs_read_file(gcs_path):
"""Extracts the contents of a file on GCS."""
args = ["gsutil", "cat", gcs_path]
args = [_GSUTIL, "cat", gcs_path]
logging.info("Reading GCS file: %s", " ".join(args))
result = subprocess.run(args=args, capture_output=True, text=True, check=True)
return result.stdout


def _fix_path(path):
"""Expands ~, normalizes slashes, and converts relative paths to absolute."""
return os.path.abspath(os.path.expanduser(path))


@attr.s(frozen=False, eq=False)
class Test(object):
"""Holds data related to the testing of one testapp."""
Expand Down Expand Up @@ -293,9 +325,9 @@ def run(self):
def _gcloud_command(self):
"""Returns the args to send this testapp to FTL on the command line."""
if self.platform == _ANDROID:
cmd = ["gcloud", "firebase", "test", "android", "run"]
cmd = [_GCLOUD, "firebase", "test", "android", "run"]
elif self.platform == _IOS:
cmd = ["gcloud", "beta", "firebase", "test", "ios", "run"]
cmd = [_GCLOUD, "beta", "firebase", "test", "ios", "run"]
else:
raise ValueError("Invalid platform, must be 'Android' or 'iOS'")
return cmd + self.device.get_gcloud_flags() + [
Expand Down