Scripts/DeviceFarmScripts/run_ios_ci.py (111 lines of code) (raw):

import argparse import sys import os import time import datetime import requests # - for uploading files import boto3 parser = argparse.ArgumentParser(description="Utility script to upload and run Device tests on AWS Device Farm for CI") parser.add_argument('--run_id', required=True, help="A unique number for each workflow run within a repository") parser.add_argument('--run_attempt', required=True, help="A unique number for each attempt of a particular workflow run in a repository") parser.add_argument('--project_arn', required=True, help="Arn for the Device Farm Project the apk will be tested on") parser.add_argument('--device_pool_arn', required=True, help="Arn for device pool of the Device Farm Project the apk will be tested on") parser.add_argument('--test_spec_file_path', required=True, help="Path to the test spec file for Device Farm test") parser.add_argument('--test_file_path', required=True, help="Path to the zip files that contains test scripts to upload to device farm") parser.add_argument('--app_file_path', required=True, help="Path to the executable .app file") def upload_file(client, projectArn, unique_prefix, filepath, _type): filename = os.path.basename(filepath) print('Upload file name: ' + unique_prefix + "_" + filename) response = client.create_upload(projectArn=projectArn, name=unique_prefix+"_"+filename, type=_type ) # Get the upload ARN, which we'll return later. upload_arn = response['upload']['arn'] # We're going to extract the URL of the upload and use Requests to upload it upload_url = response['upload']['url'] with open(filepath, 'rb') as file_stream: print(f"Uploading {filepath} to Device Farm as {response['upload']['name']}... ", end='') put_req = requests.put(upload_url, data=file_stream) print('File upload status code: ' + str(put_req.status_code) + ' reason: ' + put_req.reason) if not put_req.ok: raise Exception("Couldn't upload, requests said we're not ok. Requests says: " + put_req.reason) started = datetime.datetime.now() device_farm_upload_status = client.get_upload(arn=upload_arn) while device_farm_upload_status['upload']['status'] != 'SUCCEEDED': print(f"Upload of {filename} in state {response['upload']['status']} after " + str( datetime.datetime.now() - started)) if device_farm_upload_status['upload']['status'] == 'FAILED': print('File upload status code: ' + str(device_farm_upload_status.status_code) + ' reason: ' + device_farm_upload_status.reason) print('Upload failed to process') sys.exit(-1) time.sleep(1) device_farm_upload_status = client.get_upload(arn=upload_arn) return upload_arn def main(): args = parser.parse_args() run_id = args.run_id run_attempt = args.run_attempt project_arn = args.project_arn device_pool_arn = args.device_pool_arn test_spec_file_path = args.test_spec_file_path test_file_path = args.test_file_path app_file_path = args.app_file_path region = os.getenv('AWS_DEVICE_FARM_REGION') print("Beginning Device Farm Setup \n") # Create Boto3 client for Device Farm try: client = boto3.client('devicefarm', region_name=region) except Exception: print("Error - could not make Boto3 client. Credentials likely could not be sourced") sys.exit(-1) print("Boto3 client established") # Upload the crt library shell app to Device Farm unique_prefix = 'CI-' + run_id + '-' + run_attempt device_farm_app_upload_arn = upload_file(client, project_arn, unique_prefix, app_file_path, 'IOS_APP') device_farm_test_upload_arn = upload_file(client, project_arn, unique_prefix, test_file_path, 'APPIUM_PYTHON_TEST_PACKAGE') device_farm_test_spec_upload_arn = upload_file(client, project_arn, unique_prefix, test_spec_file_path, 'INSTRUMENTATION_TEST_SPEC') print('scheduling run') schedule_run_response = client.schedule_run( projectArn=project_arn, appArn=device_farm_app_upload_arn, devicePoolArn=device_pool_arn, name=unique_prefix, test={ "type": "APPIUM_PYTHON", "testSpecArn": device_farm_test_spec_upload_arn, "testPackageArn": device_farm_test_upload_arn }, executionConfiguration={ 'jobTimeoutMinutes': 30 } ) device_farm_run_arn = schedule_run_response['run']['arn'] run_start_time = schedule_run_response['run']['started'] run_start_date_time = run_start_time.strftime("%m/%d/%Y, %H:%M:%S") print('run scheduled at ' + run_start_date_time) get_run_response = client.get_run(arn=device_farm_run_arn) while get_run_response['run']['result'] == 'PENDING': time.sleep(10) get_run_response = client.get_run(arn=device_farm_run_arn) run_end_time = datetime.datetime.now() run_end_date_time = run_end_time.strftime("%m/%d/%Y, %H:%M:%S") print('Run ended at ' + run_end_date_time + ' with result: ' + get_run_response['run']['result']) is_success = True if get_run_response['run']['result'] != 'PASSED': print('run has failed with result ' + get_run_response['run']['result']) is_success = False # If Clean up is not executed due to the job being cancelled in CI, the uploaded files will not be deleted # from the Device Farm project and must be deleted manually. # Clean up print('Deleting app file from Device Farm project') client.delete_upload( arn=device_farm_app_upload_arn ) print('Deleting test package from Device Farm project') client.delete_upload( arn=device_farm_test_upload_arn ) print('Deleting test spec file from Device Farm project') client.delete_upload( arn=device_farm_test_spec_upload_arn ) if is_success == False: print('Exiting with fail') sys.exit(-1) print('Exiting with success') if __name__ == "__main__": main()