Automate Mobile Simulation using AWS Device Farm

Automate your iOS and Android application testing using the AWS device farm. This article will provide instruction on creating an interface that will be used to auto-deploy build .ipa/.apk files into device farm devices for testing.

Don’t need to buy physical devices to test your iOS or Android applications. Use AWS Device and automate your testing in the real devices.

Architecture

The objective here is that to provide user interface (hosted in S3 bucket) to choose the ipa/apk file and devices for testing. With this data an Ajax call is made to an API gateway which will intern trigger the lambda function. The lambda function will spin up the required devices and deploy the build file into the mobile device based on the data received from the interface.

Lamda Function

This lambda function let us to list the projects and the uploads that are already existing in the AWS Device Farm.

// assume we already executed `npm install aws-sdk`
var AWS = require('aws-sdk');
// Device Farm is only available in the us-west-2 region
var devicefarm = new AWS.DeviceFarm({ region: 'us-west-2' });

exports.handler = async (event) => {

    return new Promise(function (resolve, reject) {
        var params = {};
        devicefarm.listProjects(params, function (err, projects) {
            if (err) reject(err); // an error occurred
            else {
                var project = projects.projects[0];
                console.log("project: ", project);
                resolve(project);
            }
        });
    }).then(function(data){
        console.log("in then function","data: ",data);
        return new Promise(function(resolve,reject){
            devicefarm.listUploads({ arn: data.arn, type: 'IOS_APP' }, function(err,uploads){
                if (err) reject(err); // an error occurred
                else {
                    resolve(uploads);
                }
            })
        }).then(function(data){
            console.log("uploads: ", data);
            return data;
        }).catch(function(data){
            console.error("list uploads failed","data: ", data);
            return data;
        });
    }).catch(function(data){
        console.error("list projects failed","data: ",data);
        return data;
    });

};

Below is the Javascript code to wait for the remote session to go to the status of Running.

// assume we already executed `npm install aws-sdk`
var AWS = require('aws-sdk');
// assumes `npm install https`
const request = require("request");
// assumes `npm install fs`
const fs = require('fs');
// https://stackoverflow.com/a/41641607/8016330
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
// Device Farm is only available in the us-west-2 region
var devicefarm = new AWS.DeviceFarm({ region: 'us-west-2' });

let params = {
    name: "test of remote access"
};
devicefarm.createProject(params).promise().then(
    function (data) {
        /* process the data */
        console.log("created project", "Result: ", data.project.arn);
        let project = data.project;
        let params = {
            name: "app-debug.apk",
            type: "ANDROID_APP",
            projectArn: project.arn
        };
        devicefarm.createUpload(params).promise().then(
            function (data) {
                console.log("Created upload object successfully", "upload arn: ", data.upload.arn);
                console.log("uploading file...");

                var options = {
                    method: 'PUT',
                    url: data.upload.url,
                    headers: {},
                    body: fs.readFileSync("./aws-device-farm-sample-app-for-android/app/build/outputs/apk/app-debug.apk")
                };

                new Promise(function (resolve, reject) {
                    request(options, function (error, response, body) {
                        if (error) {
                            reject(error);
                        }
                        resolve(data);
                    });
                }).then(function (data) {
                    console.log("successfully uploaded file");
                    console.log("waiting for the sdk to finish processing");

                    getUploadStatusAndCreateRemoteSession(data.upload.arn,project).then(function (status) {
                        if (status == "SUCCEEDED") {

                        }

                    });
                }).catch(function (err) {
                    console.error("Error uploading file", "Error: ", err);
                });
            },
            function (error) {
                console.error("Error creating upload object", "Error: ", error);
            }
        );
    },
    function (error) {
        console.error("Error creating project", "Error: ", error);
    }
)

