Automazione di AWS Device Farm - AWS Device Farm

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Automazione di AWS Device Farm

L'accesso programmatico a Device Farm è un modo efficace per automatizzare le attività più comuni da svolgere, come la pianificazione di un'esecuzione o il download degli artefatti per un'esecuzione, una suite o un test. L' AWS SDK e provide offrono i mezzi per farlo. AWS CLI

L' AWS SDK fornisce l'accesso a tutti i AWS servizi, inclusi Device Farm, Amazon S3 e altro ancora. Per ulteriori informazioni, consultare la pagina

Esempio: utilizzo della AWS CLI o dell'SDK per caricare un'app o un test su Device Farm

Gli esempi seguenti mostrano come creare un caricamento su Device Farm utilizzando la AWS CLI o utilizzando l' AWS SDK in varie lingue. I caricamenti sono gli elementi fondamentali per la pianificazione delle esecuzioni di test su Device Farm e includono quanto segue:

I caricamenti vengono creati utilizzando l'CreateUploadAPI. Questa API restituisce un URL predefinito S3 a cui puoi inviare il caricamento utilizzando una richiesta HTTP PUT. L'URL scade dopo 24 ore.

AWS CLI

Nota: questo esempio utilizza lo strumento da riga di comando curl per inviare l'app a Device Farm.

Innanzitutto, crea un progetto se non l'hai già fatto.

$ aws devicefarm create-project --name MyProjectName

Questo mostrerà un output come il seguente:

{ "project": { "name": "MyProjectName", "arn": "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE", "created": 1535675814.414 } }

Quindi, procedi come segue per creare il caricamento e inviarlo a Device Farm. In questo esempio, creeremo il caricamento di un'app Android utilizzando un file APK locale. Per ulteriori informazioni sui tipi di caricamento, inclusi i dettagli sui tipi di caricamento delle app iOS, consulta la nostra documentazione API per la creazione di un Upload.

$ export APP_PATH="/local/path/to/my_sample_app.apk" $ export APP_TYPE="ANDROID_APP"

Per prima cosa, creiamo il caricamento in Device Farm:

$ aws devicefarm create-upload \ --project-arn "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE" \ --name "$(basename "$APP_PATH")" \ --type "$APP_TYPE"

Questo mostrerà un output come il seguente:

{ "upload": { "arn": "arn:aws:devicefarm:us-west-2:385076942068:upload:490a6350-0ba3-43e5-83f5-d2896b069a34/a120e848-c57b-4e8d-a720-d750a0c4d936", "name": "my_sample_app.apk", "created": 1760747318.266, "type": "ANDROID_APP", "status": "INITIALIZED", "url": "https://prod-us-west-2-uploads.s3.dualstack.us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2...", "category": "PRIVATE" } }

Quindi, esegui una chiamata PUT usando curl per inviare l'app al bucket S3 di Device Farm:

$ curl -T "$APP_PATH" "https://prod-us-west-2-uploads.s3.dualstack.us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2..."

Infine, attendi che l'app abbia lo stato «riuscito»:

$ aws devicefarm get-upload --arn "arn:aws:devicefarm:us-west-2:385076942068:upload:490a6350-0ba3-43e5-83f5-d2896b069a34/a120e848-c57b-4e8d-a720-d750a0c4d936"

Questo mostrerà un output come il seguente:

{ "upload": { "arn": "arn:aws:devicefarm:us-west-2:385076942068:upload:490a6350-0ba3-43e5-83f5-d2896b069a34/a120e848-c57b-4e8d-a720-d750a0c4d936", "name": "my_sample_app.apk", "created": 1760747318.266, "type": "ANDROID_APP", "status": "SUCCEEDED", "url": "https://prod-us-west-2-uploads.s3.dualstack.us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2...", "metadata": "{\"activity_name\":\"com.amazonaws.devicefarm.android.referenceapp.Activities.MainActivity\",\"package_name\":\"com.amazonaws.devicefarm.android.referenceapp\",...}", "category": "PRIVATE" } }
Python

Nota: questo esempio utilizza il requests pacchetto di terze parti per inviare l'app a Device Farm, oltre all' AWS SDK per Pythonboto3.

Innanzitutto, crea un progetto se non l'hai già fatto.

