Tag: Android


Encrypting an Amazon S3 object on the client side with AWS KMS and the AWS Mobile SDK for Android

by Karthik Saligrama | on | in AWS Mobile, S3 | | Comments

Starting with the AWS Mobile SDK for Android version 2.4.0, you have two options to encrypt client-side objects before sending them to Amazon S3: an AWS Key Management Service (AWS KMS) customer master key (CMK) or a client-side master key.

 

Customer master key

 

When using an AWS KMS customer master key (CMK) for client-side data encryption, you provide only a CMK ID. The AWS Mobile SDK for Android sends a request to AWS KMS for a key to encrypt your data. There is no requirement to provide encryption keys to the Amazon S3 encryption client.

While uploading, the data in the object is encrypted and the cipher blob version of the encryption key that is returned from KMS is stored in the object metadata.

When the client calls Amazon S3 to download the object and its metadata, the client uses the cipher blob key to get the plaintext key to decrypt the entire S3 object.

The following example shows how to set up Amazon S3 client-side encryption with a CMK on an Android device using the AWS Mobile SDK for Android.

 

Initialize KMSEncryptionMaterialsProvider

 

final KMSEncryptionMaterialsProvider materialProvider = new KMSEncryptionMaterialsProvider(<kmsKey>); 
final CryptoConfiguration cryptoConfiguration = new CryptoConfiguration()
                                                      .withAwsKmsRegion(Region
                                                                   .getRegion(Regions.US_EAST_1));
final AmazonS3 s3Client = new AmazonS3EncryptionClient(<credentialProvider>, 
                                            materialProvider, 
                                            cryptoConfiguration);
s3Client.setRegion(Region.getRegion(Regions.US_EAST_1));

Uploading

To upload an object to Amazon S3, use the AmazonS3EncryptionClient you initialized, and then use either PutObjectRequest or TransferUtility.

Using PutObjectRequest
final PutObjectRequest putObjectRequest = new PutObjectRequest(<bucketName>, <key>, <file>);
final PutObjectResult putObjectResult = s3Client.PutObject(putObjectRequest);
Using TransferUtility
final TransferUtility transferUtility = new TransferUtility(s3Client, <context>); 
final TransferObserver transferObserver =  transferUtility
                                                  .upload(<bucketName>, <key>, <file>);

Downloading

To download an object from Amazon S3, use the AmazonS3EncryptionClient you initialized earlier, and then use either GetObjectRequest or TransferUtility.

Using GetObjectRequest
final InputStream inputStream = s3Client.getObject(<bucketName>, <key>).getObjectContent();
Using TransferUtility:
final File tempDownloadFile = temp.newFile();
final TransferObserver observer = transferUtility
                                       .download(<bucketName>, <key>, <tempDownloadFile>);

Client-side master Key

Your client-side master keys and your unencrypted data are never sent to AWS. It is important that you safely manage your encryption keys. If you lose them, you won’t be able to decrypt your data.

If you want to use your own custom master key, use the following code to create a material provider.

final EncryptionMaterials encryptionMaterials = new EncryptionMaterials(<keypair>);
final AmazonS3 s3Client = new AmazonS3EncryptionClient(<credentialProvider>, encryptionMaterials);

As always you can post your questions and feedback to our GitHub repo or to our AWS Forums.

 

Announcing the AWS SDK for React Native

by Rohan Deshpande | on | | Comments
We’re excited to announce the immediate availability of the developer preview of the AWS SDK for React Native. The source code is available on GitHub under the Apache 2.0 license.
 
The SDK includes support for the following services:
  • Amazon S3 to store user data, including photos and videos, in the cloud. It uses the TransferUtility, which simplifies file transfers between your app and the cloud.
  • Amazon DynamoDB to store data into a NoSQL database.
  • AWS Lambda to run serverless code in the cloud without the need for backend infrastructure.
  • Amazon SNS to send and receive push notifications.
The SDK core uses Amazon Cognito Identity as the authentication provider to comply with best practices for mobile app development.
 

Getting Started with the SDK

To include the SDK in your React Native application:
  1. Download the packages from Github.
  2. Add the services that you need into your package.json.
  3. Run npm install.
Here is a sample package.json that uses AWS Lambda. 
 
% cat package.json
{
  "name": "sample",
  "version": "0.0.1",
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "aws-sdk-react-native-core": "../aws-sdk-react-native-core-0.0.1.tgz",
    "aws-sdk-react-native-lambda": "../aws-sdk-react-native-lambda-0.0.1.tgz",
    "react": "15.3.1",
    "react-native": "0.32.0"
  }
}
 	
See the GitHub repository for sample apps that demonstrate how to use the Cognito functionality to authenticate and the TransferUtility to transmit files to S3.
 

Contributing to the SDK

We welcome issue reports and contributions to the AWS SDK for React Native. Please report issues using the Github issue tracker. To contribute,  submit a pull request to the GitHub repository with a description of your issue or suggested change. If this is a bug fix, please reference the issue and include steps to reproduce it.

 

Get started with the AWS Device Farm CLI and Calabash Part 2: Retrieving Reports and Artifacts

by Epshteyn, Ilya | on | | Comments

In Part 1 of the walkthrough, we went through the process of creating an AWS Device Farm run for Calabash-Android test scripts.  In the second and final part of the series, we will go through the CLI commands for obtaining the status of the run and to retrieve all of the artifacts associated with a run including log files and screenshots.

Device Farm Run Components

Before we begin, let’s review the hierarchical structure of a Device Farm run:

  • RUN – A run in Device Farm represents a specific build of your app, with a specific set of tests, to be run on a specific set of devices. A run produces a report that contains information about the test execution. A run contains one or more jobs.
  • JOB – A job is a request to test a single app against a single device. A job contains one or more suites.
  • SUITE – A suite is a hierarchical organization of tests in a test package. A suite contains one or more tests.
  • TEST – A test is an individual test within a suite. This is the most granular entity in Device Farm’s data hierarchy.

 

Retrieving Reports and Artifacts

Using Device Farm CLI, we can obtain the status and result counters for each level of the run hierarchy including run, job, suite, and test. As you’ll see, the data available for each level of the hierarchy is very similar, with the scope of the data becoming more granular as you navigate deeper in the hierarchy.

Step 1: Retrieve the Status and Result Counters for a Device Farm Run

Use the get-run CLI command to retrieve the status and result counters of the run. 

