This repository provides actions to interact with AWS devicefarms, implemented using the AWS JavaScript SDK. AWS credentials need to be configured using the configure AWS credentials action.
Due to the nature of the application this was developed for the following restrictions apply for now:
- The application contains the test definitions in the application binary. As AWS always expects a separate test definition a dummy test definition is provided in
sample-venv/tests
. Applications wanting to use the AWS testdefinitions should still work without problem, as long as the correct files are uploaded / correct ARNs specified. This has not been tested, though. - Test results are evaluated on Github side based on files pulled from the device. Support for tests/suites an AWS is not implemented. Adding support for those APIs should be trivial, if needed. Patches are welcome.
Sample test data and applications simulating this case are provided in a separate repository.
Two types of actions are provided: Simple API wrappers - useful for debugging, testing or building workflows otherwise not properly supported - and complex actions, wrapping several API calls. Typically complex actions should be used, whenever possible.
After adding secrets for AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEVICE_POOL_ARN and AWS_PROJECT_ARN (see AWS setup section below if no devicefarm is configured) the following workflow will create a test run with a mix of downloaded and local data, and wait for it to execute. You may want to adjust app_file
, test_spec_file
and test_package_file
before running it - as shown it will pull demo data for the run:
on: push: branches: [ master ] pull_request: branches: [ master ] name: Test application on device farm jobs: deploy: name: Deploy runs-on: ubuntu-latest environment: production steps: - name: Checkout uses: actions/checkout@v2 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: Schedule test run with mixed data uses: realm/aws-devicefarm/test-application@master with: name: schedule-run file_artifacts: | Test spec file.yml Customer Artifacts.zip project_arn: ${{ secrets.AWS_PROJECT_ARN }} device_pool_arn: ${{ secrets.AWS_DEVICE_POOL_ARN }} app_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/fi.aardsoft.devicefarmsample-debug.apk app_type: ANDROID_APP test_type: APPIUM_PYTHON test_package_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/sample_env_python3.zip test_package_type: APPIUM_PYTHON_TEST_PACKAGE test_spec_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/test_spec.yaml test_spec_type: APPIUM_PYTHON_TEST_SPEC remote_src: true
It is also possible to have the test specification inline:
on: push: branches: [ master ] pull_request: branches: [ master ] name: Test application on device farm jobs: deploy: name: Deploy runs-on: ubuntu-latest environment: production steps: - name: Checkout uses: actions/checkout@v2 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: Schedule test run with mixed data uses: realm/aws-devicefarm/test-application@master with: name: schedule-run-inline file_artifacts: | Test spec file.yml Customer Artifacts.zip project_arn: ${{ secrets.AWS_PROJECT_ARN }} device_pool_arn: ${{ secrets.AWS_DEVICE_POOL_ARN }} app_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/fi.aardsoft.devicefarmsample-debug.apk app_type: ANDROID_APP test_type: APPIUM_PYTHON test_package_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/sample_env_python3.zip test_package_type: APPIUM_PYTHON_TEST_PACKAGE test_spec_file: test_spec.yaml test_spec_type: APPIUM_PYTHON_TEST_SPEC test_spec: | version: 0.1 phases: install: commands: - export PYTHON_VERSION=3 pre_test: commands: - adb -s $DEVICEFARM_DEVICE_UDID shell pm grant fi.aardsoft.devicefarmsample android.permission.READ_EXTERNAL_STORAGE - adb -s $DEVICEFARM_DEVICE_UDID shell pm grant fi.aardsoft.devicefarmsample android.permission.WRITE_EXTERNAL_STORAGE test: commands: - adb -s $DEVICEFARM_DEVICE_UDID shell am instrument -w -r -e foo bar -e bar baz fi.aardsoft.devicefarmsample post_test: commands: - adb -s $DEVICEFARM_DEVICE_UDID pull /storage/emulated/0/Android/data/fi.aardsoft.devicefarmsample/files/output.txt - mv output.txt $DEVICEFARM_LOG_DIR/test-output.txt artifacts: - $DEVICEFARM_LOG_DIR remote_src: true
The following actions are just wrappers around the JavaScript SDK. In addition to the JSON returned by the API they also return the JSON fields most likely to be useful for later calls - saving some JSON parsing compared to building actions on top of the AWS CLI. For each action documentation links to both the API and the matching call in AWS CLI are provided - with the latter typically being the more useful when building a workflow on top of those actions without trying to touch the JavaScript.
Create an upload for a file named name
, of type type
, in the project specified by project_arn
. Note that a file needs to be uploaded to the URL from the result in a second step - for an action handling the upload as well check upload-file
.
- project_arn (string): the ARN of an existing device farm project.
- type (string): the type of the file to upload. See the CLI documentation for available values.
- name (string): name of the file to upload. This is not a local file, but a file name (without path) on AWS.
- cleanup (bool, optional, default: true): delete uploads in the cleanup handler. Set this to
false
to keep uploads.
- data (JSON): raw result returned by the API.
- arn (string): the ARN of the newly created upload.
- url (string): the pre-signed URL for PUTing the file contents to.
- status (string): the status of the upload. Starts with
INITIALIZED
, and should change toSUCCEEDED
after uploading the file. Check withget-upload
.
- name: Create upload
uses: realm/aws-devicefarm/create-upload@v1
id: create-upload
with:
project_arn: arn:aws:devicefarm:us-west-2:123456789101:project:EXAMPLE-GUID-123-456
name: test.yaml
type: APPIUM_PYTHON_TEST_SPEC
A step similar to the following could be used to upload the actual file:
- name: Upload file
run: |
curl -T /path/to/local/file '${{ steps.create-upload.outputs.url }}'
The status of the upload should be checked afterwards with get-upload
, possibly in a loop until the status changes.
Deletes a resource uploaded to a devicefarm project, specified by resource_arn
.
- resource_arn (string): the ARN of the resource to delete.
This method does not return data, and completes successfully even if the resource requested for deletion does not exist.
- name: Delete upload
uses: realm/aws-devicefarm/delete-upload@v1
id: delete-upload
with:
resource_arn: arn:aws:devicefarm:us-west-2:123456789101:project:EXAMPLE-GUID-123-456
Get information about a specific device pool.
- device_pool_arn (string): the ARN of the device pool.
- data (JSON): raw result returned by the API.
- name (string): the pool name.
- description (string): the pool description.
- type (string): the pool type,
CURATED
orPRIVATE
- name: Get device pool details
uses: realm/aws-devicefarm/get-device-pool@v1
with:
device_pool_arn: arn:aws:devicefarm:us-west-2:123456789101:devicepool:EXAMPLE-GUID-123-456
Return details of the given project.
- project_arn (string): the ARN of the device farm project.
- data (JSON): raw result returned by the API.
- name (string): the project name.
- created (date): date the project was create.
- name: Get project
uses: realm/aws-devicefarm/get-project@v1
id: get-project
with:
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
Return details for a specific test run.
- run_arn (string): the ARN of the run to request details for.
- data (JSON): raw result returned by the API.
- created (string): creation timestamp for the resource.
- message (string): additional message about run results.
- name (string): the name of the run.
- parsing_result_url (string): the URL containing parsing errors, if any.
- platform (string): hte platform the run was executed on.
- result (string): result of the test run.
- result_code (string): supporting field for
result
. - status (string): status of the test run.
- type (string): the type of this upload.
Typically the ARN is obtained from an earlier step:
- name: Get run details
uses: realm/aws-devicefarm/get-run@v1
with:
run_arn: ${{ steps.schedule-run.outputs.arn }}
Return details for the upload specified by resource_arn
.
- resource_arn (string): the ARN of the resource to request details for.
- data (JSON): raw result returned by the API.
- created (string): creation timestamp for the resource.
- metadata (string): additional metadata extracted from an uploaded file.
- type (string): the type of this upload.
- status (string): the status of this upload.
- name: Get upload details
uses: realm/aws-devicefarm/get-upload@v1
with:
resource_arn: arn:aws:devicefarm:us-west-2:123456789101:upload:EXAMPLE-GUID-123-456
List artifacts for a resource. Note that you can only list one artifact type at one time, and can’t query specific artifact names. To retrieve a specific artifact loop over the returned array, check for artifact names, and GET the included URL to retrieve the artifact.
- resource_arn (string): the ARN of the resource to list artifacts for.
- type (string): the type of artifacts to list. Valid options are
FILE
,LOG
andSCREENSHOT
.
- data (JSON): raw result returned by the API.
- name: List file artifacts for run uses: realm/aws-devicefarm/list-artifacts@v1 with: resource_arn: ${{ steps.schedule-run.outputs.arn }} type: FILE
Return a list of device pools configured for the specified project.
- project_arn (string): the ARN of the device farm project.
- type (string, optional): the type of the pool to list. Valid options are
PRIVATE
orCURATED
, defaulting toPRIVATE
.
- data (JSON): raw result returned by the API.
- name: List device pools
uses: realm/aws-devicefarm/list-device-pools@v1
id: list-device-pools
with:
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
List test runs in the specified device farm project.
- project_arn (string): the ARN of the device farm project.
- data (JSON): raw result returned by the API.
- name: List runs
uses: realm/aws-devicefarm/list-runs@v1
with:
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
Return all uploads in the project specified by project_arn
as a JSON string.
- project_arn (string): the ARN of the device farm project.
- data (JSON): raw result returned by the API.
- name: List uploads
uses: realm/aws-devicefarm/list-uploads@v1
id: list-uploads
with:
project_arn: arn:aws:devicefarm:us-west-2:123456789101:project:EXAMPLE-GUID-123-456
The output can be referenced in following actions using the step ID:
with:
input: ${{ steps.list-uploads.outputs.data }}
Schedule a test run with resources uploaded to AWS already. This action returns directly after scheduling a run - this behaviour is useful to avoid blocking a workflow if other steps can still be executed, but requires later checking with get-run
if the run has finished. For an action capable of uploading required files as well as blocking until a test run has finished see test-application
.
When called without a test specification the run will be triggered with the default test environment of the specified test type.
- name (string, optional): a name used for the test run.
- project_arn (string): the ARN of the device farm project.
- device_pool_arn (string): the ARN of the device pool.
- app_arn (string): the ARN of the uploaded app.
- test_type (string): the type of the test to execute.
- test_package_arn (string): the ARN of the uploaded test package.
- test_spec_arn (string): the ARN of the uploaded test specification.
- data (JSON): raw result returned by the API.
- arn (string): the ARN of the scheduled test run.
- parsing_result_url (string): the URL containing parsing errors, if any. Note that this call may return before the API reports parse errors.
- status (string): status of the test run. Typically it can be expected to get
SCHEDULING
here. - result_code (string): result of the test run. For this call this will typically be empty.
This example references ARNs obtained from previous upload steps:
- name: Schedule a test run
uses: realm/aws-devicefarm/schedule-run@v1
with:
name: schedule_run
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
device_pool_arn: ${{ secrets.AWS_DEVICE_POOL_ARN }}
app_arn: ${{ steps.test-app.outputs.arn }}
test_type: APPIUM_PYTHON
test_package_arn: ${{ steps.test-bundle.outputs.arn }}
test_spec_arn: ${{ steps.test-spec.outputs.arn }}
This action downloads one or more artifacts from a test run. Trying to download a non-existent artifact will log a warning and omit the file frem the output, but not abort.
- run_arn (string): the ARN of the test run
- file_artifacts (multiline string, optional): file names - including extension - of type
FILE
to pull. - log_artifacts (multiline string, optional): file names - including extension - of type
LOG
to pull. - screenshot_artifacts (multiline string, optional): file names - including extension - of type
SCREENSHOT
to pull.
- data (JSON): an array containing the downloaded files for each of the three available categories.
This assumes the run with id schedule-run
created customer artifacts:
- name: Download artifacts
uses: realm/aws-devicefarm/download-artifacts@v1
with:
run_arn: ${{ steps.schedule-run.outputs.arn }}
file_artifacts: |
Test spec file.yml
Invalid Artifact Logging Warning.txt
Customer Artifacts.zip
The returned JSON looks like this - note the missing invalid file:
{
"FILE": [
"Test spec file.yml",
"Customer Artifacts.zip"
],
"SCREENSHOT": [
],
"LOG": [
]
}
This action creates a file upload and then uploads a file.
- project_arn (string): the ARN of the device farm project.
- type (string): the type of the file to upload.
- name (string, optional): the name of the file to create on AWS. The name of the actual file if missing.
- file (string): the full path to the file to upload to AWS.
- cleanup (bool, optional, default: true): delete uploads in the cleanup handler. Set this to
false
to keep uploads. - remote_src (bool, optional, default: true): try to retrieve files via http if not available locally. A file is only downloaded if it doesn’t exist yet.
- data (JSON): raw result returned by the API.
- arn (string): the ARN of the newly created upload.
- url (string): the pre-signed URL for PUTing the file contents to.
- status (string): the status of the upload. Should be
SUCCEEDED
after passing validation for the specific file type at AWS.
- name: Upload remote test bundle
uses: realm/aws-devicefarm/upload-file@v1
id: test-bundle
with:
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/test_spec.yaml
remote_src: true
type: APPIUM_PYTHON_TEST_PACKAGE
This action schedules a test run and waits for the result. It can either use already uploaded files, or upload local or remote files.
When called without a test specification the run will be triggered with the default test environment of the specified test type.
- name (string, optional): a name used for the test run.
- project_arn (string): the ARN of the device farm project.
- device_pool_arn (string): the ARN of the device pool.
- app_arn (string): the ARN of the uploaded app.
- app_file (string): the path to an app file. Use either
app_arn
orapp_file
. - app_type (string): type of the application file. For Android apps use
ANDROID_APP
. - test_type (string): the type of the test to execute.
- test_package_arn (string): the ARN of the uploaded test package.
- test_package_file (string): the path to a test package archive. Use either
test_package_arn
ortest_package_file
. - test_package_type (string): the type of the test package. For appium/python use
APPIUM_PYTHON_TEST_PACKAGE
- test_spec (multiline string): inline YAML for the test specification. See the example at the top.
- test_spec_arn (string): the ARN of the uploaded test specification.
- test_spec_file (string): the path to a test spec file. Use either
test_spec_arn
ortest_spec_file
- test_spec_type (string): the type of the test specification. For appium/python use
APPIUM_PYTHON_TEST_SPEC
- file_artifacts (multiline string, optional): file names - including extension - of type
FILE
to pull. - log_artifacts (multiline string, optional): file names - including extension - of type
LOG
to pull. - screenshot_artifacts (multiline string, optional): file names - including extension - of type
SCREENSHOT
to pull. - cleanup (bool, optional, default: true): delete uploads in the cleanup handler. Set this to
false
to keep uploads. - timeout (int, optional, default: 1800): maximum duration of a run on the device farm in seconds before it is considered failed.
- data (JSON): raw result returned by the API. The additional field
downloaded_artifacts
contains successfully pulled artifacts. - arn (string): the ARN of the scheduled test run.
- parsingResultUrl (string): the URL containing parsing errors, if any. Note that this call may return before the API reports parse errors.
- status (string): status of the test run. Typically it can be expected to get
SCHEDULING
here. - resultCode (string): result of the test run. For this call this will typically be empty.
This example pulls remote sources, and uploads them to a device farm before scheduling a run:
- name: Schedule test run
uses: realm/aws-devicefarm/test-application@v1
with:
name: run_with_uploads
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
device_pool_arn: ${{ secrets.AWS_DEVICE_POOL_ARN }}
app_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/fi.aardsoft.devicefarmsample-debug.apk
app_type: ANDROID_APP
test_type: APPIUM_PYTHON
test_package_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/sample_env_python3.zip
test_package_type: APPIUM_PYTHON_TEST_PACKAGE
test_spec_file: https://github.com/realm/aws-devicefarm-sample-data/releases/download/0.3/test_spec.yaml
test_spec_type: APPIUM_PYTHON_TEST_SPEC
remote_src: true
In the Device Farm console create a new project, and copy the displayed ARN - this is the project ARN required by some actions. Next go to Project settings
, Device pools
and create a new pool. Retrieve the pool ARN using the list-device-pools CLI command, or using the list-device-pools action if AWS CLI is not set up.
Secrets named AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEVICE_POOL_ARN and AWS_PROJECT_ARN or similar need to be set using the ARNs just created and account secrets.
It is recommended to use a dedicated role user for devicefarm access. the AWS role to limit access to devicefarm only is AWSDeviceFarmFullAccess
.
A pull request should also include build results, built with the same node version as used in CI (at the time of writing this: 16):
$ npm ci
[...]
$ npm run package
> aws-devicefarm@1.0.0 package
> node tools/build.js
Building create-upload
[...]
nvm is an easy way to add additional node versions to the local machine. After following the instructions there:
$ nvm install 16
Downloading and installing node v16.20.2...
Downloading https://nodejs.org/dist/v16.20.2/node-v16.20.2-linux-x64.tar.xz...
--2023-10-02 12:00:42-- https://nodejs.org/dist/v16.20.2/node-v16.20.2-linux-x64.tar.xz
Resolving nodejs.org (nodejs.org)... 104.20.22.46, 104.20.23.46, 2606:4700:10::6814:162e, ...
Connecting to nodejs.org (nodejs.org)|104.20.22.46|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 22556484 (22M) [application/x-xz]
Saving to: ‘/home/user/.nvm/.cache/bin/node-v16.20.2-linux-x64/node-v16.20.2-linux-x64.tar.xz’
/home/user/.nvm/.cache 100%[======================================>] 21.51M 2.70MB/s in 8.0s
2023-10-02 12:00:50 (2.71 MB/s) - ‘/home/user/.nvm/.cache/bin/node-v16.20.2-linux-x64/node-v16.20.2-linux-x64.tar.xz’ saved [22556484/22556484]
Computing checksum with sha256sum
Checksums matched!
Now using node v16.20.2 (npm v8.19.4)
Local testing is possible to some extend using act. All secrets should be exported as environment variable, otherwise act will prompt for it:
$ act -s AWS_ACCESS_KEY_ID -s AWS_SECRET_ACCESS_KEY -s AWS_DEVICE_POOL_ARN -s AWS_PROJECT_ARN