import boto3 client = boto3.client("devicefarm", region_name="us-west-2") resp = client.create_project(name="MyProjectName") print(resp) # Response will be something like: # { # "project": { # "name": "MyProjectName", # "arn": "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE", # "created": 1535675814.414 # } # }

Quindi, procedi come segue per creare il caricamento e inviarlo a Device Farm. In questo esempio, creeremo il caricamento di un'app Android utilizzando un file APK locale. Per ulteriori informazioni sui tipi di caricamento, inclusi i dettagli sui tipi di caricamento delle app iOS, consulta la nostra documentazione API per la creazione di un Upload.

import os import time import datetime import requests from pathlib import Path import boto3 def upload_device_farm_file(): project_arn = "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE" app_path = Path("/local/path/to/my_sample_app.apk") file_type = "ANDROID_APP" if not app_path.is_file(): raise RuntimeError(f"{app_path} is not a valid app file path") client = boto3.client("devicefarm", region_name="us-west-2") # 1) Create the upload in Device Farm create = client.create_upload( projectArn=project_arn, name=app_path.name, type=file_type, contentType="application/octet-stream", ) upload = create["upload"] upload_arn = upload["arn"] upload_url = upload["url"] # This will show output such as the following: # { "upload": { "arn": "...", "name": "my_sample_app.apk", "type": "ANDROID_APP", "status": "INITIALIZED", "url": "https://..." } } # 2) Do an HTTP PUT command to push the file to the pre-signed S3 URL with app_path.open("rb") as fh: print(f"Uploading {app_path.name} to Device Farm...") put_resp = requests.put(upload_url, data=fh, headers={"Content-Type": "application/octet-stream"}) put_resp.raise_for_status() # 3) Wait for the app to be in "SUCCEEDED" status (or fail/timeout) timeout_seconds = 30 start = time.time() while True: get_resp = client.get_upload(arn=upload_arn) status = get_resp["upload"]["status"] msg = get_resp["upload"].get("message") or get_resp["upload"].get("metadata") or "" elapsed = datetime.timedelta(seconds=int(time.time() - start)) print(f"[{elapsed}] status={status}{' - ' + msg if msg else ''}") if status == "SUCCEEDED": print(f"Upload complete: {upload_arn}") return upload_arn if status == "FAILED": raise RuntimeError(f"Device Farm failed to process upload: {msg}") if (time.time() - start) > timeout_seconds: raise RuntimeError(f"Timed out after {timeout_seconds}s waiting for upload to process (last status={status}).") time.sleep(1) upload_device_farm_file()
Java

Nota: questo esempio utilizza l' AWS SDK for Java v2 HttpClient e per inviare l'app a Device Farm ed è compatibile con le versioni JDK 11 e successive.

Innanzitutto, crea un progetto se non l'hai già fatto.