[ec2-user]$  aws devicefarm get-run –arn arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917

Output:

{
    "run": {
        "status": "COMPLETED",
        "name": "firstCLIRun",
        "created": 1443331615.166,
        "totalJobs": 101,
        "completedJobs": 101,
        "platform": "ANDROID_APP",
        "result": "ERRORED",
        "billingMethod": "METERED",
        "type": "CALABASH",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917",
        "counters": {
            "skipped": 37,
            "warned": 16,
            "failed": 46,
            "stopped": 0,
            "passed": 514,
            "errored": 66,
            "total": 679
        }
    }
}

The above Run has a total of 101 jobs corresponding to 101 unique devices, all of which have completed.  This Run also has 679 individual tests with 46 failures and 66 errors.


Step 2: Retrieve the Status and Counters for all Jobs within a Run:

Use the list-jobs CLI command to list all jobs within a run along with job-level status and result counters.

[ec2-user]$  aws devicefarm list-jobs –arn arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917

Output (partial):

{
    "jobs": [
        {
            "status": "COMPLETED",
            "name": "ASUS Nexus 7 – 2nd Gen (WiFi)",
            "created": 1443331616.586,
            "result": "PASSED",
            "device": {
                "formFactor": "TABLET",
                "name": "ASUS Nexus 7 – 2nd Gen (WiFi)",
                "resolution": {
                    "width": 1200,
                    "height": 1920
                },
                "image": "NA",
                "platform": "ANDROID",
                "heapSize": 0,
                "memory": 34359738368,
                "model": "Nexus 7 – 2nd Gen",
                "os": "4.3.1",
                "cpu": {
                    "frequency": "MHz",
                    "architecture": "ARMv7",
                    "clock": 1512.0
                },
                "arn": "arn:aws:devicefarm:us-west-2::device:208FE7EE973042EA97DEC2EEF31CD10A",
                "manufacturer": "ASUS"
            },
            "message": "Successful test lifecycle of Setup Test",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:job:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066",
            "counters": {
                "skipped": 0,
                "warned": 0,
                "failed": 0,
                "stopped": 0,
                "passed": 7,
                "errored": 0,
                "total": 7
            }
        },
        {
            "status": "COMPLETED",
            "name": "Amazon Kindle Fire HDX 7 (WiFi)",
            "created": 1443331615.56,
            "result": "FAILED",
            "device": {
                "formFactor": "TABLET",
                "name": "Amazon Kindle Fire HDX 7 (WiFi)",
                "resolution": {
                    "width": 1920,
                    "height": 1200
                },
                "image": "NA",
                "platform": "ANDROID",
                "heapSize": 0,
                "memory": 17179869184,
                "model": "Kindle Fire HDX 7",
                "os": "4.4.3",
                "cpu": {
                    "frequency": "MHz",
                    "architecture": "ARMv7",
                    "clock": 2150.0
                },
                "arn": "arn:aws:devicefarm:us-west-2::device:BC44B6802F134918BDAB6FB4F38C37CC",
                "manufacturer": "Amazon"
            },
        "message": "I see the text "In Theaters" failed: Timeout waiting for elements: * {text CONTAINS[c] ‘In Theaters’} (Calabash::Android::WaitHelpers::WaitError)",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:job:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00018",
            "counters": {
                "skipped": 0,
                "warned": 0,
                "failed": 5,
                "stopped": 0,
                "passed": 2,
                "errored": 0,
                "total": 7
            }
        }

Note the hierarchical nature of the ARN.  The ARN type is “job” and the job ID is appended to the Run ARN: arn:aws:devicefarm:us-west-2:705582597265:job:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066


Step 3: Retrieve the Status and Result Counters for all Suites within a Job:

Use the list-suites CLI command to list all Suites within a job along with suite-level status and result counters.

[ec2-user]$  aws devicefarm list-suites –arn arn:aws:devicefarm:us-west-2:705582597265:job:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066

Output (partial)

    "suites": [
        {
            "status": "COMPLETED",
            "name": "Setup Suite",
            "created": 1443331656.183,
            "result": "PASSED",
            "message": "Successful test lifecycle of Setup Test",
            "arn": "arn:aws:devicefarm:us-west-2:705582597265:suite:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00000",
            "counters": {
                "skipped": 0,
                "warned": 0,
                "failed": 0,
                "stopped": 0,
                "passed": 1,
                "errored": 0,
                "total": 1
            }
        },
        {
            "status": "COMPLETED",
            "name": "STARmeter",
            "created": 1443331656.221,
            "result": "PASSED",
            "message": "Given I see the text "In Theaters" passed",
            "arn": "arn:aws:devicefarm:us-west-2:705582597265:suite:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00001",
            "counters": {
                "skipped": 0,
                "warned": 0,
                "failed": 0,
                "stopped": 0,
                "passed": 1,
                "errored": 0,
                "total": 1
            }
        }

The returned ARN type is “suite” and the suite ID is appended to the end: arn:aws:devicefarm:us-west-2:705582597265:suite:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00006
 

Step 4: Retrieving the Status and Result Counters for all Tests within a Suite

Use the list-tests CLI command to list all tests within a suite along with test-level status and result counters.

[ec2-user]$  aws devicefarm list-tests –arn arn:aws:devicefarm:us-west-2:705582597265:suite:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00006

Output:

{
    "tests": [
        {
            "status": "COMPLETED",
            "name": "Teardown Test",
            "created": 1443331656.424,
            "result": "PASSED",
            "message": "Successful test lifecycle of Teardown Test",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:test:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00006/00000",
            "counters": {
                "skipped": 0,
                "warned": 0,
                "failed": 0,
                "stopped": 0,
                "passed": 1,
                "errored": 0,
                "total": 1
            }
        }
    ]
}

The returned ARN type is “test” and the Test ID is appended to the end of the ARN": "arn:aws:devicefarm:us-west-2:705582597265:test:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00006/00000
 

Step 5: Retrieving the Artifacts for a Run, Job, Suite or Test

Using the list-artifacts CLI command, you can retrieve all of the artifacts associated with any of the levels of the run by specifying the corresponding ARN.  For example:

  • List artifacts for the run by specifying the run ARN:
    [ec2-user]$  aws devicefarm list-artifacts –arn arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917 –type FILE
  • List artifacts for the job by specifying the job ARN:
    [ec2-user]$  aws devicefarm list-artifacts –arn arn:aws:devicefarm:us-west-2:705582597265:job:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066 –type FILE
  • List artifacts for the suite by specifying the suite ARN:
    [ec2-user]$  aws devicefarm list-artifacts –arn arn:aws:devicefarm:us-west-2:705582597265:suite:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00000 –type FILE
  • List artifacts for the individual test by specifying the test ARN:
    [ec2-user]$  aws devicefarm list-artifacts –arn arn:aws:devicefarm:us-west-2:705582597265:test:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00006/00000 –type FILE

Note that there are three types of artifacts available: FILE, LOG and SCREENSHOT.

The output of the list-artifacts CLI command will include a pre-signed S3 URL that you can use to securely download the artifact:

{
    "artifacts": [
        {
            "url": "https://prod-us-west-2-results.s3-us-west-2.amazonaws.com/705582597265/2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00000/00000/3d811922-64d2-4d0c-8195-ffb715300836.logcat?AWSAccessKeyId=AKIAI3BDGZ5S7TQL2OZA&Expires=1446165402&Signature=D02sc66m01XXYtSJV0hVGK4l9aA%3D",
            "extension": "logcat",
            "name": "Logcat",
            "arn": "arn:aws:devicefarm:us-west-2:705582597265:artifact:2c21a412-bb7b-4657-a28c-d7d78b3888f7/16b3ce7d-63de-4371-bbc7-fdcb20b3f917/00066/00000/00000/00000"
        }
    ]
}

 

Conclusion

In this two-part series we have demonstrated the use of the AWS CLI to submit a Calabash-Android test script to Device Farm for testing against real mobile devices.  We have also demonstrated the use of the CLI to retrieve the status of the test Run as well as to retrieve the reports and artifacts for your test Run. If you have questions, please let us know in the comments section or in our developer forum.

Get started with the AWS Device Farm CLI and Calabash Part 1: Creating a Device Farm Run for Android Calabash Test Scripts

by Epshteyn, Ilya | on | | Comments

AWS Device Farm is an app testing service that enables you to test your native, hybrid, and web apps on real Android and iOS devices that are hosted in the AWS Cloud. A test report containing high-level results, low-level logs, pixel-to-pixel screenshots, and performance data is updated as tests are completed.

Device Farm allows you to upload your own tests or use built-in, script-free compatibility tests. Because testing is automatically performed in parallel, test results are available in minutes. Device Farm supports native and hybrid Android, iOS, and Fire OS apps, including those created with PhoneGap, Titanium, Xamarin, Unity, and other frameworks. It also supports testing web apps in Chrome on Android and Safari on iOS. You can run Built-in-Fuzz tests and Explorer tests or utilize your favorite testing framework including Appium, Calabash, Espresso, and UI Automation. 

The purpose of this walkthrough is to show you how you can quickly submit Calabash test scripts to AWS Device Farm leverageing the AWS Command Line Interface (CLI) for Device Farm. Although the walkthrough uses an Android application and Calabash, you can follow the same steps to test iOS and web apps, as well as use one of the many supported frameworks.

Key Concepts

Before we get started, let’s review a few key AWS Device Farm concepts:

  • PROJECT – A project in Device Farm enables you to organize your tests in whatever way you choose. For example, there can be one project per app title, or there can be one project per platform. You can create as many projects as you need.
  • RUN – A run in Device Farm represents a specific build of your app, with a specific set of tests, to be run on a specific set of devices.
  • DEVICE POOL – A device pool is a pre-configured set of devices that can be used as part of a run. 

Scheduling a Device Farm Run Using the CLI

Prerequisite: Before you can create a run in Device Farm, you must install the AWS Command Line Interface (CLI).

Once you install the CLI, there are five steps to create a Calabash test run in AWS Device Farm:

  1. Create a Device Farm project
  2. Upload your application (Android APK file)
  3. Upload your Calabash test scripts
  4. Create a device pool
  5. Schedule a run

Step 1: Create a Device Farm Project

The first step is to create a Device Farm project. You can also use an existing project if you’ve already created one.

[ec2-user]$  aws devicefarm create-project –name adndroidTest

Output:

[ec2-user@ip-10-0-19-179 ~]$ aws devicefarm create-project –name calabashCLI
{
    "project": {
        "name": "calabashCLI",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:project:2c21a412-bb7b-4657-a28c-d7d78b3888f7",
        "created": 1442719623.245
    }
}

Note the project ARN as you will reference it when creating your run in the upcoming steps.

Step 2: Create an Upload for Your Android APK File

AWS Device Farm leverages Amazon’s secure and durable S3 service for uploading all objects required for the run.  The upload process utilizes S3 pre-signed URLs to assure a secure upload.

The first step in the upload process is to create your upload request and obtain the S3 pre-signed upload URL:

[ec2-user]$  aws devicefarm create-upload –project-arn arn:aws:devicefarm:us-west-2:705582597265:project:2c21a412-bb7b-4657-a28c-d7d78b3888f7 –name IMDb_5.4.1.105410410_105410410.apk –type ANDROID_APP

The –project-arn is the ARN of your project that you created in Step1: Create a Device Farm Project.

Output:

{
    "upload": {
        "status": "INITIALIZED",
        "name": "IMDb_5.4.1.105410410_105410410.apk",
        "created": 1442719884.445,
        "url": "https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aproject%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aupload%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/d1f8bebc-a7f5-49a3-881f-f1ffdae90303/IMDb_5.4.1.105410410_105410410.apk?AWSAccessKeyId=AKIAI3BDGZ5S7TQL2OZA&Expires=1442806284&Signature=HZYPvpPBQn%2FTo%2BWmdSx1LW1nOwE%3D",
        "type": "ANDROID_APP",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/d1f8bebc-a7f5-49a3-881f-f1ffdae90303"
    }
}

The pre-signed URL is returned as the url output parameter.

The second step is to upload the actual APK file using the S3 pre-signed URL:

[ec2-user]$  curl -T IMDb_5.4.1.105410410_105410410.apk "https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aproject%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aupload%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/d1f8bebc-a7f5-49a3-881f-f1ffdae90303/IMDb_5.4.1.105410410_105410410.apk?AWSAccessKeyId=AKIAI3BDGZ5S7TQL2OZA&Expires=1442806284&Signature=HZYPvpPBQn%2FTo%2BWmdSx1LW1nOwE%3D"

You can check the status of your APK upload using the get-upload CLI command. Specify the ARN returned in the create-upload request above.

[ec2-user]$  aws devicefarm get-upload –arn arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/d1f8bebc-a7f5-49a3-881f-f1ffdae90303

Output:

{
    "upload": {
        "status": "SUCCEEDED",
        "name": "IMDb_5.4.1.105410410_105410410.apk",
        "created": 1442719884.445,
        "type": "ANDROID_APP",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/d1f8bebc-a7f5-49a3-881f-f1ffdae90303",
        "metadata": "{"screens": ["small", "normal", "large", "xlarge"], "sdk_version": "14", "package_name": "com.imdb.mobile", "native_code": [], "target_sdk_version": "18", "version_name": "5.4.1.105410410", "version_code": "105410410", "activity_name": "com.imdb.mobile.HomeActivity"}"
    }
}

Once the status is "SUCCEEDED" you are ready to continue to Step 3.

Step 3: Create an Upload for Your Calabash Test Package

In this step, you will upload the Calabash test scripts package. Please refer to the documentation on how to prepare your Android Calabash test package for upload to Device Farm.

The upload process for Calabash test scripts is similar to the upload of the Android APK file in Step 2.

First create an upload request and obtain the S3 pre-signed upload URL:

[ec2-user]$  aws devicefarm create-upload –project-arn arn:aws:devicefarm:us-west-2:705582597265:project:2c21a412-bb7b-4657-a28c-d7d78b3888f7 –name features.zip –type CALABASH_TEST_PACKAGE

Output:

{
    "upload": {
        "status": "INITIALIZED",
        "name": "features.zip",
        "created": 1442724498.222,
        "url": "https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aproject%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aupload%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/ccfa27c9-3f66-49ac-abe0-542214cd650c/features.zip?AWSAccessKeyId=AKIAI3BDGZ5S7TQL2OZA&Expires=1442810898&Signature=MOGwu7vUP3q%2B8OrrlSmJ5nVsQe0%3D",
        "type": "CALABASH_TEST_PACKAGE",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/ccfa27c9-3f66-49ac-abe0-542214cd650c"
    }
}

Next, upload the Calabash text package ZIP file to the S3 pre-signed URL:

[ec2-user]$  curl -T features.zip "https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aproject%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A705582597265%3Aupload%3A2c21a412-bb7b-4657-a28c-d7d78b3888f7/ccfa27c9-3f66-49ac-abe0-542214cd650c/features.zip?AWSAccessKeyId=AKIAI3BDGZ5S7TQL2OZA&Expires=1442810898&Signature=MOGwu7vUP3q%2B8OrrlSmJ5nVsQe0%3D"

You can check the status of your Calabash test package upload using the get-upload CLI command. Specify the upload ARN returned in the create-upload request above.

[ec2-user]$  aws devicefarm get-upload –arn arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/ccfa27c9-3f66-49ac-abe0-542214cd650c

Output:
{
    "upload": {
        "status": "SUCCEEDED",
        "name": "features.zip",
        "created": 1442724498.222,
        "type": "CALABASH_TEST_PACKAGE",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/ccfa27c9-3f66-49ac-abe0-542214cd650c",
        "metadata": "{"valid": true}"
    }
}

Once the status is "SUCCEEDED" you are ready to continue to Step 4.

Step 4: Create a Device Pool Associated with the Project

The AWS Device Farm fleet currently includes over 200 different Android, Fire OS, and iOS devices (see the current device list). You may create Device Pools that consist of specific set of devices that you would like to test against. Your device pools can consist of static lists of devices or rule-based on multiple parameters including device platform (i.e. Android or iOS), manufacturer, and form factor.

The CLI command below creates a Device Pool consisting of all available Android devices:

[ec2-user]$  aws devicefarm create-device-pool –project-arn arn:aws:devicefarm:us-west-2:705582597265:project:2c21a412-bb7b-4657-a28c-d7d78b3888f7 –name myAndroidDevicePool –rules ‘[{"attribute": "PLATFORM", "operator": "EQUALS", "value": ""ANDROID""}]’

Output:

{
    "devicePool": {
        "rules": [
            {
                "operator": "EQUALS",
                "attribute": "PLATFORM",
                "value": ""ANDROID""
            }
        ],
        "name": "myAndroidDevicePool",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:devicepool:2c21a412-bb7b-4657-a28c-d7d78b3888f7/e4a54fbd-d094-4130-b6d9-60811820e4d8"
    }
}

Step 5: Schedule a Run

To schedule a run, you will need the following input parameters:

  • project-arn: the ARN of the project from Step1: Create a Device Farm Project
  • app-arn: the ARN of the Application upload from Step 2: Create an Upload for Your Android APK File
  • testPackageArn: the ARN of the Calabash test package upload from Step 3: Create an Upload for Your Calabash Test Package
  • device-pool-arn: the ARN of the device pool created in Step 4: Create a Device Pool Associated with the Project

The following command schedules a run in Device Farm using the specified Android application, Calabash test package, and device pool:

[ec2-user]$  aws devicefarm schedule-run –project-arn arn:aws:devicefarm:us-west-2:705582597265:project:2c21a412-bb7b-4657-a28c-d7d78b3888f7 –app-arn arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/d1f8bebc-a7f5-49a3-881f-f1ffdae90303 –device-pool-arn arn:aws:devicefarm:us-west-2:705582597265:devicepool:2c21a412-bb7b-4657-a28c-d7d78b3888f7/e4a54fbd-d094-4130-b6d9-60811820e4d8 –name firstCLIRun –test ‘{"type": "CALABASH","testPackageArn":"arn:aws:devicefarm:us-west-2:705582597265:upload:2c21a412-bb7b-4657-a28c-d7d78b3888f7/ccfa27c9-3f66-49ac-abe0-542214cd650c"}’

Output:

{
    "run": {
        "status": "SCHEDULING",
        "name": "firstCLIRun",
        "created": 1442724966.821,
        "totalJobs": 100,
        "completedJobs": 0,
        "platform": "ANDROID_APP",
        "result": "PENDING",
        "billingMethod": "METERED",
        "type": "CALABASH",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/61c16425-15c8-4fba-a44f-07dcba60f717",
        "counters": {
            "skipped": 0,
            "warned": 0,
            "failed": 0,
            "stopped": 0,
            "passed": 0,
            "errored": 0,
            "total": 0
        }
    }
}

You can check the status of the run by using the get-run CLI command:

[ec2-user]$  aws devicefarm get-run –arn arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/61c16425-15c8-4fba-a44f-07dcba60f717

Output:

{
    "run": {
        "status": "COMPLETED",
        "name": "firstCLIRun",
        "created": 1442724966.821,
        "totalJobs": 100,
        "completedJobs": 100,
        "platform": "ANDROID_APP",
        "result": "ERRORED",
        "billingMethod": "METERED",
        "type": "CALABASH",
        "arn": "arn:aws:devicefarm:us-west-2:705582597265:run:2c21a412-bb7b-4657-a28c-d7d78b3888f7/61c16425-15c8-4fba-a44f-07dcba60f717",
        "counters": {
            "skipped": 37,
            "warned": 17,
            "failed": 65,
            "stopped": 0,
            "passed": 495,
            "errored": 65,
            "total": 679
        }
    }
}

Once the status is "COMPLETED" your tests on all devices have completed and a full, aggregate summary is available. More on that in Part 2 of this series.

Conclusion

As you can see it’s easy to test your application on dozens of real mobile devices using the Device Farm CLI. Join us in Part 2 of this series where you will retrieve the status and artifacts for your Device Farm Run, including an aggregate summary, log files, and screenshots. If you have any questions please leave a comment below or reach out in our developer forum.

Getting started with Android testing on AWS Device Farm using Espresso – Part 3: Uploading your Android application to AWS Device Farm

by Richard Threlkeld | on | | Comments

AWS Device Farm is a service that allows you to test your Android, Fire OS, and iOS apps on real devices (not emulators or simulators) in the AWS Cloud. You can upload your apps to the cloud and run Fuzz tests to simulate random activity or leverage the built-in app explorer, which crawls your app and captures screenshots as well as performance metrics and logs. To take further advantage of the service you’ll need to leverage one of the supported test automation frameworks. That’s where this series of blog posts comes in.

In Part One and Part Two of this series you created a basic Android application and configured it to use Espresso for running automated tests and taking screenshots. Now that you have your development and build environment setup you can upload the app to AWS Device Farm.

Upload into Device Farm

Log onto your AWS Account and under Mobile Services select Device Farm. You may be prompted to change to the US West (Oregon) Region.

Click "Getting Started" or the "Create a new project" button if you have an existing Project. Call the Project "Espresso Test."

Go into the Project and select "Create a new Run." Choose the "Upload" button to browse to the APK file that Android Studio generated.

Depending on your operating system, the output location for the APK file will be different. In this simple example we have built an unsigned application for testing purposes on OSX so the default location will be something like:

/Users/username/AndroidStudioProjects/SimpleDemoApp/app/build/outputs/apk

Notice in this directory there will be an "app-debug.apk." This is the file we will upload here but take note of the "app-debug-androidTest-unaligned.apk" file as it will be used next.

Once you upload this file and it is processed by Device Farm you will see a message similar to below.

Press next and select "Instrumentation" as the test type. Again, press the "Upload" button. However, this time select the "app-debug-androidTest-unaligned.apk" file. This is where Android Studio has placed the test cases you created in the project structure before. Once the file uploads successfully you will see the Test Package information and Runner displayed.

If you wanted to you have the capability to apply a test filter and run a single test case rather than an entire suite. This can be very helpful if you have resolved an issue and don’t need to retest an entire suite during development. For this tutorial we will leave the filter blank.

On the next screen you will see a list of devices that your application has compatibility. If you wish you can create a custom device pool or accept the default list of devices.

Press "Next step" and take note of the device state options. If you wanted to on this screen you could modify things such as latitude/longitude, locale, radio states, or install other applications – perhaps if you would like to test dependencies on other apps.

One more thing worth pointing out is your ability to “Add extra data." A good use case for this would be an application, which is quite large and leverages an APK Expansion File. If you have an application that makes use of this capability then this would be the time for you to upload your zip file to the Test Run.

Click "Review and start run." Then, assuming everything looks okay, click "Confirm and start run" to begin testing your application. After a moment you will be able to click on the run and see some initial results. Click on one of the devices such as a Samsung Galaxy S6 (Verizon).

Note the package names in the Test Suite. Click on "com.example.simpledemoapp.EspressoTest" and you will see the "testEspresso" method you created earlier as well as some logging details in the lower pane. Clear the "Source" filter by clicking the "X" next to "Harness" and you will see all of the messages including the logcat messages from your code listed. To filter more specifically you can use wildcards in the "Message" field as seen below.

You can also download the raw logs by clicking on the "Files" tab at the top of the screen and process these files using the tools of your choice.

Finally click the "Screenshots" tab and you will see an image that looks like what you saw earlier when running the sample application locally in your emulator.

Conclusion

That concludes this series on getting started with Android test automation using Espresso and AWS Device Farm. Hopefully you now have the foundation to write your own tests that exercise the functionality and business logic of your Android apps. For additional pointers and sample code for Espresso and other frameworks, check out our sample Android app and tests on GitHub.  If you have questions or comments please join us in the comment section below.

Getting started with Android testing on AWS Device Farm using Espresso – Part 2: Setting up Espresso and taking screenshots

by Richard Threlkeld | on | | Comments

AWS Device Farm is a service that allows you to test your Android, Fire OS, and iOS apps on real devices (not emulators or simulators) in the AWS Cloud. You can upload your apps to the cloud and run Fuzz tests to simulate random activity or leverage the built-in app explorer, which crawls your app and captures screenshots as well as performance metrics and logs. To take further advantage of the service you’ll need to leverage one of the supported test automation frameworks. That’s where this series of blog posts comes in.

In Part One of this series you created a basic application. Now, in Part Two, you will create test cases in Espresso to validate functionality and take screenshots before uploading to the AWS Cloud. In Part Three you will run your app and tests in the AWS Cloud with AWS Device Farm. Let’s get started.

Gradle

Open the build.gradle for the app in the main navigation bar.

Replace the text with the following:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.example.simpledemoapp"
        minSdkVersion 19
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    packagingOptions{
        exclude 'LICENSE.txt'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.1.1'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
}

Save your changed file. On the right hand side of Android Studio you will see a tab called "Gradle." Click it and then right-click the root item and select "Refresh external project."

Expand SimpleDemoApp/SimpleDemoApp/Tasks/build and double-click “assembleAndroidTest."

Next, switch to the "Tests" view in the Project navigator.

Expand app/app/src/androidTest/java until you get to the com/example/simpledemoapp package structure.

Right-click the package and select New->Java Class. Type “EspressoTest” for the name and click OK.

Replace the contents of the file with the below code:

package com.example.simpledemoapp;

import android.test.ActivityInstrumentationTestCase2;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;

public class EspressoTest extends ActivityInstrumentationTestCase2 {

    public EspressoTest() {super(SimpleDemoActivity.class);}

    @Override
    public void setUp() throws Exception {
        super.setUp();
        getActivity();
    }

    public void testEspresso(){
        onView(withId(R.id.editText)).perform(typeText("Testing with AWS Device Farm
        onView(withId(R.id.buttonUpdate)).perform(click());
        onView(withId(R.id.updatedText)).check(matches(withText("Testing with AWS Device Farm")));
    }
}

Save the file.

In the top navigation bar select Run->Edit Configurations.

Click the plus (+) sign to add an Android Test configuration node. Click on that node and press plus again to add a new configuration for EspressoTest. Ensure that the Class matches and the Instrumentation Runner is android.support.test.runner.AndroidJUnitRunner.

Now Right-Click the EspressoTest class in the navigation pane->Run->EspressoTest.

If everything runs successfully you will see the test run in the emulator. You might need to click fast to bring it in focus.

Also you should see “Done 1 of 1” in the Run section of the console for successful test execution with Espresso.

IMPORTANT: If you created a test in your Class and your output doesn’t match the above screenshot, or you get a message such as “No test events received,” it may be due to how you named the test. Tests must start with the name “test” such as “testEspresso()” in the above example or the test runner will not recognize them.

Screenshots

At this point we have a very basic application that technically can be uploaded and tested in Device Farm. However, according to the documentation we need to save screenshots to the SD Card in order for them to be seen after a Run. If the Espresso .check() call fails we would like to see a screenshot of what the screen looked like in order to troubleshoot.

To accomplish this task we’ll create a utility class that will save PNG files to /sdcard/test-screenshots/ as per the Device Farm documentation. The class will take an input of the Activity and a string identifier for the file name.

Select File->New->Java Class and when prompted name it "ScreenShot." IMPORTANT: This name must be precise including capitalization so use a capital "S."

Paste in the following code:

package com.example.simpledemoapp;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Log;
import android.view.View;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class ScreenShot {
    private static final String TAG = "SCREENSHOT_TAG";

    public static void take(Activity activity, String name) {
        final String dir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test-screenshots/";
        final String path = dir + name;

        File filePath = new File(dir);     // Create directory if not present
        if (!filePath.isDirectory()) {
            Log.i(TAG, "Creating directory " + filePath);
            filePath.mkdirs();
        }

        Log.i(TAG, "Saving to path: " +  path);

        View phoneView = activity.getWindow().getDecorView().getRootView();
        phoneView.setDrawingCacheEnabled(true);
        Bitmap bitmap = Bitmap.createBitmap(phoneView.getDrawingCache());
        phoneView.setDrawingCacheEnabled(false);

        OutputStream out = null;

        File imageFile = new File(path);

        try {
            out = new FileOutputStream(imageFile);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            out.flush();
        }
        catch (FileNotFoundException e) {
            Log.e(TAG, e.toString());
        }
        catch (IOException e) {
            Log.e(TAG, e.toString());
        }

        finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                Log.e(TAG, e.toString());
            }
        }
    }
}

Now modify testEspresso()in the EspressoTest.java class to make a call to the newly created ScreenShot class:

public void testEspresso() throws IOException {

    Log.i("TESTESPRESSO", "Starting the Espresso Test");
    onView(withId(R.id.editText)).perform(typeText("Testing with AWS Device Farm
    onView(withId(R.id.buttonUpdate)).perform(click());
    onView(withId(R.id.updatedText)).check(matches(withText("Testing with AWS Device Farm")));

    // Take the screenshot
    ScreenShot.take(getActivity(),"Homepage");

}

You will also need to modify the AndroidManifest.xml file so that your application has permission to write and read from the SD card. In the Project Navigator expand app/src/main and double-click AndroidManifest.xml. Add in the "uses-permission" entries as in the example XML below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.simpledemoapp" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".SimpleDemoActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Run the test again in the emulator but this time after it finishes open the Android Device Monitor from the Android Studio task bar.

In the Android Device Monitor you will find a tab called "File Explorer." Select this and navigate to /storage/sdcard/test-screenshots. If you see a file called "Homepage" then you have run everything successfully. If you wish you can click on the file and download the image for viewing.

Conclusion

That’s it for Part Two! Now join us for Part Three of this series where you will upload your application to AWS Device Farm and see your tests run across multiple devices in the AWS Cloud. If you have questions please join us in the comment section below.

Getting started with Android testing on AWS Device Farm using Espresso – Part 1: Building a sample application

by Richard Threlkeld | on | | Comments

AWS Device Farm is a service that allows you to test your Android, Fire OS, and iOS apps on real devices (not emulators or simulators) in the AWS Cloud. You can upload your apps to the cloud and run Fuzz tests to simulate random activity or leverage the built-in app explorer, which crawls your app and captures screenshots as well as performance metrics and logs. To take further advantage of the service you’ll need to leverage one of the supported test automation frameworks. That’s where this series of blog posts comes in.

In this three-part series we will show you how to create a basic Android application that leverages Espresso as a testing framework and runs tests across a pool of devices in the AWS Cloud. The application has a text entry field where the user can type information and a button so that when pressed the entered information shows on the screen. This can be thought of as a basic application feature that you’ll write an automated test in Espresso to validate.

In Part One you will create the application and run it locally. Part Two covers test creation and Part Three will cover cloud execution with Device Farm.

Prerequisites

This guide assumes that you have Android Studio installed with the Android SDK configured and you have a working emulator from the Android Virtual Device (AVD) Manager.

Open the SDK Manager and scroll down to “Extras” at the bottom. Ensure that the “Android Support Repository” is installed.

Gradle

If you are not already familiar with Gradle please take a moment to familiarize yourself before going any further: https://gradle.org/getting-started-android/

Android Studio

Start by creating a new Project in Android Studio. Name the application SimpleDemoApp.

Important: For this demo ensure the Company Domain is exactly like the image above.

For this example we used KitKat as the minimum SDK version but note Espresso will support previous versions as well. Select the Blank Activity template and change the Activity name to “SimpleDemoActivity”.

Click finish and the project will be created. Open the application’s main layout file (activity_simple_demo.xml).

If you don’t see the above go to View->Tool Windows->Project and use the navigation bar on the left.

Click the text view towards the bottom of Android Studio and replace the XML with the following:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView android:text="Some Text!"
        android:id="@+id/updatedText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click to update text"
        android:id="@+id/buttonUpdate"
        android:layout_below="@+id/updatedText"
        android:layout_alignParentStart="true" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_below="@+id/buttonUpdate"
        android:layout_alignParentStart="true"
        android:layout_marginTop="52dp"
        android:layout_alignParentEnd="true" />

</RelativeLayout>

Save the file. This will create an area to input text, a button, and an area to display the text. Now we need to wire up these objects to a controller. Open the main Activity class (SimpleDemoActivity.java) from the navigation pane.

Replace the contents with the following code:

package com.example.simpledemoapp;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class SimpleDemoActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple_demo);

        Button updateButton = (Button)findViewById(R.id.buttonUpdate);
        updateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView textToUpdate =
                    (TextView)findViewById(R.id.updatedText);
                EditText enteredText = (EditText)findViewById(R.id.editText);
                textToUpdate.setText(enteredText.getText().toString());
            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if
        // it is present.
        getMenuInflater().inflate(R.menu.menu_simple_demo, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Save the file. Now run your application  either on an emulator or real device. When starting up an emulator this can take a few minutes. Once running, you should be able to input some text, click the button and have it show up on the screen.

Conclusion

That’s it for Part One! Now join us for Part Two of this series where you will modify this application to use Espresso for building test cases and take screen shots. If you have questions please join us in the comment section below.

Test user flows through your Android app with AWS Device Farm’s built-in app explorer. No scripts required.

by Trent Peterson | on | | Comments

Starting today, you can view details about how your Android app performs on real devices in the AWS Cloud without writing your own test scripts. AWS Device Farm’s new Built-in: Explorer test deploys an app explorer that crawls your application, analyzes each view it encounters, and interacts with each view’s controls as an end user would. The app explorer captures screenshots, logs, and performance data as it explores your app. All results and artifacts are collated into a Device Farm report and also made available through the API.

The app explorer works with both native and web controls, and will tap buttons, insert placeholder text into text inputs, and open and interact with menus. It captures a screenshot and logs each interaction that was performed. In addition, if your app requires an account login, you can provide credentials that the app explorer will use if it finds the login form.

Getting started

1. First, login to the AWS Device Farm console. If you’re new to Device Farm, don’t worry. You can get started with a one-time free trial of 250 minutes.

2. From within the Device Farm console, go to a Device Farm project and start the “Create a new run” wizard by clicking the “Create a new run” button. If it’s a brand new project, the wizard will start automatically.

3. Next, upload your Android app (.apk).

4. On the Configure Test step, select “Built-in: Explorer” from the test types. If you have a login form within your app, you can use the username and password fields to specify the credentials the app explorer should use.

5. Click “Next” until you’re on the Review and Start Run step. If everything looks okay, click “Confirm and start run.”

Analyzing results

As each device completes its Built-In: Explorer test, the results will be pulled into the report. You can view all screenshots in a single place on the report’s summary view by clicking on the “Screenshots” tab. You can also drill down to a specific device by clicking on the desired device from the report summary view in the "Devices" section.

View logs and screenshots for a specific device by selecting it from the AWS Device Farm report summary view

View logs, screenshots, and performance data for a specific device by selecting it from the report summary view

From within the device view, you can analyze logs, performance data, and screenshots collected by the app explorer for the specified device.

The Android app explorer captures logs for each devices

Viewing logs captured by the app explorer on a specific device

The app explorer captures screenshots for each interaction on a device

Viewing screenshots captured by the app explorer on a specific device

Conclusion

The app explorer enables you to test basic user flows through your Android application without writing test scripts, allowing you to get started with automated testing faster and test more often during development. In addition to starting the Built-in: Explorer test from the console and SDKs, you can automatically kick off app explorer tests in your Jenkins continuous integration environment with the Device Farm Jenkins plugin.

You can also augment the app explorer with your own custom tests, which allow you to exercise specific functionality within your app and take screenshots exactly where you want. Custom tests are complimentary to the app explorer, which crawls your app without consideration for your app’s business logic. You can write custom tests in a number of frameworks like Espresso, Calabash, and Appium. Learn about supported framworks in the Device Farm documentation and get started quickly using the Device Farm Android app and sample scripts.

Please let us know if you have feedback or questions about the app explorer or AWS Device Farm in general in the comments or in the developer forum.

Integrating Amazon Cognito using developer authenticated identities: An end-to-end example

by Rachit Dhall | on | | Comments

In September, we introduced developer authenticated identities, a new feature that allows you to utilize your own end-user identities with Amazon Cognito (read our announcement post). The purpose of this post is to show an end-to-end sample that demonstrates how to integrate this feature with an existing authentication system.

Using developer authenticated identities involves interaction between the end-user device, your backend for authentication, and Amazon Cognito. The following diagram shows the flow of calls between the various systems involved.

This sample has two components: a server-side authentication application written in Java (you can find the code here) and updated Cognito Android and iOS sample apps that have added functionality to interact with this backend.

Authentication Server

The authentication server is a simple application designed to store user credentials in a secure manner and provides an OpenID Connect token to authenticated users. The application provides three basic functionalities:

  1. Register Users: You can register a username-password combination that can be used to login to the application.
  2. Login: The server authenticates the user credentials and provides a key for further communication.
  3. GetToken: The client requests an OpenId connect from the server. The server validates the client is authenticated and then contacts Amazon Cognito for the OpenId connect token.

Click here to deploy the server side application in the US East (N. Virginia) Region.

Click here to deploy the server side application in the EU (Ireland) Region.

Click here to deploy the server side application in the Asia Pacific (Tokyo) Region.

For instructions on how to deploy please refer to README file of the sample.

Mobile Application

We have updated the Amazon Cognito samples to interact with this server-side application. The following sections of this post will walk you through the code changes to the sample.

Implementing the custom identity provider

To use developer authenticated identities you need to implement a custom identity provider. The identity provider facilitates the interaction between your mobile app and your authentication system and helps you manage the OpenID connect tokens needed by Cognito.

Android

The DeveloperAuthenticationProvider class extends AWSAbstractCognitoDeveloperIdentityProvider, which contains the getProviderName, login, refresh, and getIdentityId methods.

The first step is to override the getProviderName method to return the your custom provider name. This should be the same name that you chose while configuring your identity pool on the Amazon Cognito console.

The login function makes an asynchronous login request to the server with the credentials entered by the user.

public void login(String userName, String password, Context context) {
  new DeveloperAuthenticationTask(context).execute(new LoginCredentials(userName, password));
}

The DeveloperAuthenticationTask class makes the actual request to the server application. If the request is successful, then it adds your provider name and user identifier to the logins map. The developer user identifier can be an alphanumeric string that uniquely identifies a user in your backend. In the sample, we use username as a developer user identifier.

@Override
protected void onPostExecute(Void result) {
    // Be sure to update the logins map on successful login operation
    if (isSuccessful) {
        CognitoSyncClientManager
                .addLogins(
                        ((DeveloperAuthenticationProvider) CognitoSyncClientManager.provider
                                .getIdentityProvider()).getProviderName(),
                        userName);
    } else {
        new AlertDialog.Builder(context).setTitle("Login error")
                .setMessage("Username or password do not match!!").show();
    }
}

iOS

The DeveloperAuthenticatedIdentityProvider class extends the AWSAbstractCognitoIdentityProvider, which is the custom developer provider we have implemented.  The sample sets the developer provider name as one of the properties of the class in its constructor. The class DeveloperAuthenticationClient implements login and getToken requests to the server application.

- (BFTask *)login:(NSString *)username password:(NSString *)password;

If the login request is successful, then add the developer provider name and developer user identifier to the logins dictionary. The developer user identifier is any identifier that identifies a user uniquely. Again the username is used as a developer user identifier.

[self completeLogin:@{ProviderName: username}];

Implementing the refresh method

The sample app supports the following use cases for authentication: Developer authenticated identities, public providers, and unauthenticated users. For the app to use developer authenticated identities the app should contact the server application, for the last two cases the mobile application instead interacts directly with Amazon Cognito. For this reason, the refresh method has two separate flows depending on the contents of the logins.

If the end user is using your authentication system, then the logins map will have a key for the developer provider name. In this scenario, the communication with Amazon Cognito will be through the server application using the GetOpenIdTokenForDeveloperIdentity API. This API will return an identityId and OpenId connect token. The sample app calls the GetToken functionality of the backend server. This call verifies the authentication and then calls the Amazon Cognito API. Be sure to update the stored identityId and token with the one that you received from the server application using the update function.

If the loginsMap does not contain a key for developer provider name, then the mobile app calls the getIdentityId method and returns null.

Android

public String refresh() {
        setToken(null);
        // If there is a key with developer provider name in the logins map, it
        // means the app user has used developer credentials
        if (getProviderName() != null && !this.loginsMap.isEmpty()
                && this.loginsMap.containsKey(getProviderName())) {
            GetTokenResponse getTokenResponse = (GetTokenResponse) devAuthClient.getToken(
                    this.loginsMap,
                    identityId);
            update(getTokenResponse.getIdentityId(),
                    getTokenResponse.getToken());
            return getTokenResponse.getToken();
        } else {
            this.getIdentityId();
return null;
        }
    }

iOS

- (BFTask *)refresh {
    if (![self authenticatedWithProvider]) {
        return [super getIdentityId];
    }
    else {
        return [[self.client getToken:self.identityId logins:self.logins] continueWithSuccessBlock:^id(BFTask *task) {
            if (task.result) {
                DeveloperAuthenticationResponse *response = task.result;
                if (![self.identityPoolId isEqualToString:response.identityPoolId]) {
                    return [BFTask taskWithError:[NSError errorWithDomain:DeveloperAuthenticationClientDomain
                                                                     code:DeveloperAuthenticationClientInvalidConfig
                                                                 userInfo:nil]];
                }
                
                // potential for identity change here
                self.identityId = response.identityId;
                self.token = response.token;
            }
            return [BFTask taskWithResult:self.identityId];
        }];
    }
}

Implementing the getIdentityId method

Finally, we override the getIdentityId method because once again it will have two potential flows depending on the provider used by the end user. When using the developer authentication system, the identityId will be obtained using the GetToken call of the server application. For other providers or unauthenticated access, we just call the getIdentityId method of the parent class.

Android

@Override
public String getIdentityId() {
    identityId = CognitoSyncClientManager.provider.getCachedIdentityId();
    if (identityId == null) {
        if (getProviderName() != null && !this.loginsMap.isEmpty()
                && this.loginsMap.containsKey(getProviderName())) {
            GetTokenResponse getTokenResponse = (GetTokenResponse) devAuthClient.getToken(
                    this.loginsMap, identityId);
            update(getTokenResponse.getIdentityId(),
                    getTokenResponse.getToken());
            return getTokenResponse.getIdentityId();
        } else {
            return super.getIdentityId();
        }
    } else {
        return identityId;
    }
}

iOS

- (BFTask *)getIdentityId {
    // already cached the identity id, return it
    if (self.identityId) {
        return [BFTask taskWithResult:nil];
    }
    // not authenticated with our developer provider
    else if (![self authenticatedWithProvider]) {
        return [super getIdentityId];
    }
    // authenticated with our developer provider, use refresh logic to get id/token pair
    else {
        return [[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
            if (!self.identityId) {
                return [self refresh];
            }
            return [BFTask taskWithResult:self.identityId];
        }];
    }
}

Summary

We hope this blog post and the sample apps help you better understand the developer authenticated identities flow and make it easy for you to integrate your own authentication system with Amazon Cognito.  If you have any comments, questions, or feedback, feel free to leave a comment here or visit our forums and we will try to assist you.

Announcing AWS Mobile SDK General Availability

by Yosuke Matsuda | on | | Comments

We are pleased to announce that version 2 of the AWS Mobile SDK has reached General Availability (GA) and is no longer in Developer Preview. Since releasing Version 2 in Developer Preview on July 10th, we have received great feedback from the developer community, and we have made numerous improvements.

You can read about some of the more significant improvements that we made during the developer preview on Jeff Barr’s blog. The latest versions of the SDK for Android (v2.1.1) and iOS (v2.0.8) are available for download here. For more details, please refer to the release notes (Android, iOS).