async function getUploadStatusAndCreateRemoteSession(uploadarn,project) {
    await devicefarm.getUpload({ arn: uploadarn }).promise().then(
        function (data) {
            console.log("getting upload status is successful", "Status: ", data.upload.status);
            if (data.upload.status != "SUCCEEDED") {
                sleep(5000).then(() => {
                    getUploadStatusAndCreateRemoteSession(data.upload.arn,project);
                });
            } else {
                // return data.upload.status;
                devicefarm.createRemoteAccessSession({
                    projectArn: project.arn,
                    deviceArn: 'arn:aws:devicefarm:us-west-2::device:CF6DC11E4C99430BA9A1BABAE5B45364'
                }).promise().then(
                    function (session) {
                        //get session status
                        getSessionStatus(session.remoteAccessSession.arn,uploadarn);
                    },
                    function (error) {
                        console.error("Error creating remote access sesssion", "Error", error);
                    }
                );
            }
        },
        function (error) {
            console.error("Failure getting upload", "Error: ", error);
            return error;
        }
    );
}

async function getSessionStatus(sessionArn,upload) {
    await devicefarm.getRemoteAccessSession({ arn: sessionArn }).promise().then(
        function (data) {
            console.log("getting session status is successful", "Status: ", data.remoteAccessSession.status);
            if (data.remoteAccessSession.status != "RUNNING") {
                sleep(5000).then(() => {
                    getSessionStatus(sessionArn,upload);
                });
            } else {

                console.log("Remote access session started!", "Installing app...");
                let installParm = {
                    appArn: upload,
                    remoteAccessSessionArn: sessionArn
                };
                devicefarm.installToRemoteAccessSession(installParm, function (err, data) {
                    if (err) console.error(err);
                    else console.log(data);
                });

            }
        },
        function (error) {
            console.error("Failure getting session", "Error: ", error);
            return error;
        }
    );
}

Output

created project Result:  arn:aws:devicefarm:us-west-2:111122223333:project:42ca0449-2714-4dd8-848f-ae9ef6655efb
Created upload object successfully upload arn:  arn:aws:devicefarm:us-west-2:111122223333:upload:42ca0449-2714-4dd8-848f-ae9ef6655efb/cd200f8e-e7f7-4d18-a4ee-32ad959a0786
uploading file...
successfully uploaded file
waiting for the sdk to finish processing
getting upload status is successful Status:  PROCESSING
getting upload status is successful Status:  SUCCEEDED
getting session status is successful Status:  PENDING
getting session status is successful Status:  PENDING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  PREPARING
getting session status is successful Status:  RUNNING
Remote access session started! Installing app...
{ appUpload:
   { arn: 'arn:aws:aatp:us-west-2:111122223333:upload:42ca0449-2714-4dd8-848f-ae9ef6655efb/cd200f8e-e7f7-4d18-a4ee-32ad959a0786',
     name: 'app-debug.apk',
     created: 2019-05-04T00:24:32.871Z,
     type: 'ANDROID_APP',
     status: 'SUCCEEDED',
     url: 'https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A111122223333%3Aproject%3A42ca0449-2714-4dd8-848f-ae9ef6655efb/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A111122223333%3Aupload%3A42ca0449-2714-4dd8-848f-ae9ef6655efb/cd200f8e-e7f7-4d18-a4ee-32ad959a0786/app-debug.apk?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20190504T002655Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=AKIAJSORV74ENYFBITRQ%2F20190504%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Signature=4630cef6030405b6997281c2477722d3da24eb04ed6aab8e91735d936e532807',
     metadata: '{"device_admin":false,"activity_name":"com.amazonaws.devicefarm.android.referenceapp.Activities.MainActivity","version_name":"1.0","screens":["small","normal","large","xlarge"],"error_type":null,"sdk_version":"10","package_name":"com.amazonaws.devicefarm.android.referenceapp","version_code":"1","native_code":[],"target_sdk_version":"22"}',
     category: 'PRIVATE' } }

Add a Comment

Your email address will not be published. Required fields are marked *