import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.devicefarm.DeviceFarmClient; import software.amazon.awssdk.services.devicefarm.model.CreateProjectRequest; import software.amazon.awssdk.services.devicefarm.model.CreateProjectResponse; try (DeviceFarmClient client = DeviceFarmClient.builder() .region(Region.US_WEST_2) .build()) { CreateProjectResponse resp = client.createProject( CreateProjectRequest.builder().name("MyProjectName").build()); System.out.println(resp.project()); // Response will be something like: // Project{name=MyProjectName, arn=arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-..., created=...} }

Quindi, procedi come segue per creare il caricamento e inviarlo a Device Farm. In questo esempio, creeremo il caricamento di un'app Android utilizzando un file APK locale. Per ulteriori informazioni sui tipi di caricamento, inclusi i dettagli sui tipi di caricamento delle app iOS, consulta la nostra documentazione API per la creazione di un Upload.

import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.time.Instant; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.devicefarm.DeviceFarmClient; import software.amazon.awssdk.services.devicefarm.model.CreateUploadRequest; import software.amazon.awssdk.services.devicefarm.model.CreateUploadResponse; import software.amazon.awssdk.services.devicefarm.model.GetUploadRequest; import software.amazon.awssdk.services.devicefarm.model.GetUploadResponse; import software.amazon.awssdk.services.devicefarm.model.Upload; import software.amazon.awssdk.services.devicefarm.model.UploadType; public class DeviceFarmUploader { public static String upload(String projectArn, Path appPath) throws Exception { if (projectArn == null || projectArn.isEmpty()) { throw new IllegalArgumentException("Missing projectArn"); } if (!Files.isRegularFile(appPath)) { throw new IllegalArgumentException("Invalid app path: " + appPath); } String fileName = appPath.getFileName().toString().trim(); UploadType type = UploadType.ANDROID_APP; // Build a reusable HttpClient HttpClient http = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1) .connectTimeout(Duration.ofSeconds(10)) .build(); try (DeviceFarmClient client = DeviceFarmClient.builder() .region(Region.US_WEST_2) .build()) { // 1) Create the upload in Device Farm CreateUploadResponse create = client.createUpload(CreateUploadRequest.builder() .projectArn(projectArn) .name(fileName) .type(type) .contentType("application/octet-stream") .build()); Upload upload = create.upload(); String uploadArn = upload.arn(); String url = upload.url(); // This will show output such as the following: // { "upload": { "arn": "...", "name": "my_sample_app.apk", "type": "ANDROID_APP", "status": "INITIALIZED", "url": "https://..." } } // 2) PUT file to pre-signed URL using HttpClient HttpRequest put = HttpRequest.newBuilder(URI.create(url)) .timeout(Duration.ofMinutes(15)) .header("Content-Type", "application/octet-stream") .PUT(HttpRequest.BodyPublishers.ofFile(appPath)) .build(); HttpResponse<Void> resp = http.send(put, HttpResponse.BodyHandlers.discarding()); int code = resp.statusCode(); if (code / 100 != 2) { throw new IOException("Failed PUT to S3 pre-signed URL, HTTP " + code); } // 3) Wait for the app to be in "SUCCEEDED" status (or fail/timeout) Instant deadline = Instant.now().plusSeconds(30); // 30-second timeout while (true) { GetUploadResponse got = client.getUpload(GetUploadRequest.builder() .arn(uploadArn) .build()); String status = got.upload().statusAsString(); String msg = got.upload().metadata(); System.out.println("status=" + status + (msg != null ? " - " + msg : "")); if ("SUCCEEDED".equals(status)) return uploadArn; if ("FAILED".equals(status)) throw new RuntimeException("Upload failed: " + msg); if (Instant.now().isAfter(deadline)) { throw new RuntimeException("Timeout waiting for processing, last status=" + status); } Thread.sleep(2000); } } } public static void main(String[] args) throws Exception { String projectArn = "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE"; Path appPath = Paths.get("/local/path/to/my_sample_app.apk"); String result = upload(projectArn, appPath); System.out.println("Upload ARN: " + result); } }
JavaScript

Nota: questo esempio utilizza AWS SDK for JavaScript (v3) e Node 18+ per inviare l'app fetch a Device Farm.

Innanzitutto, crea un progetto se non l'hai già fatto.

import { DeviceFarmClient, CreateProjectCommand } from "@aws-sdk/client-device-farm"; const df = new DeviceFarmClient({ region: "us-west-2" }); const resp = await df.send(new CreateProjectCommand({ name: "MyProjectName" })); console.log(resp); // Response will be something like: // { project: { name: 'MyProjectName', arn: 'arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-...', created: 1535675814.414 } }

Quindi, procedi come segue per creare il caricamento e inviarlo a Device Farm. In questo esempio, creeremo il caricamento di un'app Android utilizzando un file APK locale. Per ulteriori informazioni sui tipi di caricamento, inclusi i dettagli sui tipi di caricamento delle app iOS, consulta la nostra documentazione API per la creazione di un Upload.

import { DeviceFarmClient, CreateUploadCommand, GetUploadCommand } from "@aws-sdk/client-device-farm"; import { createReadStream } from "fs"; import { basename } from "path"; const projectArn = "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE"; const appPath = "/local/path/to/my_sample_app.apk"; const name = basename(appPath).trim(); const type = "ANDROID_APP"; const client = new DeviceFarmClient({ region: "us-west-2" }); // 1) Create the upload in Device Farm const create = await client.send(new CreateUploadCommand({ projectArn, name, type, contentType: "application/octet-stream", })); const uploadArn = create.upload.arn; const url = create.upload.url; // This will show output such as the following: // { upload: { arn: '...', name: 'my_sample_app.apk', type: 'ANDROID_APP', status: 'INITIALIZED', url: 'https://...' } } // 2) PUT to pre-signed URL const putResp = await fetch(url, { method: "PUT", headers: { "Content-Type": "application/octet-stream" }, body: createReadStream(appPath), }); if (!putResp.ok) { throw new Error(`Failed PUT to pre-signed URL: ${putResp.status} ${await putResp.text().catch(()=>"")}`); } // 3) Wait for the app to be in "SUCCEEDED" status (or fail/timeout) const deadline = Date.now() + (30 * 1000); // 30-second timeout while (true) { const response = await client.send(new GetUploadCommand({ arn: uploadArn })); const { status, message, metadata } = response.upload; console.log(`status=${status}${message ? " - " + message : metadata ? " - " + metadata : ""}`); if (status === "SUCCEEDED") { console.log("Upload complete:", uploadArn); break; } if (status === "FAILED") { throw new Error(`Upload failed: ${message || metadata || "unknown"}`); } if (Date.now() > deadline) throw new Error(`Timeout waiting for processing (last status=${status})`); await new Promise(r => setTimeout(r, 2000)); }
C#

Nota: questo esempio utilizza l' AWS SDK for .NET HttpClient e invia l'app a Device Farm.

Innanzitutto, crea un progetto se non l'hai già fatto.

using System; using Amazon; using Amazon.DeviceFarm; using Amazon.DeviceFarm.Model; using var client = new AmazonDeviceFarmClient(RegionEndpoint.USWest2); var resp = await client.CreateProjectAsync(new CreateProjectRequest { Name = "MyProjectName" }); Console.WriteLine(resp.Project); // Response will be something like: // { Name = MyProjectName, Arn = arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-..., Created = ... }

Quindi, procedi come segue per creare il caricamento e inviarlo a Device Farm. In questo esempio, creeremo il caricamento di un'app Android utilizzando un file APK locale. Per ulteriori informazioni sui tipi di caricamento, inclusi i dettagli sui tipi di caricamento delle app iOS, consulta la nostra documentazione API per la creazione di un Upload.

using System; using System.IO; using System.Net.Http; using System.Threading.Tasks; using System.Net.Http.Headers; using Amazon; using Amazon.DeviceFarm; using Amazon.DeviceFarm.Model; class DeviceFarmUploader { public static async Task<string> UploadAsync(string projectArn, string appPath) { if (string.IsNullOrWhiteSpace(projectArn)) throw new ArgumentException("Missing projectArn"); if (!File.Exists(appPath)) throw new ArgumentException($"Invalid app path: {appPath}"); var type = UploadType.ANDROID_APP; using var client = new AmazonDeviceFarmClient(RegionEndpoint.USWest2); // 1) Create the upload in Device Farm var create = await client.CreateUploadAsync(new CreateUploadRequest { ProjectArn = projectArn, Name = Path.GetFileName(appPath), Type = type, ContentType = "application/octet-stream" }); var uploadArn = create.Upload.Arn; var url = create.Upload.Url; // This will show output such as the following: // { Upload: { Arn = ..., Name = my_sample_app.apk, Type = ANDROID_APP, Status = INITIALIZED, Url = https://... } } // 2) PUT file to pre-signed URL using (var http = new HttpClient()) using (var fs = File.OpenRead(appPath)) using (var content = new StreamContent(fs)) { content.Headers.Add("Content-Type", "application/octet-stream"); var resp = await http.PutAsync(url, content); if (!resp.IsSuccessStatusCode) throw new Exception($"Failed PUT to pre-signed URL: {(int)resp.StatusCode} {await resp.Content.ReadAsStringAsync()}"); } // 3) Wait for the app to be in "SUCCEEDED" status (or fail/timeout) var deadline = DateTime.UtcNow.AddSeconds(30); // 30-second timeout while (true) { var got = await client.GetUploadAsync(new GetUploadRequest { Arn = uploadArn }); var status = got.Upload.Status.Value; var msg = got.Upload.Message ?? got.Upload.Metadata; Console.WriteLine($"status={status}{(string.IsNullOrEmpty(msg) ? "" : " - " + msg)}"); if (status == UploadStatus.SUCCEEDED.Value) return uploadArn; if (status == UploadStatus.FAILED.Value) throw new Exception($"Upload failed: {msg}"); if (DateTime.UtcNow > deadline) throw new TimeoutException($"Timeout waiting for processing (last status={status})"); await Task.Delay(2000); } } static async Task Main() { var projectArn = "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE"; var appPath = "/local/path/to/my_sample_app.apk"; var result = await UploadAsync(projectArn!, appPath!); Console.WriteLine("Upload ARN: " + result); } }
Ruby

Nota: questo esempio utilizza l' AWS SDK for Net::HTTP Ruby e per inviare l'app a Device Farm.

Innanzitutto, crea un progetto se non l'hai già fatto.

require "aws-sdk-devicefarm" client = Aws::DeviceFarm::Client.new(region: "us-west-2") resp = client.create_project(name: "MyProjectName") puts resp.project.inspect # Response will be something like: # #<struct Aws::DeviceFarm::Types::Project name="MyProjectName", arn="arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-...", created=1535675814.414>

Quindi, procedi come segue per creare il caricamento e inviarlo a Device Farm. In questo esempio, creeremo il caricamento di un'app Android utilizzando un file APK locale. Per ulteriori informazioni sui tipi di caricamento, inclusi i dettagli sui tipi di caricamento delle app iOS, consulta la nostra documentazione API per la creazione di un Upload.

require "aws-sdk-devicefarm" require "net/http" require "uri" project_arn = "arn:aws:devicefarm:us-west-2:123456789101:project:5e01a8c7-c861-4c0a-b1d5-12345EXAMPLE" app_path = "/local/path/to/my_sample_app.apk" raise "Invalid APP_PATH: #{app_path}" unless File.file?(app_path) type = "ANDROID_APP" client = Aws::DeviceFarm::Client.new(region: "us-west-2") # 1) Create the upload in Device Farm create = client.create_upload( project_arn: project_arn, name: File.basename(app_path), type: type, content_type: "application/octet-stream" ) upload_arn = create.upload.arn url = create.upload.url # This will show output such as the following: # #<Upload arn="...", name="my_sample_app.apk", type="ANDROID_APP", status="INITIALIZED", url="https://..."> # 2) PUT the file to the pre-signed URL uri = URI.parse(url) Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == "https")) do |http| req = Net::HTTP::Put.new(uri) req["Content-Type"] = "application/octet-stream" req.body_stream = File.open(app_path, "rb") req.content_length = File.size(app_path) resp = http.request(req) raise "Failed PUT: #{resp.code} #{resp.body}" unless resp.code.to_i / 100 == 2 end # 3) Wait for the app to be in "SUCCEEDED" status (or fail/timeout) deadline = Time.now + 30 # 30-second timeout loop do got = client.get_upload(arn: upload_arn) status = got.upload.status msg = got.upload.message || got.upload.metadata puts "status=#{status}#{msg ? " - #{msg}" : ""}" case status when "SUCCEEDED" then puts "Upload complete: #{upload_arn}"; break when "FAILED" then raise "Upload failed: #{msg}" end raise "Timeout waiting for processing (last status=#{status})" if Time.now > deadline sleep 2 end

Esempio: utilizzo dell' AWS SDK per avviare un'esecuzione di Device Farm e raccogliere artefatti

L'esempio seguente fornisce una beginning-to-end dimostrazione di come utilizzare l' AWS SDK per lavorare con Device Farm. Inoltre, vengono effettuate le seguenti operazioni:

  • Carica un test e pacchetti applicativi su Device Farm

  • Avvia un'esecuzione di test e attende il suo completamento (o errore)

  • Scarica tutti gli artefatti prodotti dalle suite di test

Questo esempio dipende dal pacchetto requests di terze parti per interagire con HTTP.

import boto3 import os import requests import string import random import time import datetime import time import json # The following script runs a test through Device Farm # # Things you have to change: config = { # This is our app under test. "appFilePath":"app-debug.apk", "projectArn": "arn:aws:devicefarm:us-west-2:111122223333:project:1b99bcff-1111-2222-ab2f-8c3c733c55ed", # Since we care about the most popular devices, we'll use a curated pool. "testSpecArn":"arn:aws:devicefarm:us-west-2::upload:101e31e8-12ac-11e9-ab14-d663bd873e83", "poolArn":"arn:aws:devicefarm:us-west-2::devicepool:082d10e5-d7d7-48a5-ba5c-b33d66efa1f5", "namePrefix":"MyAppTest", # This is our test package. This tutorial won't go into how to make these. "testPackage":"tests.zip" } client = boto3.client('devicefarm') unique = config['namePrefix']+"-"+(datetime.date.today().isoformat())+(''.join(random.sample(string.ascii_letters,8))) print(f"The unique identifier for this run is going to be {unique} -- all uploads will be prefixed with this.") def upload_df_file(filename, type_, mime='application/octet-stream'): response = client.create_upload(projectArn=config['projectArn'], name = (unique)+"_"+os.path.basename(filename), type=type_, contentType=mime ) # 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(filename, 'rb') as file_stream: print(f"Uploading {filename} to Device Farm as {response['upload']['name']}... ",end='') put_req = requests.put(upload_url, data=file_stream, headers={"content-type":mime}) print(' done') 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() while True: print(f"Upload of {filename} in state {response['upload']['status']} after "+str(datetime.datetime.now() - started)) if response['upload']['status'] == 'FAILED': raise Exception("The upload failed processing. DeviceFarm says reason is: \n"+(response['upload']['message'] if 'message' in response['upload'] else response['upload']['metadata'])) if response['upload']['status'] == 'SUCCEEDED': break time.sleep(5) response = client.get_upload(arn=upload_arn) print("") return upload_arn our_upload_arn = upload_df_file(config['appFilePath'], "ANDROID_APP") our_test_package_arn = upload_df_file(config['testPackage'], 'APPIUM_PYTHON_TEST_PACKAGE') print(our_upload_arn, our_test_package_arn) # Now that we have those out of the way, we can start the test run... response = client.schedule_run( projectArn = config["projectArn"], appArn = our_upload_arn, devicePoolArn = config["poolArn"], name=unique, test = { "type":"APPIUM_PYTHON", "testSpecArn": config["testSpecArn"], "testPackageArn": our_test_package_arn } ) run_arn = response['run']['arn'] start_time = datetime.datetime.now() print(f"Run {unique} is scheduled as arn {run_arn} ") try: while True: response = client.get_run(arn=run_arn) state = response['run']['status'] if state == 'COMPLETED' or state == 'ERRORED': break else: print(f" Run {unique} in state {state}, total time "+str(datetime.datetime.now()-start_time)) time.sleep(10) except: # If something goes wrong in this process, we stop the run and exit. client.stop_run(arn=run_arn) exit(1) print(f"Tests finished in state {state} after "+str(datetime.datetime.now() - start_time)) # now, we pull all the logs. jobs_response = client.list_jobs(arn=run_arn) # Save the output somewhere. We're using the unique value, but you could use something else save_path = os.path.join(os.getcwd(), unique) os.mkdir(save_path) # Save the last run information for job in jobs_response['jobs'] : # Make a directory for our information job_name = job['name'] os.makedirs(os.path.join(save_path, job_name), exist_ok=True) # Get each suite within the job suites = client.list_suites(arn=job['arn'])['suites'] for suite in suites: for test in client.list_tests(arn=suite['arn'])['tests']: # Get the artifacts for artifact_type in ['FILE','SCREENSHOT','LOG']: artifacts = client.list_artifacts( type=artifact_type, arn = test['arn'] )['artifacts'] for artifact in artifacts: # We replace : because it has a special meaning in Windows & macos path_to = os.path.join(save_path, job_name, suite['name'], test['name'].replace(':','_') ) os.makedirs(path_to, exist_ok=True) filename = artifact['type']+"_"+artifact['name']+"."+artifact['extension'] artifact_save_path = os.path.join(path_to, filename) print("Downloading "+artifact_save_path) with open(artifact_save_path, 'wb') as fn, requests.get(artifact['url'],allow_redirects=True) as request: fn.write(request.content) #/for artifact in artifacts #/for artifact type in [] #/ for test in ()[] #/ for suite in suites #/ for job in _[] # done print("Finished")