AWS SDKを使いDeviceFarmでのテストをスケジューリングする
概要
AWS SDKを使用してDeviceFarmへAPKとテストコードをアップロードし、Calabashによるテストを実行してみたのでそのメモ。
APIドキュメントと使用するSDK
ドキュメントは以下を参照した。
また、SDKにはAWS SDK for Ruby - Version 2を使用する。
AWS SDK Clientの作成
clientを作成します。IAMでAWSDeviceFarmFullAccessのポリシーをアタッチしたユーザを用意し、そのAccessKeyIdとSecretAccessKeyを使用する。また、regionにはus-west-2
を指定する。
require 'aws-sdk' devicefarm = Aws::DeviceFarm::Client.new( region: 'us-west-2', credentials: Aws::Credentials.new("YOUR_ACCESS_KEY_ID", "YOUR_SECRET_ACCESS_KEY"), )
DeviceFarmのプロジェクト情報を取得
まず試しにDeviceFarmで作成したプロジェクトの情報を取得してみる。プロジェクトを作成していない場合DeviceFarmのコンソールから「Create a new project」をクリックしプロジェクトを作成しておく。
プロジェクト情報は以下のコードで取得できる。
devicefarm.get_project({ arn: "プロジェクトのARN" })
ここで、プロジェクトのARNは以下のようになる。
arn:aws:devicefarm:us-west-2:<ポリシーをアタッチしたユーザーID>:project:<DeviceFarmのプロジェクトID>
DeviceFarmのプロジェクトIDは、DeviceFarmでプロジェクトを開いた際のURLの以下の部分を使用する。
https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-west-2#/projects/この部分/runs
DevicePoolの取得
デバイスプールについて
テストを実行するデバイスの種類は、デバイスプールと呼ばれる単位で管理されている。デバイスプールをAWS SDKから作成することは出来るが、コンソールから作成した方がわかりやすい。
コンソールのプロジェクトページに表示される「Create a new run」をクリックすると新しいRun(テスト対象APKやデバイスの種類、テストケースを紐付けたもの)を作成することができるので、一度作成しRunを実行しておく。AWSのブログ記事が実行まで詳細に書いてあるので参考にした。
AWS SDKでのDevicePoolの取得
以下のコードでDevicePoolを取得でき、レスポンスにはDevicePoolのARNなどの情報が含まれる。今回はレスポンスに含まれる最初のDevicePoolを使用する。ドキュメントはここ。
resp = devicefarm.list_device_pools({ arn: "プロジェクトのARN" }) # DevicePoolのARN(後ほど使用) device_pool_arn = resp.device_pools[0].arn
テスト対象APKのアップロード
APKのアップロードは2段階の手順を踏む。
- devicefarm.create_upload()でのinitialize
- Pre-Signed URLを使用したAPKアップロード
initialize
以下のコードで初期化し、Pre-Signed URLを取得する。また、アップロードするオブジェクトのARNを取得しておく(実行をスケジューリングする際に使用)。ドキュメントはここ。
resp = devicefarm.create_upload({ project_arn: "プロジェクトのARN", name: "app-debug.apk", type: "ANDROID_APP", content_type: "application/octet-stream" }) # Pre-Signed URLの取得 pre_signed_url = resp.upload.url # 実行をスケジューリングする際に使用 apk_arn = resp.upload.arn
create_uploadのレスポンスのシンタックスは以下のようになっている。ドキュメントはここ。
{ "Upload": { "Arn": "string", "ContentType": "string", "Created": number, "Message": "string", "Metadata": "string", "Name": "string", "Status": "string", "Type": "string", "Url": "string" } }
statusは、FAILED
、INITIALIZED
、PROCESSING
、SUCCEEDED
の4種類があり、create_uploadを実行した直後は、INITIALIZED
になり、この状態ではDeviceFarmから利用できない。Pre-Signed URLを利用してAPKをアップロードすることでPROCESSING
となり、その後SUCCEEDED
へ変化する。ここでPROCESSING
の際に不具合が起きるとFAILED
になる。
upload
ここを参考に、以下のようなコードでAPKをアップロードできる。
url = URI.parse(pre_signed_url) apk = File.open("YOUR_APK_PATH", "rb").read Net::HTTP.start(url.host) do |http| http.send_request("PUT", url.request_uri, apk, {"content-type" => "application/octet-stream"}) end
テストパッケージのアップロード
今回テストにはCalabashを使用するので、Calabashのfeaturesをzipに圧縮してアップロードする。アップロードの手順はAPKのアップロードと同じ。create_uploadのtypeにCALABASH_TEST_PACKAGE
を指定する。
resp = devicefarm.create_upload({ project_arn: "プロジェクトのARN", name: "features.zip", type: "CALABASH_TEST_PACKAGE", content_type: "application/octet-stream" }) # Pre-Signed URLの取得 pre_signed_url = resp.upload.url # 実行をスケジューリングする際に使用 calabash_package_arn = resp.upload.arn url = URI.parse(pre_signed_url) features = File.open("YOUR_FEATURES_PATH", "rb").read Net::HTTP.start(url.host) do |http| http.send_request("PUT", url.request_uri, features, {"content-type" => "application/octet-stream"}) end
テストの実行
実行のスケジューリング
実行のスケジュールは以下のように行う。ドキュメントはここ。
app_arnには、APKをアップロードした際に取得したARNを、device_pool_arnはDevicePoolの取得で取得したARNを、test_package_arnにはCalabashのfeatures.zipをアップロードした際に取得したARNを使用する。
devicefarm.schedule_run({ project_arn: "プロジェクトのARN", app_arn: apk_arn, device_pool_arn: device_pool_arn, test: { type: 'CALABASH', test_package_arn: calabash_package_arn } })
APK、Test packageのアップロード完了を待つ
APK、Test packageをアップロードした直後では、それぞれのstatusがSUCCEEDED
になっているとは限らない。このため、定期的にstatusがSUCCEEDED
かどうか確認する手順が必要になる。
get_uploadを使用すると、uploadしたオブジェクトの状態を取得できるので、それを1秒ごとに取得しstatusを確認。そして、APK、Test package両方のstatusがSUCCEEDED
ならschedule_runを実行する。
10.times do resp_apk = devicefarm.get_upload({ arn: apk_arn }) resp_test_package = devicefarm.get_upload({ arn: calabash_package_arn }) if resp_apk.upload.status == "SUCCEEDED" && resp_test_package.upload.status == "SUCCEEDED" devicefarm.schedule_run({ project_arn: "プロジェクトのARN", app_arn: apk_arn, device_pool_arn: device_pool_arn, test: { type: 'CALABASH', test_package_arn: calabash_package_arn } }) exit end sleep(1) end
これでスケジューリングされ、DeviceFarm上でCalabashのテストが実行される。
TODO
CircleCIと連携させGitHubへのPushをトリガーにしてDeviceFarmでのテストを自動実行する。